Infer AnnotationAttributes method return types
- Drop 'expectedType' parameter from #getClass and #getEnum methods and rely on compiler inference based on type of assigned variable, e.g. public @interface Example { Color color(); Class<? extends UserType> userType(); int order() default 0; } AnnotationAttributes example = AnnotationUtils.getAnnotationAttributes(Example.class, true, true); Color color = example.getEnum("color"); Class<? extends UserType> userType = example.getClass("userType"); or in cases where there is no variable assignment (and thus no inference possible), use explicit generic type, e.g. bean.setColor(example.<Color>getEnum("color")); - Rename #get{Int=>Number} and update return type from int to <N extends Number>, allowing invocations such as: int order = example.getNumber("order"); These changes reduce the overall number of methods exposed by AnnotationAttributes, while at the same time providing comprehensive access to all possible annotation attribute types -- that is, instead of requiring explicit #getInt, #getFloat, #getDouble methods, the single #getNumber method is capabable of handling them all, and without any casting required. And the obvious additional benefit is more concise invocation as no redundant 'expectedType' parameters are required.
This commit is contained in:
parent
997c6c56f7
commit
e25f1cbca9
|
@ -44,7 +44,7 @@ public class ProxyCachingConfiguration extends AbstractCachingConfiguration {
|
|||
new BeanFactoryCacheOperationSourceAdvisor();
|
||||
advisor.setCacheOperationSource(cacheOperationSource());
|
||||
advisor.setAdvice(cacheInterceptor());
|
||||
advisor.setOrder(this.enableCaching.getInt("order"));
|
||||
advisor.setOrder(this.enableCaching.<Integer>getNumber("order"));
|
||||
return advisor;
|
||||
}
|
||||
|
||||
|
|
|
@ -73,8 +73,7 @@ public abstract class AdviceModeImportSelector<A extends Annotation> implements
|
|||
"@%s is not present on importing class '%s' as expected",
|
||||
annoType.getSimpleName(), importingClassMetadata.getClassName()));
|
||||
|
||||
AdviceMode adviceMode =
|
||||
attributes.getEnum(this.getAdviceModeAttributeName(), AdviceMode.class);
|
||||
AdviceMode adviceMode = attributes.getEnum(this.getAdviceModeAttributeName());
|
||||
|
||||
String[] imports = selectImports(adviceMode);
|
||||
Assert.notNull(imports, String.format("Unknown AdviceMode: '%s'", adviceMode));
|
||||
|
|
|
@ -232,8 +232,8 @@ public class AnnotationConfigUtils {
|
|||
}
|
||||
if (abd instanceof AbstractBeanDefinition) {
|
||||
if (metadata.isAnnotated(Role.class.getName())) {
|
||||
((AbstractBeanDefinition)abd).setRole(
|
||||
attributesFor(metadata, Role.class).getInt("value"));
|
||||
int role = attributesFor(metadata, Role.class).getNumber("value");
|
||||
((AbstractBeanDefinition)abd).setRole(role);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -81,7 +81,7 @@ public class AnnotationScopeMetadataResolver implements ScopeMetadataResolver {
|
|||
attributesFor(annDef.getMetadata(), this.scopeAnnotationType);
|
||||
if (attributes != null) {
|
||||
metadata.setScopeName(attributes.getString("value"));
|
||||
ScopedProxyMode proxyMode = attributes.getEnum("proxyMode", ScopedProxyMode.class);
|
||||
ScopedProxyMode proxyMode = attributes.getEnum("proxyMode");
|
||||
if (proxyMode == null || proxyMode == ScopedProxyMode.DEFAULT) {
|
||||
proxyMode = this.defaultProxyMode;
|
||||
}
|
||||
|
|
|
@ -70,15 +70,15 @@ class ComponentScanAnnotationParser {
|
|||
Assert.notNull(this.resourceLoader, "ResourceLoader must not be null");
|
||||
scanner.setResourceLoader(this.resourceLoader);
|
||||
|
||||
scanner.setBeanNameGenerator(BeanUtils.instantiateClass(
|
||||
componentScan.getClass("nameGenerator", BeanNameGenerator.class)));
|
||||
Class<? extends BeanNameGenerator> generatorClass = componentScan.getClass("nameGenerator");
|
||||
scanner.setBeanNameGenerator(BeanUtils.instantiateClass(generatorClass));
|
||||
|
||||
ScopedProxyMode scopedProxyMode = componentScan.getEnum("scopedProxy", ScopedProxyMode.class);
|
||||
ScopedProxyMode scopedProxyMode = componentScan.getEnum("scopedProxy");
|
||||
if (scopedProxyMode != ScopedProxyMode.DEFAULT) {
|
||||
scanner.setScopedProxyMode(scopedProxyMode);
|
||||
} else {
|
||||
scanner.setScopeMetadataResolver(BeanUtils.instantiateClass(
|
||||
componentScan.getClass("scopeResolver", ScopeMetadataResolver.class)));
|
||||
Class<? extends ScopeMetadataResolver> resolverClass = componentScan.getClass("scopeResolver");
|
||||
scanner.setScopeMetadataResolver(BeanUtils.instantiateClass(resolverClass));
|
||||
}
|
||||
|
||||
scanner.setResourcePattern(componentScan.getString("resourcePattern"));
|
||||
|
@ -118,7 +118,7 @@ class ComponentScanAnnotationParser {
|
|||
|
||||
private List<TypeFilter> typeFiltersFor(AnnotationAttributes filterAttributes) {
|
||||
List<TypeFilter> typeFilters = new ArrayList<TypeFilter>();
|
||||
FilterType filterType = filterAttributes.getEnum("type", FilterType.class);
|
||||
FilterType filterType = filterAttributes.getEnum("type");
|
||||
|
||||
for (Class<?> filterClass : filterAttributes.getClassArray("value")) {
|
||||
switch (filterType) {
|
||||
|
|
|
@ -198,7 +198,7 @@ class ConfigurationClassBeanDefinitionReader {
|
|||
// consider role
|
||||
AnnotationAttributes role = attributesFor(metadata, Role.class);
|
||||
if (role != null) {
|
||||
beanDef.setRole(role.getInt("value"));
|
||||
beanDef.setRole(role.<Integer>getNumber("value"));
|
||||
}
|
||||
|
||||
// consider name and any aliases
|
||||
|
@ -246,7 +246,7 @@ class ConfigurationClassBeanDefinitionReader {
|
|||
}
|
||||
}
|
||||
|
||||
Autowire autowire = bean.getEnum("autowire", Autowire.class);
|
||||
Autowire autowire = bean.getEnum("autowire");
|
||||
if (autowire.isAutowire()) {
|
||||
beanDef.setAutowireMode(autowire.value());
|
||||
}
|
||||
|
@ -266,7 +266,7 @@ class ConfigurationClassBeanDefinitionReader {
|
|||
AnnotationAttributes scope = attributesFor(metadata, Scope.class);
|
||||
if (scope != null) {
|
||||
beanDef.setScope(scope.getString("value"));
|
||||
proxyMode = scope.getEnum("proxyMode", ScopedProxyMode.class);
|
||||
proxyMode = scope.getEnum("proxyMode");
|
||||
if (proxyMode == ScopedProxyMode.DEFAULT) {
|
||||
proxyMode = ScopedProxyMode.NO;
|
||||
}
|
||||
|
|
|
@ -216,8 +216,7 @@ class ConfigurationClassParser {
|
|||
if (metadata.isAnnotated(ImportResource.class.getName())) {
|
||||
AnnotationAttributes importResource = attributesFor(metadata, ImportResource.class);
|
||||
String[] resources = importResource.getStringArray("value");
|
||||
Class<? extends BeanDefinitionReader> readerClass =
|
||||
importResource.getClass("reader", BeanDefinitionReader.class);
|
||||
Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
|
||||
for (String resource : resources) {
|
||||
configClass.addImportedResource(resource, readerClass);
|
||||
}
|
||||
|
|
|
@ -18,8 +18,6 @@ package org.springframework.context.annotation;
|
|||
|
||||
import static org.springframework.context.weaving.AspectJWeavingEnabler.ASPECTJ_AOP_XML_RESOURCE;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
|
@ -80,7 +78,8 @@ public class LoadTimeWeavingConfiguration implements ImportAware, BeanClassLoade
|
|||
loadTimeWeaver = new DefaultContextLoadTimeWeaver(this.beanClassLoader);
|
||||
}
|
||||
|
||||
switch (this.enableLTW.getEnum("aspectjWeaving", AspectJWeaving.class)) {
|
||||
AspectJWeaving aspectJWeaving = this.enableLTW.getEnum("aspectjWeaving");
|
||||
switch (aspectJWeaving) {
|
||||
case DISABLED:
|
||||
// AJ weaving is disabled -> do nothing
|
||||
break;
|
||||
|
|
|
@ -46,7 +46,7 @@ public class ProxyAsyncConfiguration extends AbstractAsyncConfiguration {
|
|||
|
||||
AsyncAnnotationBeanPostProcessor bpp = new AsyncAnnotationBeanPostProcessor();
|
||||
|
||||
Class<? extends Annotation> customAsyncAnnotation = enableAsync.getClass("annotation", Annotation.class);
|
||||
Class<? extends Annotation> customAsyncAnnotation = enableAsync.getClass("annotation");
|
||||
if (customAsyncAnnotation != AnnotationUtils.getDefaultValue(EnableAsync.class, "annotation")) {
|
||||
bpp.setAsyncAnnotationType(customAsyncAnnotation);
|
||||
}
|
||||
|
@ -56,8 +56,7 @@ public class ProxyAsyncConfiguration extends AbstractAsyncConfiguration {
|
|||
}
|
||||
|
||||
bpp.setProxyTargetClass(this.enableAsync.getBoolean("proxyTargetClass"));
|
||||
|
||||
bpp.setOrder(this.enableAsync.getInt("order"));
|
||||
bpp.setOrder(this.enableAsync.<Integer>getNumber("order"));
|
||||
|
||||
return bpp;
|
||||
}
|
||||
|
|
|
@ -92,16 +92,18 @@ public class AnnotationAttributes extends LinkedHashMap<String, Object> {
|
|||
return doGet(attributeName, Boolean.class);
|
||||
}
|
||||
|
||||
public int getInt(String attributeName) {
|
||||
return doGet(attributeName, Integer.class);
|
||||
}
|
||||
|
||||
public <E extends Enum<?>> E getEnum(String attributeName, Class<E> enumType) {
|
||||
return doGet(attributeName, enumType);
|
||||
@SuppressWarnings("unchecked")
|
||||
public <N extends Number> N getNumber(String attributeName) {
|
||||
return (N) doGet(attributeName, Integer.class);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> Class<? extends T> getClass(String attributeName, Class<T> expectedType) {
|
||||
public <E extends Enum<?>> E getEnum(String attributeName) {
|
||||
return (E) doGet(attributeName, Enum.class);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> Class<? extends T> getClass(String attributeName) {
|
||||
return (Class<T>)doGet(attributeName, Class.class);
|
||||
}
|
||||
|
||||
|
|
|
@ -55,11 +55,11 @@ public class AnnotationAttributesTests {
|
|||
assertThat(a.getStringArray("names"), equalTo(new String[] { "dave", "frank", "hal" }));
|
||||
assertThat(a.getBoolean("bool1"), equalTo(true));
|
||||
assertThat(a.getBoolean("bool2"), equalTo(false));
|
||||
assertThat(a.getEnum("color", Color.class), equalTo(Color.RED));
|
||||
assertTrue(a.getClass("clazz", Number.class).equals(Integer.class));
|
||||
assertThat(a.<Color>getEnum("color"), equalTo(Color.RED));
|
||||
assertTrue(a.getClass("clazz").equals(Integer.class));
|
||||
assertThat(a.getClassArray("classes"), equalTo(new Class[] { Number.class, Short.class, Integer.class }));
|
||||
assertThat(a.getInt("number"), equalTo(42));
|
||||
assertThat(a.getAnnotation("anno").getInt("value"), equalTo(10));
|
||||
assertThat(a.<Integer>getNumber("number"), equalTo(42));
|
||||
assertThat(a.getAnnotation("anno").<Integer>getNumber("value"), equalTo(10));
|
||||
assertThat(a.getAnnotationArray("annoArray")[0].getString("name"), equalTo("algernon"));
|
||||
}
|
||||
|
||||
|
@ -68,13 +68,13 @@ public class AnnotationAttributesTests {
|
|||
AnnotationAttributes a = new AnnotationAttributes();
|
||||
a.put("color", "RED");
|
||||
try {
|
||||
a.getEnum("", Color.class);
|
||||
a.getEnum("");
|
||||
fail();
|
||||
} catch (IllegalArgumentException ex) {
|
||||
assertThat(ex.getMessage(), equalTo("attributeName must not be null or empty"));
|
||||
}
|
||||
try {
|
||||
a.getEnum(null, Color.class);
|
||||
a.getEnum(null);
|
||||
fail();
|
||||
} catch (IllegalArgumentException ex) {
|
||||
assertThat(ex.getMessage(), equalTo("attributeName must not be null or empty"));
|
||||
|
@ -86,7 +86,7 @@ public class AnnotationAttributesTests {
|
|||
AnnotationAttributes a = new AnnotationAttributes();
|
||||
a.put("color", "RED");
|
||||
try {
|
||||
a.getEnum("colour", Color.class);
|
||||
a.getEnum("colour");
|
||||
fail();
|
||||
} catch (IllegalArgumentException ex) {
|
||||
assertThat(ex.getMessage(), equalTo("Attribute 'colour' not found"));
|
||||
|
@ -98,11 +98,11 @@ public class AnnotationAttributesTests {
|
|||
AnnotationAttributes a = new AnnotationAttributes();
|
||||
a.put("color", "RED");
|
||||
try {
|
||||
a.getEnum("color", Color.class);
|
||||
a.getEnum("color");
|
||||
fail();
|
||||
} catch (IllegalArgumentException ex) {
|
||||
String expected =
|
||||
"Attribute 'color' is of type [String], but [Color] was expected";
|
||||
"Attribute 'color' is of type [String], but [Enum] was expected";
|
||||
assertThat(ex.getMessage().substring(0, expected.length()), equalTo(expected));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -109,34 +109,34 @@ public class AnnotationMetadataTests {
|
|||
{ // perform tests with classValuesAsString = false (the default)
|
||||
AnnotationAttributes specialAttrs = (AnnotationAttributes) metadata.getAnnotationAttributes(SpecialAttr.class.getName());
|
||||
assertThat(specialAttrs.size(), is(6));
|
||||
assertTrue(String.class.isAssignableFrom(specialAttrs.getClass("clazz", Object.class)));
|
||||
assertThat(specialAttrs.getEnum("state", Thread.State.class), is(Thread.State.NEW));
|
||||
assertTrue(String.class.isAssignableFrom(specialAttrs.getClass("clazz")));
|
||||
assertTrue(specialAttrs.getEnum("state").equals(Thread.State.NEW));
|
||||
|
||||
AnnotationAttributes nestedAnno = specialAttrs.getAnnotation("nestedAnno");
|
||||
assertThat("na", is(nestedAnno.getString("value")));
|
||||
assertThat(nestedAnno.getEnum("anEnum", SomeEnum.class), is(SomeEnum.LABEL1));
|
||||
assertTrue(nestedAnno.getEnum("anEnum").equals(SomeEnum.LABEL1));
|
||||
assertArrayEquals(new Class[]{String.class}, (Class[])nestedAnno.get("classArray"));
|
||||
|
||||
AnnotationAttributes[] nestedAnnoArray = specialAttrs.getAnnotationArray("nestedAnnoArray");
|
||||
assertThat(nestedAnnoArray.length, is(2));
|
||||
assertThat(nestedAnnoArray[0].getString("value"), is("default"));
|
||||
assertThat(nestedAnnoArray[0].getEnum("anEnum", SomeEnum.class), is(SomeEnum.DEFAULT));
|
||||
assertTrue(nestedAnnoArray[0].getEnum("anEnum").equals(SomeEnum.DEFAULT));
|
||||
assertArrayEquals(new Class[]{Void.class}, (Class[])nestedAnnoArray[0].get("classArray"));
|
||||
assertThat(nestedAnnoArray[1].getString("value"), is("na1"));
|
||||
assertThat(nestedAnnoArray[1].getEnum("anEnum", SomeEnum.class), is(SomeEnum.LABEL2));
|
||||
assertTrue(nestedAnnoArray[1].getEnum("anEnum").equals(SomeEnum.LABEL2));
|
||||
assertArrayEquals(new Class[]{Number.class}, (Class[])nestedAnnoArray[1].get("classArray"));
|
||||
assertArrayEquals(new Class[]{Number.class}, nestedAnnoArray[1].getClassArray("classArray"));
|
||||
|
||||
AnnotationAttributes optional = specialAttrs.getAnnotation("optional");
|
||||
assertThat(optional.getString("value"), is("optional"));
|
||||
assertThat(optional.getEnum("anEnum", SomeEnum.class), is(SomeEnum.DEFAULT));
|
||||
assertTrue(optional.getEnum("anEnum").equals(SomeEnum.DEFAULT));
|
||||
assertArrayEquals(new Class[]{Void.class}, (Class[])optional.get("classArray"));
|
||||
assertArrayEquals(new Class[]{Void.class}, optional.getClassArray("classArray"));
|
||||
|
||||
AnnotationAttributes[] optionalArray = specialAttrs.getAnnotationArray("optionalArray");
|
||||
assertThat(optionalArray.length, is(1));
|
||||
assertThat(optionalArray[0].getString("value"), is("optional"));
|
||||
assertThat(optionalArray[0].getEnum("anEnum", SomeEnum.class), is(SomeEnum.DEFAULT));
|
||||
assertTrue(optionalArray[0].getEnum("anEnum").equals(SomeEnum.DEFAULT));
|
||||
assertArrayEquals(new Class[]{Void.class}, (Class[])optionalArray[0].get("classArray"));
|
||||
assertArrayEquals(new Class[]{Void.class}, optionalArray[0].getClassArray("classArray"));
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ public class ProxyTransactionManagementConfiguration extends AbstractTransaction
|
|||
new BeanFactoryTransactionAttributeSourceAdvisor();
|
||||
advisor.setTransactionAttributeSource(transactionAttributeSource());
|
||||
advisor.setAdvice(transactionInterceptor());
|
||||
advisor.setOrder(this.enableTx.getInt("order"));
|
||||
advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
|
||||
return advisor;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue