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