Exception fine-tuning and general polishing

Issue: SPR-13067
This commit is contained in:
Juergen Hoeller 2015-07-17 15:24:04 +02:00
parent 9f15f347bf
commit aedef43a9a
5 changed files with 41 additions and 39 deletions

View File

@ -55,6 +55,7 @@ abstract class AbstractAliasAwareAnnotationAttributeExtractor implements Annotat
*/ */
AbstractAliasAwareAnnotationAttributeExtractor(Class<? extends Annotation> annotationType, AbstractAliasAwareAnnotationAttributeExtractor(Class<? extends Annotation> annotationType,
AnnotatedElement annotatedElement, Object source) { AnnotatedElement annotatedElement, Object source) {
Assert.notNull(annotationType, "annotationType must not be null"); Assert.notNull(annotationType, "annotationType must not be null");
Assert.notNull(source, "source must not be null"); Assert.notNull(source, "source must not be null");
this.annotationType = annotationType; this.annotationType = annotationType;
@ -63,6 +64,7 @@ abstract class AbstractAliasAwareAnnotationAttributeExtractor implements Annotat
this.attributeAliasMap = AnnotationUtils.getAttributeAliasMap(annotationType); this.attributeAliasMap = AnnotationUtils.getAttributeAliasMap(annotationType);
} }
@Override @Override
public final Class<? extends Annotation> getAnnotationType() { public final Class<? extends Annotation> getAnnotationType() {
return this.annotationType; return this.annotationType;
@ -84,25 +86,24 @@ abstract class AbstractAliasAwareAnnotationAttributeExtractor implements Annotat
Object attributeValue = getRawAttributeValue(attributeMethod); Object attributeValue = getRawAttributeValue(attributeMethod);
String aliasName = this.attributeAliasMap.get(attributeName); String aliasName = this.attributeAliasMap.get(attributeName);
if ((aliasName != null)) { if (aliasName != null) {
Object aliasValue = getRawAttributeValue(aliasName); Object aliasValue = getRawAttributeValue(aliasName);
Object defaultValue = AnnotationUtils.getDefaultValue(getAnnotationType(), attributeName); Object defaultValue = AnnotationUtils.getDefaultValue(getAnnotationType(), attributeName);
if (!nullSafeEquals(attributeValue, aliasValue) && !nullSafeEquals(attributeValue, defaultValue) if (!ObjectUtils.nullSafeEquals(attributeValue, aliasValue) &&
&& !nullSafeEquals(aliasValue, defaultValue)) { !ObjectUtils.nullSafeEquals(attributeValue, defaultValue) &&
String elementName = (getAnnotatedElement() == null ? "unknown element" !ObjectUtils.nullSafeEquals(aliasValue, defaultValue)) {
: getAnnotatedElement().toString()); String elementName = (getAnnotatedElement() != null ? getAnnotatedElement().toString() : "unknown element");
String msg = String.format("In annotation [%s] declared on [%s] and synthesized from [%s], " throw new AnnotationConfigurationException(String.format(
+ "attribute [%s] and its alias [%s] are present with values of [%s] and [%s], " "In annotation [%s] declared on %s and synthesized from [%s], attribute '%s' and its " +
+ "but only one is permitted.", getAnnotationType().getName(), elementName, getSource(), "alias '%s' are present with values of [%s] and [%s], but only one is permitted.",
attributeName, aliasName, nullSafeToString(attributeValue), nullSafeToString(aliasValue)); getAnnotationType().getName(), elementName, getSource(), attributeName, aliasName,
throw new AnnotationConfigurationException(msg); ObjectUtils.nullSafeToString(attributeValue), ObjectUtils.nullSafeToString(aliasValue)));
} }
// If the user didn't declare the annotation with an explicit value, // If the user didn't declare the annotation with an explicit value,
// return the value of the alias. // return the value of the alias.
if (nullSafeEquals(attributeValue, defaultValue)) { if (ObjectUtils.nullSafeEquals(attributeValue, defaultValue)) {
attributeValue = aliasValue; attributeValue = aliasValue;
} }
} }
@ -110,6 +111,7 @@ abstract class AbstractAliasAwareAnnotationAttributeExtractor implements Annotat
return attributeValue; return attributeValue;
} }
/** /**
* Get the raw, unmodified attribute value from the underlying * Get the raw, unmodified attribute value from the underlying
* {@linkplain #getSource source} that corresponds to the supplied * {@linkplain #getSource source} that corresponds to the supplied
@ -124,12 +126,4 @@ abstract class AbstractAliasAwareAnnotationAttributeExtractor implements Annotat
*/ */
protected abstract Object getRawAttributeValue(String attributeName); protected abstract Object getRawAttributeValue(String attributeName);
private static boolean nullSafeEquals(Object o1, Object o2) {
return ObjectUtils.nullSafeEquals(o1, o2);
}
private static String nullSafeToString(Object obj) {
return ObjectUtils.nullSafeToString(obj);
}
} }

View File

