Skip to content

Commit

Permalink
Infer AnnotationAttributes method return types
Browse files Browse the repository at this point in the history
 - 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.
  • Loading branch information
cbeams committed Feb 13, 2012
1 parent 997c6c5 commit e25f1cb
Show file tree
Hide file tree
Showing 13 changed files with 43 additions and 45 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public BeanFactoryCacheOperationSourceAdvisor cacheAdvisor() {
new BeanFactoryCacheOperationSourceAdvisor();
advisor.setCacheOperationSource(cacheOperationSource());
advisor.setAdvice(cacheInterceptor());
advisor.setOrder(this.enableCaching.getInt("order"));
advisor.setOrder(this.enableCaching.<Integer>getNumber("order"));
return advisor;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,7 @@ public final String[] selectImports(AnnotationMetadata importingClassMetadata) {
"@%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));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -232,8 +232,8 @@ static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd) {
}
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);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ public ScopeMetadata resolveScopeMetadata(BeanDefinition definition) {
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;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,15 +70,15 @@ public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan) {
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"));
Expand Down Expand Up @@ -118,7 +118,7 @@ public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan) {

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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) {
// 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
Expand Down Expand Up @@ -246,7 +246,7 @@ else if (configClass.getMetadata().isAnnotated(Lazy.class.getName())){
}
}

Autowire autowire = bean.getEnum("autowire", Autowire.class);
Autowire autowire = bean.getEnum("autowire");
if (autowire.isAutowire()) {
beanDef.setAutowireMode(autowire.value());
}
Expand All @@ -266,7 +266,7 @@ else if (configClass.getMetadata().isAnnotated(Lazy.class.getName())){
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;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -216,8 +216,7 @@ protected void doProcessConfigurationClass(ConfigurationClass configClass, Annot
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);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@

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;
Expand Down Expand Up @@ -80,7 +78,8 @@ public LoadTimeWeaver loadTimeWeaver() {
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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public AsyncAnnotationBeanPostProcessor asyncAdvisor() {

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);
}
Expand All @@ -56,8 +56,7 @@ public AsyncAnnotationBeanPostProcessor asyncAdvisor() {
}

bpp.setProxyTargetClass(this.enableAsync.getBoolean("proxyTargetClass"));

bpp.setOrder(this.enableAsync.getInt("order"));
bpp.setOrder(this.enableAsync.<Integer>getNumber("order"));

return bpp;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,16 +92,18 @@ public boolean getBoolean(String attributeName) {
return doGet(attributeName, Boolean.class);
}

public int getInt(String attributeName) {
return doGet(attributeName, Integer.class);
@SuppressWarnings("unchecked")
public <N extends Number> N getNumber(String attributeName) {
return (N) doGet(attributeName, Integer.class);
}

public <E extends Enum<?>> E getEnum(String attributeName, Class<E> enumType) {
return doGet(attributeName, enumType);
@SuppressWarnings("unchecked")
public <E extends Enum<?>> E getEnum(String attributeName) {
return (E) doGet(attributeName, Enum.class);
}

@SuppressWarnings("unchecked")
public <T> Class<? extends T> getClass(String attributeName, Class<T> expectedType) {
public <T> Class<? extends T> getClass(String attributeName) {
return (Class<T>)doGet(attributeName, Class.class);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,11 @@ public void testTypeSafeAttributeAccess() {
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"));
}

Expand All @@ -68,13 +68,13 @@ public void getEnum_emptyAttributeName() {
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"));
Expand All @@ -86,7 +86,7 @@ public void getEnum_notFound() {
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"));
Expand All @@ -98,11 +98,11 @@ public void getEnum_typeMismatch() {
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));
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,34 +109,34 @@ private void doTestAnnotationInfo(AnnotationMetadata metadata) {
{ // 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"));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {
new BeanFactoryTransactionAttributeSourceAdvisor();
advisor.setTransactionAttributeSource(transactionAttributeSource());
advisor.setAdvice(transactionInterceptor());
advisor.setOrder(this.enableTx.getInt("order"));
advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
return advisor;
}

Expand Down

0 comments on commit e25f1cb

Please sign in to comment.