6 changed files with 312 additions and 220 deletions
@ -0,0 +1,95 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2002-2014 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 |
||||||
|
* |
||||||
|
* http://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.core.type.classreading; |
||||||
|
|
||||||
|
import java.lang.reflect.Field; |
||||||
|
|
||||||
|
import org.apache.commons.logging.Log; |
||||||
|
import org.apache.commons.logging.LogFactory; |
||||||
|
|
||||||
|
import org.springframework.asm.AnnotationVisitor; |
||||||
|
import org.springframework.asm.SpringAsmInfo; |
||||||
|
import org.springframework.asm.Type; |
||||||
|
import org.springframework.core.annotation.AnnotationAttributes; |
||||||
|
import org.springframework.util.ReflectionUtils; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author Chris Beams |
||||||
|
* @author Juergen Hoeller |
||||||
|
* @author Phillip Webb |
||||||
|
* @author Sam Brannen |
||||||
|
* @since 3.1.1 |
||||||
|
*/ |
||||||
|
abstract class AbstractRecursiveAnnotationVisitor extends AnnotationVisitor { |
||||||
|
|
||||||
|
protected final Log logger = LogFactory.getLog(getClass()); |
||||||
|
|
||||||
|
protected final AnnotationAttributes attributes; |
||||||
|
|
||||||
|
protected final ClassLoader classLoader; |
||||||
|
|
||||||
|
|
||||||
|
public AbstractRecursiveAnnotationVisitor(ClassLoader classLoader, AnnotationAttributes attributes) { |
||||||
|
super(SpringAsmInfo.ASM_VERSION); |
||||||
|
this.classLoader = classLoader; |
||||||
|
this.attributes = attributes; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public void visit(String attributeName, Object attributeValue) { |
||||||
|
this.attributes.put(attributeName, attributeValue); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public AnnotationVisitor visitAnnotation(String attributeName, String asmTypeDescriptor) { |
||||||
|
String annotationType = Type.getType(asmTypeDescriptor).getClassName(); |
||||||
|
AnnotationAttributes nestedAttributes = new AnnotationAttributes(); |
||||||
|
this.attributes.put(attributeName, nestedAttributes); |
||||||
|
return new RecursiveAnnotationAttributesVisitor(annotationType, nestedAttributes, this.classLoader); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public AnnotationVisitor visitArray(String attributeName) { |
||||||
|
return new RecursiveAnnotationArrayVisitor(attributeName, this.attributes, this.classLoader); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void visitEnum(String attributeName, String asmTypeDescriptor, String attributeValue) { |
||||||
|
Object newValue = getEnumValue(asmTypeDescriptor, attributeValue); |
||||||
|
visit(attributeName, newValue); |
||||||
|
} |
||||||
|
|
||||||
|
protected Object getEnumValue(String asmTypeDescriptor, String attributeValue) { |
||||||
|
Object valueToUse = attributeValue; |
||||||
|
try { |
||||||
|
Class<?> enumType = this.classLoader.loadClass(Type.getType(asmTypeDescriptor).getClassName()); |
||||||
|
Field enumConstant = ReflectionUtils.findField(enumType, attributeValue); |
||||||
|
if (enumConstant != null) { |
||||||
|
valueToUse = enumConstant.get(null); |
||||||
|
} |
||||||
|
} |
||||||
|
catch (ClassNotFoundException ex) { |
||||||
|
logger.debug("Failed to classload enum type while reading annotation metadata", ex); |
||||||
|
} |
||||||
|
catch (IllegalAccessException ex) { |
||||||
|
logger.warn("Could not access enum value while reading annotation metadata", ex); |
||||||
|
} |
||||||
|
return valueToUse; |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,85 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2002-2014 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 |
||||||
|
* |
||||||
|
* http://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.core.type.classreading; |
||||||
|
|
||||||
|
import java.lang.reflect.Array; |
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
import org.springframework.asm.AnnotationVisitor; |
||||||
|
import org.springframework.asm.Type; |
||||||
|
import org.springframework.core.annotation.AnnotationAttributes; |
||||||
|
import org.springframework.util.ObjectUtils; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author Chris Beams |
||||||
|
* @author Juergen Hoeller |
||||||
|
* @since 3.1.1 |
||||||
|
*/ |
||||||
|
class RecursiveAnnotationArrayVisitor extends AbstractRecursiveAnnotationVisitor { |
||||||
|
|
||||||
|
private final String attributeName; |
||||||
|
|
||||||
|
private final List<AnnotationAttributes> allNestedAttributes = new ArrayList<AnnotationAttributes>(); |
||||||
|
|
||||||
|
|
||||||
|
public RecursiveAnnotationArrayVisitor( |
||||||
|
String attributeName, AnnotationAttributes attributes, ClassLoader classLoader) { |
||||||
|
|
||||||
|
super(classLoader, attributes); |
||||||
|
this.attributeName = attributeName; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public void visit(String attributeName, Object attributeValue) { |
||||||
|
Object newValue = attributeValue; |
||||||
|
Object existingValue = this.attributes.get(this.attributeName); |
||||||
|
if (existingValue != null) { |
||||||
|
newValue = ObjectUtils.addObjectToArray((Object[]) existingValue, newValue); |
||||||
|
} |
||||||
|
else { |
||||||
|
Class<?> arrayClass = newValue.getClass(); |
||||||
|
if (Enum.class.isAssignableFrom(arrayClass)) { |
||||||
|
while (arrayClass.getSuperclass() != null && !arrayClass.isEnum()) { |
||||||
|
arrayClass = arrayClass.getSuperclass(); |
||||||
|
} |
||||||
|
} |
||||||
|
Object[] newArray = (Object[]) Array.newInstance(arrayClass, 1); |
||||||
|
newArray[0] = newValue; |
||||||
|
newValue = newArray; |
||||||
|
} |
||||||
|
this.attributes.put(this.attributeName, newValue); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public AnnotationVisitor visitAnnotation(String attributeName, String asmTypeDescriptor) { |
||||||
|
String annotationType = Type.getType(asmTypeDescriptor).getClassName(); |
||||||
|
AnnotationAttributes nestedAttributes = new AnnotationAttributes(); |
||||||
|
this.allNestedAttributes.add(nestedAttributes); |
||||||
|
return new RecursiveAnnotationAttributesVisitor(annotationType, nestedAttributes, this.classLoader); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void visitEnd() { |
||||||
|
if (!this.allNestedAttributes.isEmpty()) { |
||||||
|
this.attributes.put(this.attributeName, |
||||||
|
this.allNestedAttributes.toArray(new AnnotationAttributes[this.allNestedAttributes.size()])); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,90 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2002-2014 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 |
||||||
|
* |
||||||
|
* http://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.core.type.classreading; |
||||||
|
|
||||||
|
import java.lang.annotation.Annotation; |
||||||
|
import java.lang.reflect.Method; |
||||||
|
import java.lang.reflect.Modifier; |
||||||
|
|
||||||
|
import org.springframework.core.annotation.AnnotationAttributes; |
||||||
|
import org.springframework.core.annotation.AnnotationUtils; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author Chris Beams |
||||||
|
* @author Juergen Hoeller |
||||||
|
* @since 3.1.1 |
||||||
|
*/ |
||||||
|
class RecursiveAnnotationAttributesVisitor extends AbstractRecursiveAnnotationVisitor { |
||||||
|
|
||||||
|
private final String annotationType; |
||||||
|
|
||||||
|
|
||||||
|
public RecursiveAnnotationAttributesVisitor( |
||||||
|
String annotationType, AnnotationAttributes attributes, ClassLoader classLoader) { |
||||||
|
|
||||||
|
super(classLoader, attributes); |
||||||
|
this.annotationType = annotationType; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public final void visitEnd() { |
||||||
|
try { |
||||||
|
Class<?> annotationClass = this.classLoader.loadClass(this.annotationType); |
||||||
|
doVisitEnd(annotationClass); |
||||||
|
} |
||||||
|
catch (ClassNotFoundException ex) { |
||||||
|
logger.debug("Failed to class-load type while reading annotation metadata. " + |
||||||
|
"This is a non-fatal error, but certain annotation metadata may be unavailable.", ex); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
protected void doVisitEnd(Class<?> annotationClass) { |
||||||
|
registerDefaultValues(annotationClass); |
||||||
|
} |
||||||
|
|
||||||
|
private void registerDefaultValues(Class<?> annotationClass) { |
||||||
|
// Only do further scanning for public annotations; we'd run into
|
||||||
|
// IllegalAccessExceptions otherwise, and we don't want to mess with
|
||||||
|
// accessibility in a SecurityManager environment.
|
||||||
|
if (Modifier.isPublic(annotationClass.getModifiers())) { |
||||||
|
// Check declared default values of attributes in the annotation type.
|
||||||
|
Method[] annotationAttributes = annotationClass.getMethods(); |
||||||
|
for (Method annotationAttribute : annotationAttributes) { |
||||||
|
String attributeName = annotationAttribute.getName(); |
||||||
|
Object defaultValue = annotationAttribute.getDefaultValue(); |
||||||
|
if (defaultValue != null && !this.attributes.containsKey(attributeName)) { |
||||||
|
if (defaultValue instanceof Annotation) { |
||||||
|
defaultValue = AnnotationAttributes.fromMap(AnnotationUtils.getAnnotationAttributes( |
||||||
|
(Annotation) defaultValue, false, true)); |
||||||
|
} |
||||||
|
else if (defaultValue instanceof Annotation[]) { |
||||||
|
Annotation[] realAnnotations = (Annotation[]) defaultValue; |
||||||
|
AnnotationAttributes[] mappedAnnotations = new AnnotationAttributes[realAnnotations.length]; |
||||||
|
for (int i = 0; i < realAnnotations.length; i++) { |
||||||
|
mappedAnnotations[i] = AnnotationAttributes.fromMap( |
||||||
|
AnnotationUtils.getAnnotationAttributes(realAnnotations[i], false, true)); |
||||||
|
} |
||||||
|
defaultValue = mappedAnnotations; |
||||||
|
} |
||||||
|
this.attributes.put(attributeName, defaultValue); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
Loading…
Reference in new issue