@ -16,6 +16,8 @@
package org.springframework.core.annotation; package org.springframework.core.annotation;
import org.springframework.core.NestedRuntimeException;
/** /**
* Thrown by {@link AnnotationUtils} and <em>synthesized annotations</em> * Thrown by {@link AnnotationUtils} and <em>synthesized annotations</em>
* if an annotation is improperly configured. * if an annotation is improperly configured.
@ -26,7 +28,7 @@ package org.springframework.core.annotation;
* @see SynthesizedAnnotation * @see SynthesizedAnnotation
*/ */
@SuppressWarnings("serial") @SuppressWarnings("serial")
public class AnnotationConfigurationException extends RuntimeException { public class AnnotationConfigurationException extends NestedRuntimeException {
/** /**
* Construct a new {@code AnnotationConfigurationException} with the * Construct a new {@code AnnotationConfigurationException} with the

View File

@ -46,20 +46,22 @@ class DefaultAnnotationAttributeExtractor extends AbstractAliasAwareAnnotationAt
super(annotation.annotationType(), annotatedElement, annotation); super(annotation.annotationType(), annotatedElement, annotation);
} }
@Override
public Annotation getSource() {
return (Annotation) super.getSource();
}
@Override @Override
protected Object getRawAttributeValue(Method attributeMethod) { protected Object getRawAttributeValue(Method attributeMethod) {
ReflectionUtils.makeAccessible(attributeMethod); ReflectionUtils.makeAccessible(attributeMethod);
return ReflectionUtils.invokeMethod(attributeMethod, getAnnotation()); return ReflectionUtils.invokeMethod(attributeMethod, getSource());
} }
@Override @Override
protected Object getRawAttributeValue(String attributeName) { protected Object getRawAttributeValue(String attributeName) {
Method attributeMethod = ReflectionUtils.findMethod(getAnnotation().annotationType(), attributeName); Method attributeMethod = ReflectionUtils.findMethod(getSource().annotationType(), attributeName);
return getRawAttributeValue(attributeMethod); return getRawAttributeValue(attributeMethod);
} }
private Annotation getAnnotation() {
return (Annotation) getSource();
}
} }

View File

@ -52,23 +52,26 @@ class MapAnnotationAttributeExtractor extends AbstractAliasAwareAnnotationAttrib
*/ */
MapAnnotationAttributeExtractor(Map<String, Object> attributes, Class<? extends Annotation> annotationType, MapAnnotationAttributeExtractor(Map<String, Object> attributes, Class<? extends Annotation> annotationType,
AnnotatedElement annotatedElement) { AnnotatedElement annotatedElement) {
super(annotationType, annotatedElement, enrichAndValidateAttributes(new HashMap<String, Object>(attributes), annotationType));
super(annotationType, annotatedElement, enrichAndValidateAttributes(attributes, annotationType));
}
@SuppressWarnings("unchecked")
public Map<String, Object> getSource() {
return (Map<String, Object>) super.getSource();
} }
@Override @Override
protected Object getRawAttributeValue(Method attributeMethod) { protected Object getRawAttributeValue(Method attributeMethod) {
return getMap().get(attributeMethod.getName()); return getSource().get(attributeMethod.getName());
} }
@Override @Override
protected Object getRawAttributeValue(String attributeName) { protected Object getRawAttributeValue(String attributeName) {
return getMap().get(attributeName); return getSource().get(attributeName);
} }
@SuppressWarnings("unchecked")
private Map<String, Object> getMap() {
return (Map<String, Object>) getSource();
}
/** /**
* Enrich and validate the supplied {@code attributes} map by ensuring * Enrich and validate the supplied {@code attributes} map by ensuring
@ -81,9 +84,10 @@ class MapAnnotationAttributeExtractor extends AbstractAliasAwareAnnotationAttrib
* an {@link IllegalArgumentException} will be thrown. * an {@link IllegalArgumentException} will be thrown.
* @see AliasFor * @see AliasFor
*/ */
private static Map<String, Object> enrichAndValidateAttributes(Map<String, Object> attributes, private static Map<String, Object> enrichAndValidateAttributes(
Class<? extends Annotation> annotationType) { Map<String, Object> original, Class<? extends Annotation> annotationType) {
Map<String, Object> attributes = new HashMap<String, Object>(original);
Map<String, String> attributeAliasMap = getAttributeAliasMap(annotationType); Map<String, String> attributeAliasMap = getAttributeAliasMap(annotationType);
for (Method attributeMethod : getAttributeMethods(annotationType)) { for (Method attributeMethod : getAttributeMethods(annotationType)) {

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2014 the original author or authors. * Copyright 2002-2015 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -75,8 +75,8 @@ public class SqlScriptsTestExecutionListenerTests {
exception.expect(AnnotationConfigurationException.class); exception.expect(AnnotationConfigurationException.class);
exception.expectMessage(either( exception.expectMessage(either(
containsString("attribute [value] and its alias [scripts]")).or( containsString("attribute 'value' and its alias 'scripts'")).or(
containsString("attribute [scripts] and its alias [value]"))); containsString("attribute 'scripts' and its alias 'value'")));
exception.expectMessage(either(containsString("values of [{foo}] and [{bar}]")).or( exception.expectMessage(either(containsString("values of [{foo}] and [{bar}]")).or(
containsString("values of [{bar}] and [{foo}]"))); containsString("values of [{bar}] and [{foo}]")));
exception.expectMessage(containsString("but only one is permitted")); exception.expectMessage(containsString("but only one is permitted"));