提交 d3a40687 编写于 作者: J Juergen Hoeller

Minimized ASM usage

In particular, avoid accidental usage of ASM for core JDK types - which will fail in case of a new bytecode version in the JDK, even if the application itself has been compiled with an earlier bytecode target.

Issue: SPR-10292
上级 34bcdcfe
/* /*
* Copyright 2002-2012 the original author or authors. * Copyright 2002-2013 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.
...@@ -58,15 +58,19 @@ public class AnnotatedGenericBeanDefinition extends GenericBeanDefinition implem ...@@ -58,15 +58,19 @@ public class AnnotatedGenericBeanDefinition extends GenericBeanDefinition implem
* allowing for ASM-based processing and avoidance of early loading of the bean class. * allowing for ASM-based processing and avoidance of early loading of the bean class.
* Note that this constructor is functionally equivalent to * Note that this constructor is functionally equivalent to
* {@link org.springframework.context.annotation.ScannedGenericBeanDefinition * {@link org.springframework.context.annotation.ScannedGenericBeanDefinition
* ScannedGenericBeanDefinition}, however the semantics of the latter indicate that * ScannedGenericBeanDefinition}, however the semantics of the latter indicate that a
* a bean was discovered specifically via component-scanning as opposed to other * bean was discovered specifically via component-scanning as opposed to other means.
* means.
* @param metadata the annotation metadata for the bean class in question * @param metadata the annotation metadata for the bean class in question
* @since 3.1.1 * @since 3.1.1
*/ */
public AnnotatedGenericBeanDefinition(AnnotationMetadata metadata) { public AnnotatedGenericBeanDefinition(AnnotationMetadata metadata) {
Assert.notNull(metadata, "AnnotationMetadata must not be null"); Assert.notNull(metadata, "AnnotationMetadata must not be null");
setBeanClassName(metadata.getClassName()); if (metadata instanceof StandardAnnotationMetadata) {
setBeanClass(((StandardAnnotationMetadata) metadata).getIntrospectedClass());
}
else {
setBeanClassName(metadata.getClassName());
}
this.metadata = metadata; this.metadata = metadata;
} }
......
/* /*
* Copyright 2002-2012 the original author or authors. * Copyright 2002-2013 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.
...@@ -81,7 +81,7 @@ final class ConfigurationClass { ...@@ -81,7 +81,7 @@ final class ConfigurationClass {
* using the {@link Import} annotation or automatically processed as a nested * using the {@link Import} annotation or automatically processed as a nested
* configuration class (if imported is {@code true}). * configuration class (if imported is {@code true}).
* @param metadataReader reader used to parse the underlying {@link Class} * @param metadataReader reader used to parse the underlying {@link Class}
* @param beanName name of the {@code @Configuration} class bean * @param imported whether the given configuration class is being imported
* @since 3.1.1 * @since 3.1.1
*/ */
public ConfigurationClass(MetadataReader metadataReader, boolean imported) { public ConfigurationClass(MetadataReader metadataReader, boolean imported) {
...@@ -110,7 +110,7 @@ final class ConfigurationClass { ...@@ -110,7 +110,7 @@ final class ConfigurationClass {
* using the {@link Import} annotation or automatically processed as a nested * using the {@link Import} annotation or automatically processed as a nested
* configuration class (if imported is {@code true}). * configuration class (if imported is {@code true}).
* @param clazz the underlying {@link Class} to represent * @param clazz the underlying {@link Class} to represent
* @param beanName name of the {@code @Configuration} class bean * @param imported whether the given configuration class is being imported
* @since 3.1.1 * @since 3.1.1
*/ */
public ConfigurationClass(Class<?> clazz, boolean imported) { public ConfigurationClass(Class<?> clazz, boolean imported) {
...@@ -119,6 +119,7 @@ final class ConfigurationClass { ...@@ -119,6 +119,7 @@ final class ConfigurationClass {
this.imported = imported; this.imported = imported;
} }
public AnnotationMetadata getMetadata() { public AnnotationMetadata getMetadata() {
return this.metadata; return this.metadata;
} }
......
...@@ -134,8 +134,6 @@ class ConfigurationClassBeanDefinitionReader { ...@@ -134,8 +134,6 @@ class ConfigurationClassBeanDefinitionReader {
private void registerBeanDefinitionForImportedConfigurationClass(ConfigurationClass configClass) { private void registerBeanDefinitionForImportedConfigurationClass(ConfigurationClass configClass) {
AnnotationMetadata metadata = configClass.getMetadata(); AnnotationMetadata metadata = configClass.getMetadata();
BeanDefinition configBeanDef = new AnnotatedGenericBeanDefinition(metadata); BeanDefinition configBeanDef = new AnnotatedGenericBeanDefinition(metadata);
String className = metadata.getClassName();
configBeanDef.setBeanClassName(className);
if (ConfigurationClassUtils.checkConfigurationClassCandidate(configBeanDef, this.metadataReaderFactory)) { if (ConfigurationClassUtils.checkConfigurationClassCandidate(configBeanDef, this.metadataReaderFactory)) {
String configBeanName = this.importBeanNameGenerator.generateBeanName(configBeanDef, this.registry); String configBeanName = this.importBeanNameGenerator.generateBeanName(configBeanDef, this.registry);
this.registry.registerBeanDefinition(configBeanName, configBeanDef); this.registry.registerBeanDefinition(configBeanName, configBeanDef);
...@@ -146,7 +144,7 @@ class ConfigurationClassBeanDefinitionReader { ...@@ -146,7 +144,7 @@ class ConfigurationClassBeanDefinitionReader {
} }
else { else {
this.problemReporter.error( this.problemReporter.error(
new InvalidConfigurationImportProblem(className, configClass.getResource(), metadata)); new InvalidConfigurationImportProblem(metadata.getClassName(), configClass.getResource(), metadata));
} }
} }
......
...@@ -17,11 +17,12 @@ ...@@ -17,11 +17,12 @@
package org.springframework.context.annotation; package org.springframework.context.annotation;
import java.io.IOException; import java.io.IOException;
import java.lang.annotation.Annotation;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
import java.util.Map; import java.util.Map;
...@@ -42,6 +43,7 @@ import org.springframework.beans.factory.support.BeanDefinitionReader; ...@@ -42,6 +43,7 @@ import org.springframework.beans.factory.support.BeanDefinitionReader;
import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanNameGenerator; import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.context.ResourceLoaderAware; import org.springframework.context.ResourceLoaderAware;
import org.springframework.core.NestedIOException;
import org.springframework.core.annotation.AnnotationAttributes; import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.env.CompositePropertySource; import org.springframework.core.env.CompositePropertySource;
import org.springframework.core.env.Environment; import org.springframework.core.env.Environment;
...@@ -54,7 +56,7 @@ import org.springframework.core.type.StandardAnnotationMetadata; ...@@ -54,7 +56,7 @@ import org.springframework.core.type.StandardAnnotationMetadata;
import org.springframework.core.type.classreading.MetadataReader; import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory; import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.AssignableTypeFilter; import org.springframework.core.type.filter.AssignableTypeFilter;
import org.springframework.util.CollectionUtils; import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import static org.springframework.context.annotation.MetadataUtils.*; import static org.springframework.context.annotation.MetadataUtils.*;
...@@ -171,45 +173,12 @@ class ConfigurationClassParser { ...@@ -171,45 +173,12 @@ class ConfigurationClassParser {
ConfigurationClass configClass, AnnotationMetadata metadata) throws IOException { ConfigurationClass configClass, AnnotationMetadata metadata) throws IOException {
// recursively process any member (nested) classes first // recursively process any member (nested) classes first
for (String memberClassName : metadata.getMemberClassNames()) { processMemberClasses(metadata);
MetadataReader reader = this.metadataReaderFactory.getMetadataReader(memberClassName);
AnnotationMetadata memberClassMetadata = reader.getAnnotationMetadata();
if (ConfigurationClassUtils.isConfigurationCandidate(memberClassMetadata)) {
processConfigurationClass(new ConfigurationClass(reader, true));
}
}
// process any @PropertySource annotations // process any @PropertySource annotations
AnnotationAttributes propertySource = AnnotationAttributes propertySource = attributesFor(metadata, org.springframework.context.annotation.PropertySource.class);
attributesFor(metadata, org.springframework.context.annotation.PropertySource.class);
if (propertySource != null) { if (propertySource != null) {
String name = propertySource.getString("name"); processPropertySource(propertySource);
String[] locations = propertySource.getStringArray("value");
int nLocations = locations.length;
if (nLocations == 0) {
throw new IllegalArgumentException("At least one @PropertySource(value) location is required");
}
for (int i = 0; i < nLocations; i++) {
locations[i] = this.environment.resolveRequiredPlaceholders(locations[i]);
}
ClassLoader classLoader = this.resourceLoader.getClassLoader();
if (!StringUtils.hasText(name)) {
for (String location : locations) {
this.propertySources.push(new ResourcePropertySource(location, classLoader));
}
}
else {
if (nLocations == 1) {
this.propertySources.push(new ResourcePropertySource(name, locations[0], classLoader));
}
else {
CompositePropertySource ps = new CompositePropertySource(name);
for (String location : locations) {
ps.addPropertySource(new ResourcePropertySource(location, classLoader));
}
this.propertySources.push(ps);
}
}
} }
// process any @ComponentScan annotions // process any @ComponentScan annotions
...@@ -228,9 +197,12 @@ class ConfigurationClassParser { ...@@ -228,9 +197,12 @@ class ConfigurationClassParser {
} }
// process any @Import annotations // process any @Import annotations
Set<String> imports = getImports(metadata.getClassName(), null, new HashSet<String>());
if (!CollectionUtils.isEmpty(imports)) { Set<Object> imports = new LinkedHashSet<Object>();
processImport(configClass, imports.toArray(new String[imports.size()]), true); Set<Object> visited = new LinkedHashSet<Object>();
collectImports(metadata, imports, visited);
if (!imports.isEmpty()) {
processImport(configClass, imports, true);
} }
// process any @ImportResource annotations // process any @ImportResource annotations
...@@ -279,6 +251,65 @@ class ConfigurationClassParser { ...@@ -279,6 +251,65 @@ class ConfigurationClassParser {
return null; return null;
} }
/**
* Register member (nested) classes that happen to be configuration classes themselves.
* @param metadata the metadata representation of the containing class
* @throws IOException if there is any problem reading metadata from a member class
*/
private void processMemberClasses(AnnotationMetadata metadata) throws IOException {
if (metadata instanceof StandardAnnotationMetadata) {
for (Class<?> memberClass : ((StandardAnnotationMetadata) metadata).getIntrospectedClass().getDeclaredClasses()) {
if (ConfigurationClassUtils.isConfigurationCandidate(new StandardAnnotationMetadata(memberClass))) {
processConfigurationClass(new ConfigurationClass(memberClass, true));
}
}
}
else {
for (String memberClassName : metadata.getMemberClassNames()) {
MetadataReader reader = this.metadataReaderFactory.getMetadataReader(memberClassName);
AnnotationMetadata memberClassMetadata = reader.getAnnotationMetadata();
if (ConfigurationClassUtils.isConfigurationCandidate(memberClassMetadata)) {
processConfigurationClass(new ConfigurationClass(reader, true));
}
}
}
}
/**
* Process the given <code>@PropertySource</code> annotation metadata.
* @param propertySource metadata for the <code>@PropertySource</code> annotation found
* @throws IOException if loading a property source failed
*/
private void processPropertySource(AnnotationAttributes propertySource) throws IOException {
String name = propertySource.getString("name");
String[] locations = propertySource.getStringArray("value");
int nLocations = locations.length;
if (nLocations == 0) {
throw new IllegalArgumentException("At least one @PropertySource(value) location is required");
}
for (int i = 0; i < nLocations; i++) {
locations[i] = this.environment.resolveRequiredPlaceholders(locations[i]);
}
ClassLoader classLoader = this.resourceLoader.getClassLoader();
if (!StringUtils.hasText(name)) {
for (String location : locations) {
this.propertySources.push(new ResourcePropertySource(location, classLoader));
}
}
else {
if (nLocations == 1) {
this.propertySources.push(new ResourcePropertySource(name, locations[0], classLoader));
}
else {
CompositePropertySource ps = new CompositePropertySource(name);
for (String location : locations) {
ps.addPropertySource(new ResourcePropertySource(location, classLoader));
}
this.propertySources.push(ps);
}
}
}
/** /**
* Recursively collect all declared {@code @Import} values. Unlike most * Recursively collect all declared {@code @Import} values. Unlike most
* meta-annotations it is valid to have several {@code @Import}s declared with * meta-annotations it is valid to have several {@code @Import}s declared with
...@@ -287,69 +318,99 @@ class ConfigurationClassParser { ...@@ -287,69 +318,99 @@ class ConfigurationClassParser {
* <p>For example, it is common for a {@code @Configuration} class to declare direct * <p>For example, it is common for a {@code @Configuration} class to declare direct
* {@code @Import}s in addition to meta-imports originating from an {@code @Enable} * {@code @Import}s in addition to meta-imports originating from an {@code @Enable}
* annotation. * annotation.
* @param className the class name to search * @param metadata the metadata representation of the class to search
* @param imports the imports collected so far or {@code null} * @param imports the imports collected so far
* @param visited used to track visited classes to prevent infinite recursion (must not be null) * @param visited used to track visited classes to prevent infinite recursion
* @return a set of all {@link Import#value() import values} or {@code null}
* @throws IOException if there is any problem reading metadata from the named class * @throws IOException if there is any problem reading metadata from the named class
*/ */
private Set<String> getImports(String className, Set<String> imports, Set<String> visited) throws IOException { private void collectImports(AnnotationMetadata metadata, Set<Object> imports, Set<Object> visited) throws IOException {
if (visited.add(className) && !className.startsWith("java")) { String className = metadata.getClassName();
AnnotationMetadata metadata = metadataReaderFactory.getMetadataReader(className).getAnnotationMetadata(); if (visited.add(className)) {
for (String annotationType : metadata.getAnnotationTypes()) { if (metadata instanceof StandardAnnotationMetadata) {
imports = getImports(annotationType, imports, visited); StandardAnnotationMetadata stdMetadata = (StandardAnnotationMetadata) metadata;
for (Annotation ann : stdMetadata.getIntrospectedClass().getAnnotations()) {
if (!ann.annotationType().getName().startsWith("java") && !(ann instanceof Import)) {
collectImports(new StandardAnnotationMetadata(ann.annotationType()), imports, visited);
}
}
Map<String, Object> attributes = stdMetadata.getAnnotationAttributes(Import.class.getName(), false);
if (attributes != null) {
Class[] value = (Class[]) attributes.get("value");
if (!ObjectUtils.isEmpty(value)) {
imports.addAll(Arrays.asList(value));
}
}
} }
Map<String, Object> attributes = metadata.getAnnotationAttributes(Import.class.getName(), true); else {
if (attributes != null) { for (String annotationType : metadata.getAnnotationTypes()) {
String[] value = (String[]) attributes.get("value"); if (!className.startsWith("java") && !className.equals(Import.class.getName())) {
if (value != null && value.length > 0) { try {
imports = (imports == null ? new LinkedHashSet<String>() : imports); collectImports(
imports.addAll(Arrays.asList(value)); new StandardAnnotationMetadata(this.resourceLoader.getClassLoader().loadClass(annotationType)),
imports, visited);
}
catch (ClassNotFoundException ex) {
//
}
}
}
Map<String, Object> attributes = metadata.getAnnotationAttributes(Import.class.getName(), true);
if (attributes != null) {
String[] value = (String[]) attributes.get("value");
if (!ObjectUtils.isEmpty(value)) {
imports.addAll(Arrays.asList(value));
}
} }
} }
} }
return imports;
} }
private void processImport(ConfigurationClass configClass, String[] classesToImport, boolean checkForCircularImports) throws IOException { private void processImport(ConfigurationClass configClass, Collection<?> classesToImport, boolean checkForCircularImports) throws IOException {
if (checkForCircularImports && this.importStack.contains(configClass)) { if (checkForCircularImports && this.importStack.contains(configClass)) {
this.problemReporter.error(new CircularImportProblem(configClass, this.importStack, configClass.getMetadata())); this.problemReporter.error(new CircularImportProblem(configClass, this.importStack, configClass.getMetadata()));
} }
else { else {
this.importStack.push(configClass); this.importStack.push(configClass);
AnnotationMetadata importingClassMetadata = configClass.getMetadata(); AnnotationMetadata importingClassMetadata = configClass.getMetadata();
for (String candidate : classesToImport) { try {
MetadataReader reader = this.metadataReaderFactory.getMetadataReader(candidate); for (Object candidate : classesToImport) {
if (new AssignableTypeFilter(ImportSelector.class).match(reader, this.metadataReaderFactory)) { Object candidateToCheck = (candidate instanceof Class ? (Class) candidate : this.metadataReaderFactory.getMetadataReader((String) candidate));
// the candidate class is an ImportSelector -> delegate to it to determine imports if (checkAssignability(ImportSelector.class, candidateToCheck)) {
try { // the candidate class is an ImportSelector -> delegate to it to determine imports
ImportSelector selector = BeanUtils.instantiateClass( Class<?> candidateClass = (candidate instanceof Class ? (Class) candidate : this.resourceLoader.getClassLoader().loadClass((String) candidate));
this.resourceLoader.getClassLoader().loadClass(candidate), ImportSelector.class); ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);
processImport(configClass, selector.selectImports(importingClassMetadata), false); processImport(configClass, Arrays.asList(selector.selectImports(importingClassMetadata)), false);
} }
catch (ClassNotFoundException ex) { else if (checkAssignability(ImportBeanDefinitionRegistrar.class, candidateToCheck)) {
throw new IllegalStateException(ex); // the candidate class is an ImportBeanDefinitionRegistrar -> delegate to it to register additional bean definitions
} Class<?> candidateClass = (candidate instanceof Class ? (Class) candidate : this.resourceLoader.getClassLoader().loadClass((String) candidate));
} ImportBeanDefinitionRegistrar registrar = BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class);
else if (new AssignableTypeFilter(ImportBeanDefinitionRegistrar.class).match(reader, this.metadataReaderFactory)) {
// the candidate class is an ImportBeanDefinitionRegistrar -> delegate to it to register additional bean definitions
try {
ImportBeanDefinitionRegistrar registrar = BeanUtils.instantiateClass(
this.resourceLoader.getClassLoader().loadClass(candidate), ImportBeanDefinitionRegistrar.class);
invokeAwareMethods(registrar); invokeAwareMethods(registrar);
registrar.registerBeanDefinitions(importingClassMetadata, registry); registrar.registerBeanDefinitions(importingClassMetadata, this.registry);
} }
catch (ClassNotFoundException ex) { else {
throw new IllegalStateException(ex); // candidate class not an ImportSelector or ImportBeanDefinitionRegistrar -> process it as a @Configuration class
this.importStack.registerImport(importingClassMetadata.getClassName(), (candidate instanceof Class ? ((Class) candidate).getName() : (String) candidate));
processConfigurationClass(candidateToCheck instanceof Class ? new ConfigurationClass((Class) candidateToCheck, true) :
new ConfigurationClass((MetadataReader) candidateToCheck, true));
} }
} }
else {
// the candidate class not an ImportSelector or ImportBeanDefinitionRegistrar -> process it as a @Configuration class
this.importStack.registerImport(importingClassMetadata.getClassName(), candidate);
processConfigurationClass(new ConfigurationClass(reader, true));
}
} }
this.importStack.pop(); catch (ClassNotFoundException ex) {
throw new NestedIOException("Failed to load import candidate class", ex);
}
finally {
this.importStack.pop();
}
}
}
private boolean checkAssignability(Class<?> clazz, Object candidate) throws IOException {
if (candidate instanceof Class) {
return clazz.isAssignableFrom((Class) candidate);
}
else {
return new AssignableTypeFilter(clazz).match((MetadataReader) candidate, this.metadataReaderFactory);
} }
} }
......
...@@ -79,7 +79,7 @@ public class ImportedConfigurationClassEnhancementTests { ...@@ -79,7 +79,7 @@ public class ImportedConfigurationClassEnhancementTests {
@Test(expected=BeanDefinitionParsingException.class) @Test(expected=BeanDefinitionParsingException.class)
public void importingAnNonConfigurationClassCausesIllegalArgumentException() { public void importingNonConfigurationClassCausesBeanDefinitionParsingException() {
new AnnotationConfigApplicationContext(ConfigThatImportsNonConfigClass.class); new AnnotationConfigApplicationContext(ConfigThatImportsNonConfigClass.class);
} }
} }
...@@ -103,5 +103,5 @@ class ConfigThatDoesImport extends Config { } ...@@ -103,5 +103,5 @@ class ConfigThatDoesImport extends Config { }
class ConfigThatDoesNotImport extends Config { } class ConfigThatDoesNotImport extends Config { }
@Configuration @Configuration
@Import(Void.class) @Import(TestBean.class)
class ConfigThatImportsNonConfigClass { } class ConfigThatImportsNonConfigClass { }
\ No newline at end of file
...@@ -114,8 +114,15 @@ public class LocalVariableTableParameterNameDiscoverer implements ParameterNameD ...@@ -114,8 +114,15 @@ public class LocalVariableTableParameterNameDiscoverer implements ParameterNameD
} }
catch (IOException ex) { catch (IOException ex) {
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
logger.debug("Exception thrown while reading '.class' file for class [" + clazz logger.debug("Exception thrown while reading '.class' file for class [" + clazz +
+ "] - unable to determine constructors/methods parameter names", ex); "] - unable to determine constructors/methods parameter names", ex);
}
}
catch (IllegalArgumentException ex) {
if (logger.isDebugEnabled()) {
logger.debug("ASM ClassReader failed to parse class file [" + clazz +
"], probably due to a new Java class file version that isn't supported yet " +
"- unable to determine constructors/methods parameter names", ex);
} }
} }
finally { finally {
......
/* /*
* Copyright 2002-2012 the original author or authors. * Copyright 2002-2013 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.
...@@ -145,6 +145,8 @@ public class StandardAnnotationMetadata extends StandardClassMetadata implements ...@@ -145,6 +145,8 @@ public class StandardAnnotationMetadata extends StandardClassMetadata implements
return AnnotationUtils.getAnnotationAttributes( return AnnotationUtils.getAnnotationAttributes(
ann, classValuesAsString, this.nestedAnnotationsAsMap); ann, classValuesAsString, this.nestedAnnotationsAsMap);
} }
}
for (Annotation ann : anns) {
for (Annotation metaAnn : ann.annotationType().getAnnotations()) { for (Annotation metaAnn : ann.annotationType().getAnnotations()) {
if (metaAnn.annotationType().getName().equals(annotationType)) { if (metaAnn.annotationType().getName().equals(annotationType)) {
return AnnotationUtils.getAnnotationAttributes( return AnnotationUtils.getAnnotationAttributes(
......
/* /*
* Copyright 2002-2012 the original author or authors. * Copyright 2002-2013 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.
...@@ -105,19 +105,11 @@ final class AnnotationMetadataReadingVisitor extends ClassMetadataReadingVisitor ...@@ -105,19 +105,11 @@ final class AnnotationMetadataReadingVisitor extends ClassMetadataReadingVisitor
} }
public AnnotationAttributes getAnnotationAttributes(String annotationType, boolean classValuesAsString) { public AnnotationAttributes getAnnotationAttributes(String annotationType, boolean classValuesAsString) {
return getAnnotationAttributes(annotationType, classValuesAsString, false);
}
public AnnotationAttributes getAnnotationAttributes(
String annotationType, boolean classValuesAsString, boolean nestedAttributesAsMap) {
AnnotationAttributes raw = this.attributeMap.get(annotationType); AnnotationAttributes raw = this.attributeMap.get(annotationType);
return convertClassValues(raw, classValuesAsString, nestedAttributesAsMap); return convertClassValues(raw, classValuesAsString);
} }
private AnnotationAttributes convertClassValues( private AnnotationAttributes convertClassValues(AnnotationAttributes original, boolean classValuesAsString) {
AnnotationAttributes original, boolean classValuesAsString, boolean nestedAttributesAsMap) {
if (original == null) { if (original == null) {
return null; return null;
} }
...@@ -126,12 +118,12 @@ final class AnnotationMetadataReadingVisitor extends ClassMetadataReadingVisitor ...@@ -126,12 +118,12 @@ final class AnnotationMetadataReadingVisitor extends ClassMetadataReadingVisitor
try { try {
Object value = entry.getValue(); Object value = entry.getValue();
if (value instanceof AnnotationAttributes) { if (value instanceof AnnotationAttributes) {
value = convertClassValues((AnnotationAttributes)value, classValuesAsString, nestedAttributesAsMap); value = convertClassValues((AnnotationAttributes) value, classValuesAsString);
} }
else if (value instanceof AnnotationAttributes[]) { else if (value instanceof AnnotationAttributes[]) {
AnnotationAttributes[] values = (AnnotationAttributes[])value; AnnotationAttributes[] values = (AnnotationAttributes[])value;
for (int i = 0; i < values.length; i++) { for (int i = 0; i < values.length; i++) {
values[i] = convertClassValues(values[i], classValuesAsString, nestedAttributesAsMap); values[i] = convertClassValues(values[i], classValuesAsString);
} }
} }
else if (value instanceof Type) { else if (value instanceof Type) {
...@@ -182,4 +174,5 @@ final class AnnotationMetadataReadingVisitor extends ClassMetadataReadingVisitor ...@@ -182,4 +174,5 @@ final class AnnotationMetadataReadingVisitor extends ClassMetadataReadingVisitor
annotatedMethods.addAll(list); annotatedMethods.addAll(list);
return annotatedMethods; return annotatedMethods;
} }
} }
...@@ -64,7 +64,7 @@ final class SimpleMetadataReader implements MetadataReader { ...@@ -64,7 +64,7 @@ final class SimpleMetadataReader implements MetadataReader {
classReader.accept(visitor, ClassReader.SKIP_DEBUG); classReader.accept(visitor, ClassReader.SKIP_DEBUG);
this.annotationMetadata = visitor; this.annotationMetadata = visitor;
// (since AnnotationMetadataReader extends ClassMetadataReadingVisitor) // (since AnnotationMetadataReadingVisitor extends ClassMetadataReadingVisitor)
this.classMetadata = visitor; this.classMetadata = visitor;
this.resource = resource; this.resource = resource;
} }
......
...@@ -16,13 +16,10 @@ ...@@ -16,13 +16,10 @@
package org.springframework.transaction.annotation; package org.springframework.transaction.annotation;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
import java.util.Map; import java.util.Map;
import org.junit.Test; import org.junit.Test;
import org.springframework.aop.support.AopUtils; import org.springframework.aop.support.AopUtils;
import org.springframework.context.annotation.AdviceMode; import org.springframework.context.annotation.AdviceMode;
import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext;
...@@ -33,6 +30,9 @@ import org.springframework.tests.transaction.CallCountingTransactionManager; ...@@ -33,6 +30,9 @@ import org.springframework.tests.transaction.CallCountingTransactionManager;
import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.AnnotationTransactionNamespaceHandlerTests.TransactionalTestBean; import org.springframework.transaction.annotation.AnnotationTransactionNamespaceHandlerTests.TransactionalTestBean;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
/** /**
* Tests demonstrating use of @EnableTransactionManagement @Configuration classes. * Tests demonstrating use of @EnableTransactionManagement @Configuration classes.
* *
...@@ -84,9 +84,9 @@ public class EnableTransactionManagementTests { ...@@ -84,9 +84,9 @@ public class EnableTransactionManagementTests {
new AnnotationConfigApplicationContext(EnableAspectJTxConfig.class, TxManagerConfig.class); new AnnotationConfigApplicationContext(EnableAspectJTxConfig.class, TxManagerConfig.class);
fail("should have thrown CNFE when trying to load AnnotationTransactionAspect. " + fail("should have thrown CNFE when trying to load AnnotationTransactionAspect. " +
"Do you actually have org.springframework.aspects on the classpath?"); "Do you actually have org.springframework.aspects on the classpath?");
} catch (Exception ex) { }
System.out.println(ex); catch (Exception ex) {
assertThat(ex.getMessage().endsWith("AspectJTransactionManagementConfiguration.class] cannot be opened because it does not exist"), is(true)); assertThat(ex.getMessage().contains("AspectJTransactionManagementConfiguration"), is(true));
} }
} }
......
/* /*
* Copyright 2002-2012 the original author or authors. * Copyright 2002-2013 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.
...@@ -16,14 +16,11 @@ ...@@ -16,14 +16,11 @@
package org.springframework.cache.annotation; package org.springframework.cache.annotation;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import org.junit.Test; import org.junit.Test;
import org.springframework.aop.Advisor; import org.springframework.aop.Advisor;
import org.springframework.aop.framework.Advised; import org.springframework.aop.framework.Advised;
import org.springframework.aop.support.AopUtils; import org.springframework.aop.support.AopUtils;
...@@ -36,6 +33,9 @@ import org.springframework.context.annotation.Bean; ...@@ -36,6 +33,9 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Repository; import org.springframework.stereotype.Repository;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
/** /**
* Integration tests for the @EnableCaching annotation. * Integration tests for the @EnableCaching annotation.
* *
...@@ -60,11 +60,12 @@ public class EnableCachingIntegrationTests { ...@@ -60,11 +60,12 @@ public class EnableCachingIntegrationTests {
ctx.register(Config.class, AspectJCacheConfig.class); ctx.register(Config.class, AspectJCacheConfig.class);
try { try {
ctx.refresh(); ctx.refresh();
} catch (Exception ex) { }
catch (Exception ex) {
// this test is a bit fragile, but gets the job done, proving that an // this test is a bit fragile, but gets the job done, proving that an
// attempt was made to look up the AJ aspect. It's due to classpath issues // attempt was made to look up the AJ aspect. It's due to classpath issues
// in .integration-tests that it's not found. // in .integration-tests that it's not found.
assertTrue(ex.getMessage().endsWith("AspectJCachingConfiguration.class] cannot be opened because it does not exist")); assertTrue(ex.getMessage().contains("AspectJCachingConfiguration"));
} }
} }
......
...@@ -115,11 +115,12 @@ public class EnableTransactionManagementIntegrationTests { ...@@ -115,11 +115,12 @@ public class EnableTransactionManagementIntegrationTests {
ctx.register(Config.class, AspectJTxConfig.class); ctx.register(Config.class, AspectJTxConfig.class);
try { try {
ctx.refresh(); ctx.refresh();
} catch (Exception ex) { }
catch (Exception ex) {
// this test is a bit fragile, but gets the job done, proving that an // this test is a bit fragile, but gets the job done, proving that an
// attempt was made to look up the AJ aspect. It's due to classpath issues // attempt was made to look up the AJ aspect. It's due to classpath issues
// in .integration-tests that it's not found. // in .integration-tests that it's not found.
assertTrue(ex.getMessage().endsWith("AspectJTransactionManagementConfiguration.class] cannot be opened because it does not exist")); assertTrue(ex.getMessage().contains("AspectJTransactionManagementConfiguration"));
} }
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册