From b4954780aaa7d36e00826b86b269fa60173e901f Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Fri, 30 May 2014 18:14:36 +0200 Subject: [PATCH] ClassMetadata exposes isAnnotation() now, and correctly returns false from hasSuperClass() for interfaces and annotations Issue: SPR-11711 --- .../core/type/ClassMetadata.java | 9 +- .../core/type/StandardClassMetadata.java | 7 +- .../ClassMetadataReadingVisitor.java | 12 +- .../core/type/AnnotationMetadataTests.java | 111 ++++++++++++++---- 4 files changed, 112 insertions(+), 27 deletions(-) diff --git a/spring-core/src/main/java/org/springframework/core/type/ClassMetadata.java b/spring-core/src/main/java/org/springframework/core/type/ClassMetadata.java index 3f64971310..d664198e7d 100644 --- a/spring-core/src/main/java/org/springframework/core/type/ClassMetadata.java +++ b/spring-core/src/main/java/org/springframework/core/type/ClassMetadata.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * 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. @@ -38,6 +38,12 @@ public interface ClassMetadata { */ boolean isInterface(); + /** + * Return whether the underlying class represents an annotation. + * @since 4.1 + */ + boolean isAnnotation(); + /** * Return whether the underlying class is marked as abstract. */ @@ -100,6 +106,7 @@ public interface ClassMetadata { * access, and private classes and interfaces declared by the class, but excludes * inherited classes and interfaces. An empty array is returned if no member classes * or interfaces exist. + * @since 3.1 */ String[] getMemberClassNames(); diff --git a/spring-core/src/main/java/org/springframework/core/type/StandardClassMetadata.java b/spring-core/src/main/java/org/springframework/core/type/StandardClassMetadata.java index 1c56f4ff8a..935184b0c5 100644 --- a/spring-core/src/main/java/org/springframework/core/type/StandardClassMetadata.java +++ b/spring-core/src/main/java/org/springframework/core/type/StandardClassMetadata.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * 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. @@ -60,6 +60,11 @@ public class StandardClassMetadata implements ClassMetadata { return this.introspectedClass.isInterface(); } + @Override + public boolean isAnnotation() { + return this.introspectedClass.isAnnotation(); + } + @Override public boolean isAbstract() { return Modifier.isAbstract(this.introspectedClass.getModifiers()); diff --git a/spring-core/src/main/java/org/springframework/core/type/classreading/ClassMetadataReadingVisitor.java b/spring-core/src/main/java/org/springframework/core/type/classreading/ClassMetadataReadingVisitor.java index 0d78fc2737..b0caadf533 100644 --- a/spring-core/src/main/java/org/springframework/core/type/classreading/ClassMetadataReadingVisitor.java +++ b/spring-core/src/main/java/org/springframework/core/type/classreading/ClassMetadataReadingVisitor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * 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. @@ -47,6 +47,8 @@ class ClassMetadataReadingVisitor extends ClassVisitor implements ClassMetadata private boolean isInterface; + private boolean isAnnotation; + private boolean isAbstract; private boolean isFinal; @@ -71,9 +73,10 @@ class ClassMetadataReadingVisitor extends ClassVisitor implements ClassMetadata public void visit(int version, int access, String name, String signature, String supername, String[] interfaces) { this.className = ClassUtils.convertResourcePathToClassName(name); this.isInterface = ((access & Opcodes.ACC_INTERFACE) != 0); + this.isAnnotation = ((access & Opcodes.ACC_ANNOTATION) != 0); this.isAbstract = ((access & Opcodes.ACC_ABSTRACT) != 0); this.isFinal = ((access & Opcodes.ACC_FINAL) != 0); - if (supername != null) { + if (supername != null && !this.isInterface) { this.superClassName = ClassUtils.convertResourcePathToClassName(supername); } this.interfaces = new String[interfaces.length]; @@ -146,6 +149,11 @@ class ClassMetadataReadingVisitor extends ClassVisitor implements ClassMetadata return this.isInterface; } + @Override + public boolean isAnnotation() { + return this.isAnnotation; + } + @Override public boolean isAbstract() { return this.isAbstract; diff --git a/spring-core/src/test/java/org/springframework/core/type/AnnotationMetadataTests.java b/spring-core/src/test/java/org/springframework/core/type/AnnotationMetadataTests.java index bfd89f5ba6..92ebc8735c 100644 --- a/spring-core/src/test/java/org/springframework/core/type/AnnotationMetadataTests.java +++ b/spring-core/src/test/java/org/springframework/core/type/AnnotationMetadataTests.java @@ -18,6 +18,7 @@ package org.springframework.core.type; import java.io.Serializable; import java.lang.annotation.Annotation; +import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -79,6 +80,89 @@ public class AnnotationMetadataTests { doTestSubClassAnnotationInfo(metadata); } + private void doTestSubClassAnnotationInfo(AnnotationMetadata metadata) { + assertThat(metadata.getClassName(), is(AnnotatedComponentSubClass.class.getName())); + assertThat(metadata.isInterface(), is(false)); + assertThat(metadata.isAnnotation(), is(false)); + assertThat(metadata.isAbstract(), is(false)); + assertThat(metadata.isConcrete(), is(true)); + assertThat(metadata.hasSuperClass(), is(true)); + assertThat(metadata.getSuperClassName(), is(AnnotatedComponent.class.getName())); + assertThat(metadata.getInterfaceNames().length, is(0)); + assertThat(metadata.isAnnotated(Component.class.getName()), is(false)); + assertThat(metadata.isAnnotated(Scope.class.getName()), is(false)); + assertThat(metadata.isAnnotated(SpecialAttr.class.getName()), is(false)); + assertThat(metadata.hasAnnotation(Component.class.getName()), is(false)); + assertThat(metadata.hasAnnotation(Scope.class.getName()), is(false)); + assertThat(metadata.hasAnnotation(SpecialAttr.class.getName()), is(false)); + assertThat(metadata.getAnnotationTypes().size(), is(0)); + assertThat(metadata.getAnnotationAttributes(Component.class.getName()), nullValue()); + assertThat(metadata.getAnnotatedMethods(DirectAnnotation.class.getName()).size(), equalTo(0)); + assertThat(metadata.isAnnotated(IsAnnotatedAnnotation.class.getName()), equalTo(false)); + assertThat(metadata.getAllAnnotationAttributes(DirectAnnotation.class.getName()), nullValue()); + } + + @Test + public void standardAnnotationMetadataForInterface() throws Exception { + AnnotationMetadata metadata = new StandardAnnotationMetadata(AnnotationMetadata.class, true); + doTestMetadataForInterfaceClass(metadata); + } + + @Test + public void asmAnnotationMetadataForInterface() throws Exception { + MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory(); + MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(AnnotationMetadata.class.getName()); + AnnotationMetadata metadata = metadataReader.getAnnotationMetadata(); + doTestMetadataForInterfaceClass(metadata); + } + + private void doTestMetadataForInterfaceClass(AnnotationMetadata metadata) { + assertThat(metadata.getClassName(), is(AnnotationMetadata.class.getName())); + assertThat(metadata.isInterface(), is(true)); + assertThat(metadata.isAnnotation(), is(false)); + assertThat(metadata.isAbstract(), is(true)); + assertThat(metadata.isConcrete(), is(false)); + assertThat(metadata.hasSuperClass(), is(false)); + assertThat(metadata.getSuperClassName(), nullValue()); + assertThat(metadata.getInterfaceNames().length, is(2)); + assertThat(metadata.getInterfaceNames()[0], is(ClassMetadata.class.getName())); + assertThat(metadata.getInterfaceNames()[1], is(AnnotatedTypeMetadata.class.getName())); + assertThat(metadata.getAnnotationTypes().size(), is(0)); + } + + @Test + public void standardAnnotationMetadataForAnnotation() throws Exception { + AnnotationMetadata metadata = new StandardAnnotationMetadata(Component.class, true); + doTestMetadataForAnnotationClass(metadata); + } + + @Test + public void asmAnnotationMetadataForAnnotation() throws Exception { + MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory(); + MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(Component.class.getName()); + AnnotationMetadata metadata = metadataReader.getAnnotationMetadata(); + doTestMetadataForAnnotationClass(metadata); + } + + private void doTestMetadataForAnnotationClass(AnnotationMetadata metadata) { + assertThat(metadata.getClassName(), is(Component.class.getName())); + assertThat(metadata.isInterface(), is(true)); + assertThat(metadata.isAnnotation(), is(true)); + assertThat(metadata.isAbstract(), is(true)); + assertThat(metadata.isConcrete(), is(false)); + assertThat(metadata.hasSuperClass(), is(false)); + assertThat(metadata.getSuperClassName(), nullValue()); + assertThat(metadata.getInterfaceNames().length, is(1)); + assertThat(metadata.getInterfaceNames()[0], is(Annotation.class.getName())); + assertThat(metadata.isAnnotated(Documented.class.getName()), is(true)); + assertThat(metadata.isAnnotated(Scope.class.getName()), is(false)); + assertThat(metadata.isAnnotated(SpecialAttr.class.getName()), is(false)); + assertThat(metadata.hasAnnotation(Documented.class.getName()), is(true)); + assertThat(metadata.hasAnnotation(Scope.class.getName()), is(false)); + assertThat(metadata.hasAnnotation(SpecialAttr.class.getName()), is(false)); + assertThat(metadata.getAnnotationTypes().size(), is(3)); + } + /** * In order to preserve backward-compatibility, {@link StandardAnnotationMetadata} * defaults to return nested annotations and annotation arrays as actual @@ -89,7 +173,6 @@ public class AnnotationMetadataTests { @Test public void standardAnnotationMetadata_nestedAnnotationsAsMap_false() throws Exception { AnnotationMetadata metadata = new StandardAnnotationMetadata(AnnotatedComponent.class); - AnnotationAttributes specialAttrs = (AnnotationAttributes) metadata.getAnnotationAttributes(SpecialAttr.class.getName()); Annotation[] nestedAnnoArray = (Annotation[]) specialAttrs.get("nestedAnnoArray"); assertThat(nestedAnnoArray[0], instanceOf(NestedAnno.class)); @@ -97,9 +180,7 @@ public class AnnotationMetadataTests { @Test public void metaAnnotationOverridesUsingStandardAnnotationMetadata() { - AnnotationMetadata metadata = new StandardAnnotationMetadata( - ComposedConfigurationWithAttributeOverridesClass.class); - + AnnotationMetadata metadata = new StandardAnnotationMetadata(ComposedConfigurationWithAttributeOverridesClass.class); assertMetaAnnotationOverrides(metadata); } @@ -108,7 +189,6 @@ public class AnnotationMetadataTests { MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory(); MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(ComposedConfigurationWithAttributeOverridesClass.class.getName()); AnnotationMetadata metadata = metadataReader.getAnnotationMetadata(); - assertMetaAnnotationOverrides(metadata); } @@ -184,6 +264,7 @@ public class AnnotationMetadataTests { private void doTestAnnotationInfo(AnnotationMetadata metadata) { assertThat(metadata.getClassName(), is(AnnotatedComponent.class.getName())); assertThat(metadata.isInterface(), is(false)); + assertThat(metadata.isAnnotation(), is(false)); assertThat(metadata.isAbstract(), is(false)); assertThat(metadata.isConcrete(), is(true)); assertThat(metadata.hasSuperClass(), is(true)); @@ -283,21 +364,6 @@ public class AnnotationMetadataTests { } } - private void doTestSubClassAnnotationInfo(AnnotationMetadata metadata) { - assertThat(metadata.getClassName(), is(AnnotatedComponentSubClass.class.getName())); - assertThat(metadata.isAnnotated(Component.class.getName()), is(false)); - assertThat(metadata.isAnnotated(Scope.class.getName()), is(false)); - assertThat(metadata.isAnnotated(SpecialAttr.class.getName()), is(false)); - assertThat(metadata.hasAnnotation(Component.class.getName()), is(false)); - assertThat(metadata.hasAnnotation(Scope.class.getName()), is(false)); - assertThat(metadata.hasAnnotation(SpecialAttr.class.getName()), is(false)); - assertThat(metadata.getAnnotationTypes().size(), is(0)); - assertThat(metadata.getAnnotationAttributes(Component.class.getName()), nullValue()); - assertThat(metadata.getAnnotatedMethods(DirectAnnotation.class.getName()).size(), equalTo(0)); - assertThat(metadata.isAnnotated(IsAnnotatedAnnotation.class.getName()), equalTo(false)); - assertThat(metadata.getAllAnnotationAttributes(DirectAnnotation.class.getName()), nullValue()); - } - private void doTestMethodAnnotationInfo(AnnotationMetadata classMetadata) { Set methods = classMetadata.getAnnotatedMethods(TestAutowired.class.getName()); assertThat(methods.size(), is(1)); @@ -310,7 +376,7 @@ public class AnnotationMetadataTests { // ------------------------------------------------------------------------- public static enum SomeEnum { - LABEL1, LABEL2, DEFAULT; + LABEL1, LABEL2, DEFAULT } @Target({}) @@ -406,9 +472,8 @@ public class AnnotationMetadataTests { } } - @SuppressWarnings({ "serial" }) + @SuppressWarnings("serial") private static class AnnotatedComponentSubClass extends AnnotatedComponent { - } @Target(ElementType.TYPE)