Stop using Constants utility in IsolationLevelDataSourceRouter
See gh-30851
This commit is contained in:
parent
181c814e69
commit
06c6af9b0d
|
|
@ -16,11 +16,12 @@
|
||||||
|
|
||||||
package org.springframework.jdbc.datasource.lookup;
|
package org.springframework.jdbc.datasource.lookup;
|
||||||
|
|
||||||
import org.springframework.core.Constants;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.springframework.lang.Nullable;
|
import org.springframework.lang.Nullable;
|
||||||
import org.springframework.transaction.TransactionDefinition;
|
import org.springframework.transaction.TransactionDefinition;
|
||||||
import org.springframework.transaction.support.DefaultTransactionDefinition;
|
|
||||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DataSource that routes to one of various target DataSources based on the
|
* DataSource that routes to one of various target DataSources based on the
|
||||||
|
|
@ -82,6 +83,7 @@ import org.springframework.transaction.support.TransactionSynchronizationManager
|
||||||
* </bean></pre>
|
* </bean></pre>
|
||||||
*
|
*
|
||||||
* @author Juergen Hoeller
|
* @author Juergen Hoeller
|
||||||
|
* @author Sam Brannen
|
||||||
* @since 2.0.1
|
* @since 2.0.1
|
||||||
* @see #setTargetDataSources
|
* @see #setTargetDataSources
|
||||||
* @see #setDefaultTargetDataSource
|
* @see #setDefaultTargetDataSource
|
||||||
|
|
@ -93,8 +95,17 @@ import org.springframework.transaction.support.TransactionSynchronizationManager
|
||||||
*/
|
*/
|
||||||
public class IsolationLevelDataSourceRouter extends AbstractRoutingDataSource {
|
public class IsolationLevelDataSourceRouter extends AbstractRoutingDataSource {
|
||||||
|
|
||||||
/** Constants instance for TransactionDefinition. */
|
/**
|
||||||
private static final Constants constants = new Constants(TransactionDefinition.class);
|
* Map of constant names to constant values for the isolation constants
|
||||||
|
* defined in {@link TransactionDefinition}.
|
||||||
|
*/
|
||||||
|
static final Map<String, Integer> constants = Map.of(
|
||||||
|
"ISOLATION_DEFAULT", TransactionDefinition.ISOLATION_DEFAULT,
|
||||||
|
"ISOLATION_READ_UNCOMMITTED", TransactionDefinition.ISOLATION_READ_UNCOMMITTED,
|
||||||
|
"ISOLATION_READ_COMMITTED", TransactionDefinition.ISOLATION_READ_COMMITTED,
|
||||||
|
"ISOLATION_REPEATABLE_READ", TransactionDefinition.ISOLATION_REPEATABLE_READ,
|
||||||
|
"ISOLATION_SERIALIZABLE", TransactionDefinition.ISOLATION_SERIALIZABLE
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -104,14 +115,16 @@ public class IsolationLevelDataSourceRouter extends AbstractRoutingDataSource {
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected Object resolveSpecifiedLookupKey(Object lookupKey) {
|
protected Object resolveSpecifiedLookupKey(Object lookupKey) {
|
||||||
if (lookupKey instanceof Integer) {
|
if (lookupKey instanceof Integer isolationLevel) {
|
||||||
return lookupKey;
|
Assert.isTrue(constants.containsValue(isolationLevel),
|
||||||
|
"Only values of isolation constants allowed");
|
||||||
|
return isolationLevel;
|
||||||
}
|
}
|
||||||
else if (lookupKey instanceof String constantName) {
|
else if (lookupKey instanceof String constantName) {
|
||||||
if (!constantName.startsWith(DefaultTransactionDefinition.PREFIX_ISOLATION)) {
|
Assert.hasText(constantName, "'lookupKey' must not be null or blank");
|
||||||
throw new IllegalArgumentException("Only isolation constants allowed");
|
Integer isolationLevel = constants.get(constantName);
|
||||||
}
|
Assert.notNull(isolationLevel, "Only isolation constants allowed");
|
||||||
return constants.asNumber(constantName);
|
return isolationLevel;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,98 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2002-2023 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.springframework.jdbc.datasource.lookup;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import org.springframework.transaction.TransactionDefinition;
|
||||||
|
import org.springframework.util.ReflectionUtils;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||||
|
import static org.springframework.transaction.TransactionDefinition.ISOLATION_DEFAULT;
|
||||||
|
import static org.springframework.transaction.TransactionDefinition.ISOLATION_READ_COMMITTED;
|
||||||
|
import static org.springframework.transaction.TransactionDefinition.ISOLATION_READ_UNCOMMITTED;
|
||||||
|
import static org.springframework.transaction.TransactionDefinition.ISOLATION_REPEATABLE_READ;
|
||||||
|
import static org.springframework.transaction.TransactionDefinition.ISOLATION_SERIALIZABLE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for {@link IsolationLevelDataSourceRouter}.
|
||||||
|
*
|
||||||
|
* @author Sam Brannen
|
||||||
|
* @since 6.1
|
||||||
|
*/
|
||||||
|
class IsolationLevelDataSourceRouterTests {
|
||||||
|
|
||||||
|
private final IsolationLevelDataSourceRouter router = new IsolationLevelDataSourceRouter();
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void resolveSpecifiedLookupKeyForInvalidTypes() {
|
||||||
|
assertThatIllegalArgumentException().isThrownBy(() -> router.resolveSpecifiedLookupKey(new Object()));
|
||||||
|
assertThatIllegalArgumentException().isThrownBy(() -> router.resolveSpecifiedLookupKey('X'));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void resolveSpecifiedLookupKeyByNameForUnsupportedValues() {
|
||||||
|
assertThatIllegalArgumentException().isThrownBy(() -> router.resolveSpecifiedLookupKey(null));
|
||||||
|
assertThatIllegalArgumentException().isThrownBy(() -> router.resolveSpecifiedLookupKey(" "));
|
||||||
|
assertThatIllegalArgumentException().isThrownBy(() -> router.resolveSpecifiedLookupKey("bogus"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify that the internal 'constants' map is properly configured for all
|
||||||
|
* ISOLATION_ constants defined in {@link TransactionDefinition}.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
void resolveSpecifiedLookupKeyByNameForAllSupportedValues() {
|
||||||
|
Set<Integer> uniqueValues = new HashSet<>();
|
||||||
|
streamIsolationConstants()
|
||||||
|
.forEach(name -> {
|
||||||
|
Integer isolationLevel = (Integer) router.resolveSpecifiedLookupKey(name);
|
||||||
|
Integer expected = IsolationLevelDataSourceRouter.constants.get(name);
|
||||||
|
assertThat(isolationLevel).isEqualTo(expected);
|
||||||
|
uniqueValues.add(isolationLevel);
|
||||||
|
});
|
||||||
|
assertThat(uniqueValues).containsExactlyInAnyOrderElementsOf(IsolationLevelDataSourceRouter.constants.values());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void resolveSpecifiedLookupKeyByInteger() {
|
||||||
|
assertThatIllegalArgumentException().isThrownBy(() -> router.resolveSpecifiedLookupKey(999));
|
||||||
|
|
||||||
|
assertThat(router.resolveSpecifiedLookupKey(ISOLATION_DEFAULT)).isEqualTo(ISOLATION_DEFAULT);
|
||||||
|
assertThat(router.resolveSpecifiedLookupKey(ISOLATION_READ_UNCOMMITTED)).isEqualTo(ISOLATION_READ_UNCOMMITTED);
|
||||||
|
assertThat(router.resolveSpecifiedLookupKey(ISOLATION_READ_COMMITTED)).isEqualTo(ISOLATION_READ_COMMITTED);
|
||||||
|
assertThat(router.resolveSpecifiedLookupKey(ISOLATION_REPEATABLE_READ)).isEqualTo(ISOLATION_REPEATABLE_READ);
|
||||||
|
assertThat(router.resolveSpecifiedLookupKey(ISOLATION_SERIALIZABLE)).isEqualTo(ISOLATION_SERIALIZABLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static Stream<String> streamIsolationConstants() {
|
||||||
|
return Arrays.stream(TransactionDefinition.class.getFields())
|
||||||
|
.filter(ReflectionUtils::isPublicStaticFinal)
|
||||||
|
.map(Field::getName)
|
||||||
|
.filter(name -> name.startsWith("ISOLATION_"));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue