Stop using Constants utility in IsolationLevelDataSourceRouter

See gh-30851
This commit is contained in:
Sam Brannen 2023-07-31 14:40:34 +03:00
parent 181c814e69
commit 06c6af9b0d
2 changed files with 121 additions and 10 deletions

View File

@ -16,11 +16,12 @@
package org.springframework.jdbc.datasource.lookup;
import org.springframework.core.Constants;
import java.util.Map;
import org.springframework.lang.Nullable;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.util.Assert;
/**
* DataSource that routes to one of various target DataSources based on the
@ -82,6 +83,7 @@ import org.springframework.transaction.support.TransactionSynchronizationManager
* &lt;/bean&gt;</pre>
*
* @author Juergen Hoeller
* @author Sam Brannen
* @since 2.0.1
* @see #setTargetDataSources
* @see #setDefaultTargetDataSource
@ -93,8 +95,17 @@ import org.springframework.transaction.support.TransactionSynchronizationManager
*/
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
protected Object resolveSpecifiedLookupKey(Object lookupKey) {
if (lookupKey instanceof Integer) {
return lookupKey;
if (lookupKey instanceof Integer isolationLevel) {
Assert.isTrue(constants.containsValue(isolationLevel),
"Only values of isolation constants allowed");
return isolationLevel;
}
else if (lookupKey instanceof String constantName) {
if (!constantName.startsWith(DefaultTransactionDefinition.PREFIX_ISOLATION)) {
throw new IllegalArgumentException("Only isolation constants allowed");
}
return constants.asNumber(constantName);
Assert.hasText(constantName, "'lookupKey' must not be null or blank");
Integer isolationLevel = constants.get(constantName);
Assert.notNull(isolationLevel, "Only isolation constants allowed");
return isolationLevel;
}
else {
throw new IllegalArgumentException(

View File

@ -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_"));
}
}