protected void processConfigurationClass(ConfigurationClass configClass) throws IOException { AnnotationMetadata metadata = configClass.getMetadata(); if (this.environment != null && ProfileHelper.isProfileAnnotationPresent(metadata)) { if (!this.environment.acceptsProfiles(ProfileHelper.getCandidateProfiles(metadata))) { return; } } while (metadata != null) { doProcessConfigurationClass(configClass, metadata); String superClassName = metadata.getSuperClassName(); if (superClassName != null && !Object.class.getName().equals(superClassName)) { if (metadata instanceof StandardAnnotationMetadata) { Class<?> clazz = ((StandardAnnotationMetadata) metadata).getIntrospectedClass(); metadata = new StandardAnnotationMetadata(clazz.getSuperclass()); } else { MetadataReader reader = this.metadataReaderFactory.getMetadataReader(superClassName); metadata = reader.getAnnotationMetadata(); } } else { metadata = null; } } if (this.configurationClasses.contains(configClass) && configClass.getBeanName() != null) { // Explicit bean definition found, probably replacing an import. // Let's remove the old one and go with the new one. this.configurationClasses.remove(configClass); } this.configurationClasses.add(configClass); }
private void processFeatureAnnotations(AnnotationMetadata metadata) { try { for (String annotationType : metadata.getAnnotationTypes()) { MetadataReader metadataReader = new SimpleMetadataReaderFactory().getMetadataReader(annotationType); if (metadataReader.getAnnotationMetadata().isAnnotated(FeatureAnnotation.class.getName())) { Map<String, Object> annotationAttributes = metadataReader .getAnnotationMetadata() .getAnnotationAttributes(FeatureAnnotation.class.getName(), true); // TODO SPR-7420: this is where we can catch user-defined types and avoid instantiating // them for STS purposes FeatureAnnotationParser processor = (FeatureAnnotationParser) BeanUtils.instantiateClass( Class.forName((String) annotationAttributes.get("parser"))); FeatureSpecification spec = processor.process(metadata); spec.execute(this.specificationContext); } } } catch (BeanDefinitionParsingException ex) { throw ex; } catch (Exception ex) { // TODO SPR-7420: what exception to throw? throw new RuntimeException(ex); } }
/** method adds all the method names to map with annotation attribute value as key */ private static void findAnnotationMethods( final Class<? extends Annotation> annotationClass, final String attributeName) throws IOException { final String basePackagePath = ClassUtils.convertClassNameToResourcePath( new StandardEnvironment().resolveRequiredPlaceholders(SEARCH_PACKAGE)); final String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + basePackagePath + "/" + RESOURCE_PATTERN; final Resource[] resources = resourcePatternResolver.getResources(packageSearchPath); for (final Resource resource : resources) { if (resource.isReadable()) { final MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(resource); final Set<MethodMetadata> metadataSet = metadataReader.getAnnotationMetadata().getAnnotatedMethods(annotationClass.getName()); if (metadataSet != null && metadataSet.size() > 0) { for (final MethodMetadata metadata : metadataSet) { final Map<String, Object> attributes = metadata.getAnnotationAttributes(annotationClass.getName()); final JobName attributeValue = (JobName) attributes.get(attributeName); final String className = metadata.getDeclaringClassName(); final String[] mapVal = {className, metadata.getMethodName()}; targetMethosMap.put(attributeValue.toString(), mapVal); } } } } }
/** Register the {@link Configuration} class itself as a bean definition. */ private void doLoadBeanDefinitionForConfigurationClassIfNecessary( ConfigurationClass configClass) { if (configClass.getBeanName() != null) { // a bean definition already exists for this configuration class -> nothing to do return; } // no bean definition exists yet -> this must be an imported configuration class (@Import). BeanDefinition configBeanDef = new GenericBeanDefinition(); String className = configClass.getMetadata().getClassName(); configBeanDef.setBeanClassName(className); if (checkConfigurationClassCandidate(configBeanDef, this.metadataReaderFactory)) { String configBeanName = BeanDefinitionReaderUtils.registerWithGeneratedName(configBeanDef, this.registry); configClass.setBeanName(configBeanName); if (logger.isDebugEnabled()) { logger.debug( String.format( "Registered bean definition for imported @Configuration class %s", configBeanName)); } } else { try { MetadataReader reader = this.metadataReaderFactory.getMetadataReader(className); AnnotationMetadata metadata = reader.getAnnotationMetadata(); this.problemReporter.error( new InvalidConfigurationImportProblem(className, reader.getResource(), metadata)); } catch (IOException ex) { throw new IllegalStateException("Could not create MetadataReader for class " + className); } } }
@Test public void asmAnnotationMetadataForSubclass() throws Exception { MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory(); MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(AnnotatedComponentSubClass.class.getName()); AnnotationMetadata metadata = metadataReader.getAnnotationMetadata(); doTestSubClassAnnotationInfo(metadata); }
@Test public void asmAnnotationMetadataForAnnotation() throws Exception { MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory(); MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(Component.class.getName()); AnnotationMetadata metadata = metadataReader.getAnnotationMetadata(); doTestMetadataForAnnotationClass(metadata); }
/** https://jira.spring.io/browse/SPR-11649 */ @Test public void multipleAnnotationsWithIdenticalAttributeNamesUsingAnnotationMetadataReadingVisitor() throws Exception { MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory(); MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(NamedAnnotationsClass.class.getName()); AnnotationMetadata metadata = metadataReader.getAnnotationMetadata(); assertMultipleAnnotationsWithIdenticalAttributeNames(metadata); }
@Test public void metaAnnotationOverridesUsingAnnotationMetadataReadingVisitor() throws Exception { MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory(); MetadataReader metadataReader = metadataReaderFactory.getMetadataReader( ComposedConfigurationWithAttributeOverridesClass.class.getName()); AnnotationMetadata metadata = metadataReader.getAnnotationMetadata(); assertMetaAnnotationOverrides(metadata); }
/** * Determine whether the given class does not match any exclude filter and does match at least one * include filter. * * @param metadataReader the ASM ClassReader for the class * @return whether the class qualifies as a candidate component */ protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException { for (TypeFilter tf : this.excludeFilters) { if (tf.match(metadataReader, this.metadataReaderFactory)) { return false; } } for (TypeFilter tf : this.includeFilters) { if (tf.match(metadataReader, this.metadataReaderFactory)) { AnnotationMetadata metadata = metadataReader.getAnnotationMetadata(); if (!metadata.isAnnotated(Profile.class.getName())) { return true; } AnnotationAttributes profile = MetadataUtils.attributesFor(metadata, Profile.class); return this.environment.acceptsProfiles(profile.getStringArray("value")); } } return false; }
/** * Check whether the given bean definition is a candidate for a configuration class, and mark it * accordingly. * * @param beanDef the bean definition to check * @param metadataReaderFactory the current factory in use by the caller * @return whether the candidate qualifies as (any kind of) configuration class */ public static boolean checkConfigurationClassCandidate( BeanDefinition beanDef, MetadataReaderFactory metadataReaderFactory) { AnnotationMetadata metadata = null; // Check already loaded Class if present... // since we possibly can't even load the class file for this Class. if (beanDef instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) beanDef).hasBeanClass()) { metadata = new StandardAnnotationMetadata(((AbstractBeanDefinition) beanDef).getBeanClass()); } else { String className = beanDef.getBeanClassName(); if (className != null) { try { MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(className); metadata = metadataReader.getAnnotationMetadata(); } catch (IOException ex) { if (logger.isDebugEnabled()) { logger.debug( "Could not find class file for introspecting factory methods: " + className, ex); } return false; } } } if (metadata != null) { if (metadata.isAnnotated(Configuration.class.getName())) { beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL); return true; } else if (metadata.isAnnotated(Component.class.getName()) || metadata.hasAnnotatedMethods(Bean.class.getName())) { beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE); return true; } } return false; }
protected void doProcessConfigurationClass( ConfigurationClass configClass, AnnotationMetadata metadata) throws IOException { // recursively process any member (nested) classes first for (String memberClassName : metadata.getMemberClassNames()) { MetadataReader reader = this.metadataReaderFactory.getMetadataReader(memberClassName); AnnotationMetadata memberClassMetadata = reader.getAnnotationMetadata(); if (isConfigurationCandidate(memberClassMetadata)) { processConfigurationClass(new ConfigurationClass(reader, null)); } } // process any @PropertySource annotations Map<String, Object> propertySourceAttributes = metadata.getAnnotationAttributes( org.springframework.context.annotation.PropertySource.class.getName()); if (propertySourceAttributes != null) { String name = (String) propertySourceAttributes.get("name"); String[] locations = (String[]) propertySourceAttributes.get("value"); ClassLoader classLoader = this.resourceLoader.getClassLoader(); for (String location : locations) { location = this.environment.resolveRequiredPlaceholders(location); ResourcePropertySource ps = StringUtils.hasText(name) ? new ResourcePropertySource(name, location, classLoader) : new ResourcePropertySource(location, classLoader); this.propertySources.push(ps); } } // process any @ComponentScan annotions Map<String, Object> componentScanAttributes = metadata.getAnnotationAttributes(ComponentScan.class.getName()); if (componentScanAttributes != null) { // the config class is annotated with @ComponentScan -> perform the scan immediately Set<BeanDefinitionHolder> scannedBeanDefinitions = this.componentScanParser.parse(componentScanAttributes); // check the set of scanned definitions for any further config classes and parse recursively // if necessary for (BeanDefinitionHolder holder : scannedBeanDefinitions) { if (ConfigurationClassUtils.checkConfigurationClassCandidate( holder.getBeanDefinition(), metadataReaderFactory)) { try { this.parse(holder.getBeanDefinition().getBeanClassName(), holder.getBeanName()); } catch (ConflictingBeanDefinitionException ex) { throw new CircularComponentScanException( "A conflicting bean definition was detected while processing @ComponentScan annotations. " + "This usually indicates a circle between scanned packages.", ex); } } } } // process any @Import annotations List<Map<String, Object>> allImportAttribs = AnnotationUtils.findAllAnnotationAttributes(Import.class, metadata.getClassName(), true); for (Map<String, Object> importAttribs : allImportAttribs) { processImport(configClass, (String[]) importAttribs.get("value"), true); } // process any @ImportResource annotations if (metadata.isAnnotated(ImportResource.class.getName())) { String[] resources = (String[]) metadata.getAnnotationAttributes(ImportResource.class.getName()).get("value"); Class<?> readerClass = (Class<?>) metadata.getAnnotationAttributes(ImportResource.class.getName()).get("reader"); if (readerClass == null) { throw new IllegalStateException( "No reader class associated with imported resources: " + StringUtils.arrayToCommaDelimitedString(resources)); } for (String resource : resources) { configClass.addImportedResource(resource, readerClass); } } // process individual @Bean methods Set<MethodMetadata> beanMethods = metadata.getAnnotatedMethods(Bean.class.getName()); for (MethodMetadata methodMetadata : beanMethods) { configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass)); } }