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; | ||||
| 
 | ||||
| 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 | |||
|  * </bean></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( | ||||
|  |  | |||
|  | @ -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