package spoon.test.annotation;
import org.junit.Before;
import org.junit.Test;
import spoon.Launcher;
import spoon.OutputType;
import spoon.processing.AbstractAnnotationProcessor;
import spoon.processing.ProcessingManager;
import spoon.reflect.code.CtBlock;
import spoon.reflect.code.CtConstructorCall;
import spoon.reflect.code.CtExpression;
import spoon.reflect.code.CtLiteral;
import spoon.reflect.code.CtLocalVariable;
import spoon.reflect.code.CtNewArray;
import spoon.reflect.code.CtReturn;
import spoon.reflect.code.CtStatement;
import spoon.reflect.declaration.CtAnnotatedElementType;
import spoon.reflect.declaration.CtAnnotation;
import spoon.reflect.declaration.CtAnnotationMethod;
import spoon.reflect.declaration.CtAnnotationType;
import spoon.reflect.declaration.CtClass;
import spoon.reflect.declaration.CtConstructor;
import spoon.reflect.declaration.CtElement;
import spoon.reflect.declaration.CtEnum;
import spoon.reflect.declaration.CtEnumValue;
import spoon.reflect.declaration.CtField;
import spoon.reflect.declaration.CtInterface;
import spoon.reflect.declaration.CtMethod;
import spoon.reflect.declaration.CtPackage;
import spoon.reflect.declaration.CtParameter;
import spoon.reflect.declaration.CtType;
import spoon.reflect.declaration.CtTypeParameter;
import spoon.reflect.factory.Factory;
import spoon.reflect.reference.CtTypeReference;
import spoon.reflect.visitor.DefaultJavaPrettyPrinter;
import spoon.reflect.visitor.PrettyPrinter;
import spoon.reflect.visitor.filter.AbstractFilter;
import spoon.reflect.visitor.filter.NameFilter;
import spoon.reflect.visitor.filter.TypeFilter;
import spoon.support.QueueProcessingManager;
import spoon.test.annotation.testclasses.AnnotArray;
import spoon.test.annotation.testclasses.AnnotParamTypeEnum;
import spoon.test.annotation.testclasses.AnnotParamTypes;
import spoon.test.annotation.testclasses.AnnotationDefaultAnnotation;
import spoon.test.annotation.testclasses.AnnotationIntrospection;
import spoon.test.annotation.testclasses.AnnotationRepeated;
import spoon.test.annotation.testclasses.AnnotationsAppliedOnAnyTypeInAClass;
import spoon.test.annotation.testclasses.AnnotationsRepeated;
import spoon.test.annotation.testclasses.Bound;
import spoon.test.annotation.testclasses.Foo;
import spoon.test.annotation.testclasses.Foo.InnerAnnotation;
import spoon.test.annotation.testclasses.Foo.MiddleAnnotation;
import spoon.test.annotation.testclasses.Foo.OuterAnnotation;
import spoon.test.annotation.testclasses.GlobalAnnotation;
import spoon.test.annotation.testclasses.InnerAnnot;
import spoon.test.annotation.testclasses.Main;
import spoon.test.annotation.testclasses.SuperAnnotation;
import spoon.test.annotation.testclasses.TestInterface;
import spoon.test.annotation.testclasses.TypeAnnotation;
import spoon.test.annotation.testclasses.PortRange;
import java.io.File;
import java.lang.annotation.Annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static spoon.testing.utils.ModelUtils.buildClass;
import static spoon.testing.utils.ModelUtils.canBeBuilt;
public class AnnotationTest {
private Launcher launcher;
private Factory factory;
@Before
public void setUp() throws Exception {
launcher = new Launcher();
launcher.run(new String[] {
"-i", "./src/test/java/spoon/test/annotation/testclasses/",
"--output-type", "nooutput"
});
factory = launcher.getFactory();
}
@Test
public void testModelBuildingAnnotationBound() throws Exception {
CtType<?> type = this.factory.Type().get("spoon.test.annotation.testclasses.Bound");
assertEquals("Bound", type.getSimpleName());
assertEquals(1, type.getAnnotations().size());
}
@Test
public void testWritingAnnotParamArray() throws Exception {
CtType<?> type = this.factory.Type().get("spoon.test.annotation.testclasses.AnnotParam");
assertEquals("@java.lang.SuppressWarnings(value = { \"unused\" , \"rawtypes\" })"
+ DefaultJavaPrettyPrinter.LINE_SEPARATOR,
type.getElements(new TypeFilter<>(CtAnnotation.class)).get(0).toString());
}
@Test
public void testModelBuildingAnnotationBoundUsage() throws Exception {
CtType<?> type = this.factory.Type().get("spoon.test.annotation.testclasses.Main");
assertEquals("Main", type.getSimpleName());
CtParameter<?> param = type.getElements(new TypeFilter<CtParameter<?>>(CtParameter.class)).get(0);
assertEquals("a", param.getSimpleName());
List<CtAnnotation<? extends Annotation>> annotations = param.getAnnotations();
assertEquals(1, annotations.size());
CtAnnotation<?> a = annotations.get(0);
Bound actualAnnotation = (Bound) a.getActualAnnotation();
assertEquals(8, actualAnnotation.max());
}
@Test
public void testPersistenceProperty() throws Exception {
CtType<?> type = this.factory.Type().get("spoon.test.annotation.testclasses.PersistenceProperty");
assertEquals("PersistenceProperty", type.getSimpleName());
assertEquals(2, type.getAnnotations().size());
CtAnnotation<Target> a1 = type.getAnnotation(type.getFactory().Type().createReference(Target.class));
assertNotNull(a1);
CtAnnotation<Retention> a2 = type.getAnnotation(type.getFactory().Type().createReference(Retention.class));
assertNotNull(a2);
assertTrue(a1.getValues().containsKey("value"));
assertTrue(a2.getValues().containsKey("value"));
}
@Test
public void testAnnotationParameterTypes() throws Exception {
CtType<?> type = this.factory.Type().get("spoon.test.annotation.testclasses.Main");
CtMethod<?> m1 = type.getElements(new NameFilter<CtMethod<?>>("m1")).get(0);
List<CtAnnotation<? extends Annotation>> annotations = m1.getAnnotations();
assertEquals(1, annotations.size());
CtAnnotation<?> a = annotations.get(0);
AnnotParamTypes annot = (AnnotParamTypes) a.getActualAnnotation();
assertEquals(42, annot.integer());
assertEquals(1, annot.integers().length);
assertEquals(42, annot.integers()[0]);
assertEquals("Hello World!", annot.string());
assertEquals(2, annot.strings().length);
assertEquals("Hello", annot.strings()[0]);
assertEquals("World", annot.strings()[1]);
assertEquals(Integer.class, annot.clazz());
assertEquals(2, annot.classes().length);
assertEquals(Integer.class, annot.classes()[0]);
assertEquals(String.class, annot.classes()[1]);
assertEquals(true, annot.b());
assertEquals('c', annot.c());
assertEquals(42, annot.byt());
assertEquals((short) 42, annot.s());
assertEquals(42, annot.l());
assertEquals(3.14f, annot.f(), 0f);
assertEquals(3.14159, annot.d(), 0);
assertEquals(AnnotParamTypeEnum.G, annot.e());
assertEquals("dd", annot.ia().value());
CtMethod<?> m2 = type.getElements(new NameFilter<CtMethod<?>>("m2")).get(0);
annotations = m2.getAnnotations();
assertEquals(1, annotations.size());
a = annotations.get(0);
annot = (AnnotParamTypes) a.getActualAnnotation();
assertEquals(42, annot.integer());
assertEquals(1, annot.integers().length);
assertEquals(42, annot.integers()[0]);
assertEquals("Hello World!", annot.string());
assertEquals(2, annot.strings().length);
assertEquals("Hello", annot.strings()[0]);
assertEquals("world", annot.strings()[1]);
assertEquals(false, annot.b());
assertEquals(42, annot.byt());
assertEquals((short) 42, annot.s());
assertEquals(42, annot.l());
assertEquals(3.14f, annot.f(), 0f);
assertEquals(3.14159, annot.d(), 0);
assertEquals(AnnotParamTypeEnum.G, annot.e());
assertEquals("dd", annot.ia().value());
// tests binary expressions
CtMethod<?> m3 = type.getElements(new NameFilter<CtMethod<?>>("m3")).get(0);
annotations = m3.getAnnotations();
assertEquals(1, annotations.size());
a = annotations.get(0);
annot = (AnnotParamTypes) a.getActualAnnotation();
assertEquals(45, annot.integer());
assertEquals(2, annot.integers().length);
assertEquals(40, annot.integers()[0]);
assertEquals(42 * 3, annot.integers()[1]);
assertEquals("Hello World!concatenated", annot.string());
assertEquals(2, annot.strings().length);
assertEquals("Helloconcatenated", annot.strings()[0]);
assertEquals("worldconcatenated", annot.strings()[1]);
assertEquals(true, annot.b());
assertEquals(42 ^ 1, annot.byt());
assertEquals((short) 42 / 2, annot.s());
assertEquals(43, annot.l());
assertEquals(3.14f * 2f, annot.f(), 0f);
assertEquals(3.14159d / 3d, annot.d(), 0);
assertEquals(AnnotParamTypeEnum.G, annot.e());
assertEquals("dddd", annot.ia().value());
}
@Test
public void testAnnotatedElementTypes() throws Exception {
// load package of the test classes
CtPackage pkg = this.factory.Package().get("spoon.test.annotation.testclasses");
// check annotated element type of the package annotation
List<CtAnnotation<?>> annotations = pkg.getAnnotations();
assertEquals(2, annotations.size());
assertTrue(annotations.get(0).getAnnotatedElement().equals(pkg));
assertEquals(CtAnnotatedElementType.PACKAGE, annotations.get(0).getAnnotatedElementType());
// load class Main from package and check annotated element type of the class annotation
CtClass<?> clazz = pkg.getType("Main");
assertEquals(Main.class, clazz.getActualClass());
annotations = clazz.getAnnotations();
assertEquals(1, annotations.size());
assertTrue(annotations.get(0).getAnnotatedElement().equals(clazz));
assertEquals(CtAnnotatedElementType.TYPE, clazz.getAnnotations().get(0).getAnnotatedElementType());
// load method toString() from class and check annotated element type of the annotation
List<CtMethod<?>> methods = clazz.getMethodsByName("toString");
assertEquals(1, methods.size());
CtMethod<?> method = methods.get(0);
assertEquals("toString", method.getSimpleName());
annotations = method.getAnnotations();
assertEquals(1, annotations.size());
assertTrue(annotations.get(0).getAnnotatedElement().equals(method));
assertEquals(CtAnnotatedElementType.METHOD, annotations.get(0).getAnnotatedElementType());
// load parameter of method m(int) and check annotated element type of the parameter annotation
methods = clazz.getMethodsByName("m");
assertEquals(1, methods.size());
method = methods.get(0);
assertEquals("m", method.getSimpleName());
List<CtParameter<?>> parameters = method.getParameters();
assertEquals(1, parameters.size());
CtParameter<?> parameter = parameters.get(0);
annotations = parameter.getAnnotations();
assertEquals(1, annotations.size());
assertTrue(annotations.get(0).getAnnotatedElement().equals(parameter));
assertEquals(CtAnnotatedElementType.PARAMETER, annotations.get(0).getAnnotatedElementType());
// load constructor of the clazz and check annotated element type of the constructor annotation
Set<? extends CtConstructor<?>> constructors = clazz.getConstructors();
assertEquals(1, constructors.size());
CtConstructor<?> constructor = constructors.iterator().next();
annotations = constructor.getAnnotations();
assertEquals(1, annotations.size());
assertTrue(annotations.get(0).getAnnotatedElement().equals(constructor));
assertEquals(CtAnnotatedElementType.CONSTRUCTOR, annotations.get(0).getAnnotatedElementType());
// load value ia of the m1() method annotation, which is also an annotation
// and check the annotated element type of the inner annotation.
methods = clazz.getMethodsByName("m1");
assertEquals(1, methods.size());
method = methods.get(0);
annotations = method.getAnnotations();
assertEquals(1, annotations.size());
CtAnnotation<?> annotation = annotations.get(0);
assertTrue(annotations.get(0).getAnnotatedElement().equals(method));
assertEquals(CtAnnotatedElementType.METHOD, annotations.get(0).getAnnotatedElementType());
Object element = annotation.getValues().get("ia");
assertNotNull(element);
assertTrue(element instanceof CtAnnotation);
assertTrue(((CtAnnotation<?>) element).getAnnotatedElement().equals(annotation));
assertEquals(CtAnnotatedElementType.ANNOTATION_TYPE, ((CtAnnotation<?>) element).getAnnotatedElementType());
// load enum AnnotParamTypeEnum and check the annotated element type of the annotation of the enum and of the fields
CtEnum<?> enumeration = pkg.getType("AnnotParamTypeEnum");
assertEquals(AnnotParamTypeEnum.class, enumeration.getActualClass());
annotations = enumeration.getAnnotations();
assertEquals(1, annotations.size());
assertTrue(annotations.get(0).getAnnotatedElement().equals(enumeration));
assertEquals(CtAnnotatedElementType.TYPE, annotations.get(0).getAnnotatedElementType());
List<CtEnumValue<?>> fields = enumeration.getEnumValues();
assertEquals(3, fields.size());
annotations = fields.get(0).getAnnotations();
assertEquals(1, annotations.size());
assertTrue(annotations.get(0).getAnnotatedElement().equals(fields.get(0)));
assertEquals(CtAnnotatedElementType.FIELD, annotations.get(0).getAnnotatedElementType());
// load interface type TestInterface and check the annotated element type of the annotation
CtInterface<?> ctInterface = pkg.getType("TestInterface");
assertEquals(TestInterface.class, ctInterface.getActualClass());
annotations = ctInterface.getAnnotations();
assertEquals(1, annotations.size());
assertTrue(annotations.get(0).getAnnotatedElement().equals(ctInterface));
assertEquals(CtAnnotatedElementType.TYPE, annotations.get(0).getAnnotatedElementType());
// load annotation type Bound and check the annotated element type of the annotations
CtAnnotationType<?> annotationType = pkg.getType("Bound");
assertEquals(Bound.class, annotationType.getActualClass());
assertNull(annotationType.getSuperclass());
assertEquals(1, annotationType.getMethods().size());
assertEquals(0,annotationType.getSuperInterfaces().size());
annotations = annotationType.getAnnotations();
assertEquals(1, annotations.size());
assertTrue(annotations.get(0).getAnnotatedElement().equals(annotationType));
assertEquals(CtAnnotatedElementType.ANNOTATION_TYPE, annotations.get(0).getAnnotatedElementType());
}
@Test
public void testAnnotationWithDefaultArrayValue() throws Throwable {
final String res = "java.lang.Class<?>[] value() default { };";
CtType<?> type = this.factory.Type().get("spoon.test.annotation.testclasses.AnnotArrayInnerClass");
CtType<?> annotationInnerClass = type.getNestedType("Annotation");
assertEquals("Annotation", annotationInnerClass.getSimpleName());
assertEquals(1, annotationInnerClass.getAnnotations().size());
assertEquals(res, annotationInnerClass.getMethod("value").toString());
CtType<?> annotation = this.factory.Type().get("spoon.test.annotation.testclasses.AnnotArray");
assertEquals("AnnotArray", annotation.getSimpleName());
assertEquals(1, annotation.getAnnotations().size());
assertEquals(res, annotation.getMethod("value").toString());
}
@Test
public void testInnerAnnotationsWithArray() throws Exception {
final CtClass<?> ctClass = (CtClass<?>) this.factory.Type().get("spoon.test.annotation.testclasses.Foo");
final CtMethod<?> testMethod = ctClass.getMethodsByName("test").get(0);
final List<CtAnnotation<? extends Annotation>> testMethodAnnotations = testMethod.getAnnotations();
assertEquals(1, testMethodAnnotations.size());
final CtAnnotation<? extends Annotation> firstAnnotation = testMethodAnnotations.get(0);
assertEquals(OuterAnnotation.class, getActualClassFromAnnotation(firstAnnotation));
final CtNewArray<?> arrayAnnotations = (CtNewArray<?>) firstAnnotation.getValues().get("value");
assertEquals(2, arrayAnnotations.getElements().size());
final CtAnnotation<?> firstAnnotationInArray = getMiddleAnnotation(arrayAnnotations, 0);
assertEquals(MiddleAnnotation.class, getActualClassFromAnnotation(firstAnnotationInArray));
final CtAnnotation<?> secondAnnotationInArray = getMiddleAnnotation(arrayAnnotations, 1);
assertEquals(MiddleAnnotation.class, getActualClassFromAnnotation(secondAnnotationInArray));
final CtAnnotation<?> innerAnnotationInFirstMiddleAnnotation = getInnerAnnotation(firstAnnotationInArray);
assertEquals(InnerAnnotation.class, getActualClassFromAnnotation(innerAnnotationInFirstMiddleAnnotation));
assertEquals("hello", getLiteralValueInAnnotation(innerAnnotationInFirstMiddleAnnotation).getValue());
final CtAnnotation<?> innerAnnotationInSecondMiddleAnnotation = getInnerAnnotation(secondAnnotationInArray);
assertEquals(InnerAnnotation.class, getActualClassFromAnnotation(innerAnnotationInSecondMiddleAnnotation));
assertEquals("hello again", getLiteralValueInAnnotation(innerAnnotationInSecondMiddleAnnotation).getValue());
}
@Test
public void testAccessAnnotationValue() throws Exception {
final CtClass<?> ctClass = (CtClass<?>) this.factory.Type().get("spoon.test.annotation.testclasses.Main");
CtMethod<?> testMethod = ctClass.getMethodsByName("testValueWithArray").get(0);
Class<?>[] value = testMethod.getAnnotation(AnnotArray.class).value();
assertArrayEquals(new Class[] { RuntimeException.class }, value);
testMethod = ctClass.getMethodsByName("testValueWithoutArray").get(0);
value = testMethod.getAnnotation(AnnotArray.class).value();
assertArrayEquals(new Class[] { RuntimeException.class }, value);
}
@Test
public void testUsageOfTypeAnnotationInNewInstance() throws Exception {
final CtClass<?> ctClass = (CtClass<?>) this.factory.Type().get("spoon.test.annotation.testclasses.AnnotationsAppliedOnAnyTypeInAClass");
final CtConstructorCall<?> ctConstructorCall = ctClass.getElements(new AbstractFilter<CtConstructorCall<?>>(CtConstructorCall.class) {
@Override
public boolean matches(CtConstructorCall<?> element) {
return "String".equals(element.getType().getSimpleName());
}
}).get(0);
final List<CtAnnotation<? extends Annotation>> typeAnnotations = ctConstructorCall.getType().getAnnotations();
assertEquals("Type of the new class must use an annotation", 1, typeAnnotations.size());
assertEquals("Type of the new class is typed by TypeAnnotation", TypeAnnotation.class, typeAnnotations.get(0).getAnnotationType().getActualClass());
assertEquals(CtAnnotatedElementType.TYPE_USE, typeAnnotations.get(0).getAnnotatedElementType());
assertEquals("New class with an type annotation must be well printed", "new java.lang.@spoon.test.annotation.testclasses.TypeAnnotation" + System.lineSeparator() + "String()", ctConstructorCall.toString());
}
@Test
public void testUsageOfTypeAnnotationInCast() throws Exception {
final CtClass<?> ctClass = (CtClass<?>) this.factory.Type().get("spoon.test.annotation.testclasses.AnnotationsAppliedOnAnyTypeInAClass");
final CtReturn<?> returns = ctClass.getElements(new AbstractFilter<CtReturn<?>>(CtReturn.class) {
@Override
public boolean matches(CtReturn<?> element) {
return !element.getReturnedExpression().getTypeCasts().isEmpty();
}
}).get(0);
final CtExpression<?> returnedExpression = returns.getReturnedExpression();
final List<CtAnnotation<? extends Annotation>> typeAnnotations = returnedExpression.getTypeCasts().get(0).getAnnotations();
assertEquals("Cast with a type annotation must have it in its model", 1, typeAnnotations.size());
assertEquals("Type annotation in the cast must be typed by TypeAnnotation", TypeAnnotation.class, typeAnnotations.get(0).getAnnotationType().getActualClass());
assertEquals(CtAnnotatedElementType.TYPE_USE, typeAnnotations.get(0).getAnnotatedElementType());
assertEquals("Cast with an type annotation must be well printed", "((java.lang.@spoon.test.annotation.testclasses.TypeAnnotation" + System.lineSeparator() + "String) (s))", returnedExpression.toString());
}
@Test
public void testUsageOfTypeAnnotationBeforeExceptionInSignatureOfMethod() throws Exception {
final CtClass<?> ctClass = (CtClass<?>) this.factory.Type().get("spoon.test.annotation.testclasses.AnnotationsAppliedOnAnyTypeInAClass");
final CtMethod<?> method = ctClass.getMethodsByName("m").get(0);
final CtTypeReference<?> thrownReference = method.getThrownTypes().toArray(new CtTypeReference<?>[0])[0];
final List<CtAnnotation<? extends Annotation>> typeAnnotations = thrownReference.getAnnotations();
assertEquals("Thrown type with a type annotation must have it in its model", 1, typeAnnotations.size());
assertEquals("Type annotation with the thrown type must be typed by TypeAnnotation", TypeAnnotation.class, typeAnnotations.get(0).getAnnotationType().getActualClass());
assertEquals(CtAnnotatedElementType.TYPE_USE, typeAnnotations.get(0).getAnnotatedElementType());
assertEquals("Thrown type with an type annotation must be well printed", "public void m() throws java.lang.@spoon.test.annotation.testclasses.TypeAnnotation" + System.lineSeparator() + "Exception {"
+ System.lineSeparator() + "}", method.toString());
}
@Test
public void testUsageOfTypeAnnotationInReturnTypeInMethod() throws Exception {
final CtClass<?> ctClass = (CtClass<?>) this.factory.Type().get("spoon.test.annotation.testclasses.AnnotationsAppliedOnAnyTypeInAClass");
final CtMethod<?> method = ctClass.getMethodsByName("m3").get(0);
final List<CtAnnotation<? extends Annotation>> typeAnnotations = method.getType().getAnnotations();
assertEquals("Return type with a type annotation must have it in its model", 1, typeAnnotations.size());
assertEquals("Type annotation with the return type must be typed by TypeAnnotation", TypeAnnotation.class, typeAnnotations.get(0).getAnnotationType().getActualClass());
assertEquals(CtAnnotatedElementType.TYPE_USE, typeAnnotations.get(0).getAnnotatedElementType());
assertEquals("Return type with an type annotation must be well printed", "public java.lang.@spoon.test.annotation.testclasses.TypeAnnotation" + System.lineSeparator() + "String m3() {"
+ System.lineSeparator()
+ " return \"\";"
+ System.lineSeparator() + "}", method.toString());
}
@Test
public void testUsageOfTypeAnnotationOnParameterInMethod() throws Exception {
final CtClass<?> ctClass = (CtClass<?>) this.factory.Type().get(AnnotationsAppliedOnAnyTypeInAClass.class);
final CtMethod<?> method = ctClass.getMethodsByName("m6").get(0);
final CtParameter<?> ctParameter = method.getParameters().get(0);
final List<CtAnnotation<? extends Annotation>> typeAnnotations = ctParameter.getType().getAnnotations();
assertEquals("Parameter type with a type annotation must have it in its model", 1, typeAnnotations.size());
assertEquals("Type annotation with the parameter type must be typed by TypeAnnotation", TypeAnnotation.class, typeAnnotations.get(0).getAnnotationType().getActualClass());
assertEquals(CtAnnotatedElementType.TYPE_USE, typeAnnotations.get(0).getAnnotatedElementType());
assertEquals("Parameter type with an type annotation must be well printed", "java.lang.@spoon.test.annotation.testclasses.TypeAnnotation" + System.lineSeparator() + "String param", ctParameter.toString());
}
@Test
public void testUsageOfTypeAnnotationOnLocalVariableInMethod() throws Exception {
final CtClass<?> ctClass = (CtClass<?>) this.factory.Type().get(AnnotationsAppliedOnAnyTypeInAClass.class);
final CtMethod<?> method = ctClass.getMethodsByName("m6").get(0);
final CtLocalVariable<?> ctLocalVariable = method.getBody().getElements(new AbstractFilter<CtLocalVariable<?>>(CtLocalVariable.class) {
@Override
public boolean matches(CtLocalVariable<?> element) {
return true;
}
}).get(0);
final List<CtAnnotation<? extends Annotation>> typeAnnotations = ctLocalVariable.getType().getAnnotations();
assertEquals("Local variable type with a type annotation must have it in its model", 1, typeAnnotations.size());
assertEquals("Type annotation with the local variable type must be typed by TypeAnnotation", TypeAnnotation.class, typeAnnotations.get(0).getAnnotationType().getActualClass());
assertEquals(CtAnnotatedElementType.TYPE_USE, typeAnnotations.get(0).getAnnotatedElementType());
assertEquals("Local variable type with an type annotation must be well printed", "java.lang.@spoon.test.annotation.testclasses.TypeAnnotation" + System.lineSeparator() + "String s = \"\"", ctLocalVariable.toString());
}
@Test
public void testUsageOfTypeAnnotationInExtendsImplementsOfAClass() throws Exception {
final CtClass<?> ctClass = (CtClass<?>) this.factory.Type().get("spoon.test.annotation.testclasses.AnnotationsAppliedOnAnyTypeInAClass");
final CtClass<?> innerClass = ctClass.getElements(new NameFilter<CtClass<?>>("DummyClass")).get(0);
final CtTypeReference<?> extendsActual = innerClass.getSuperclass();
final List<CtAnnotation<? extends Annotation>> extendsTypeAnnotations = extendsActual.getAnnotations();
final String superClassExpected = "spoon.test.annotation.testclasses.@spoon.test.annotation.testclasses.TypeAnnotation" + System.lineSeparator() + "AnnotArrayInnerClass";
assertEquals("Extends with a type annotation must have it in its model", 1, extendsTypeAnnotations.size());
assertEquals("Type annotation on a extends must be typed by TypeAnnotation", TypeAnnotation.class, extendsTypeAnnotations.get(0).getAnnotationType().getActualClass());
assertEquals(CtAnnotatedElementType.TYPE_USE, extendsTypeAnnotations.get(0).getAnnotatedElementType());
assertEquals("Extends with an type annotation must be well printed", superClassExpected, extendsActual.toString());
final Set<CtTypeReference<?>> superInterfaces = innerClass.getSuperInterfaces();
final CtTypeReference<?> firstSuperInterface = superInterfaces.toArray(new CtTypeReference<?>[0])[0];
final List<CtAnnotation<? extends Annotation>> implementsTypeAnnotations = firstSuperInterface.getAnnotations();
final String superInterfaceExpected = "spoon.test.annotation.testclasses.@spoon.test.annotation.testclasses.TypeAnnotation" + System.lineSeparator() + "BasicAnnotation";
assertEquals("Implements with a type annotation must have it in its model", 1, implementsTypeAnnotations.size());
assertEquals("Type annotation on a extends must be typed by TypeAnnotation", TypeAnnotation.class, implementsTypeAnnotations.get(0).getAnnotationType().getActualClass());
assertEquals(CtAnnotatedElementType.TYPE_USE, implementsTypeAnnotations.get(0).getAnnotatedElementType());
assertEquals("Extends with an type annotation must be well printed", superInterfaceExpected, firstSuperInterface.toString());
final CtEnum<?> enumActual = ctClass.getElements(new NameFilter<CtEnum<?>>("DummyEnum")).get(0);
final Set<CtTypeReference<?>> superInterfacesOfEnum = enumActual.getSuperInterfaces();
final CtTypeReference<?> firstSuperInterfaceOfEnum = superInterfacesOfEnum.toArray(new CtTypeReference<?>[0])[0];
final List<CtAnnotation<? extends Annotation>> enumTypeAnnotations = firstSuperInterfaceOfEnum.getAnnotations();
final String enumExpected = "public enum DummyEnum implements spoon.test.annotation.testclasses.@spoon.test.annotation.testclasses.TypeAnnotation" + System.lineSeparator() + "BasicAnnotation {" + System.lineSeparator() + " ;" + System.lineSeparator() + "}";
assertEquals("Implements in a enum with a type annotation must have it in its model", 1, enumTypeAnnotations.size());
assertEquals("Type annotation on a implements in a enum must be typed by TypeAnnotation", TypeAnnotation.class, enumTypeAnnotations.get(0).getAnnotationType().getActualClass());
assertEquals(CtAnnotatedElementType.TYPE_USE, enumTypeAnnotations.get(0).getAnnotatedElementType());
assertEquals("Implements in a enum with an type annotation must be well printed", enumExpected, enumActual.toString());
final CtInterface<?> interfaceActual = ctClass.getElements(new NameFilter<CtInterface<?>>("DummyInterface")).get(0);
final Set<CtTypeReference<?>> superInterfacesOfInterface = interfaceActual.getSuperInterfaces();
final CtTypeReference<?> firstSuperInterfaceOfInterface = superInterfacesOfInterface.toArray(new CtTypeReference<?>[0])[0];
final List<CtAnnotation<? extends Annotation>> interfaceTypeAnnotations = firstSuperInterfaceOfInterface.getAnnotations();
final String interfaceExpected = "public interface DummyInterface extends spoon.test.annotation.testclasses.@spoon.test.annotation.testclasses.TypeAnnotation" + System.lineSeparator() + "BasicAnnotation {}";
assertEquals("Implements in a interface with a type annotation must have it in its model", 1, interfaceTypeAnnotations.size());
assertEquals("Type annotation on a implements in a enum must be typed by TypeAnnotation", TypeAnnotation.class, interfaceTypeAnnotations.get(0).getAnnotationType().getActualClass());
assertEquals(CtAnnotatedElementType.TYPE_USE, interfaceTypeAnnotations.get(0).getAnnotatedElementType());
assertEquals("Implements in a interface with an type annotation must be well printed", interfaceExpected, interfaceActual.toString());
}
@Test
public void testUsageOfTypeAnnotationWithGenericTypesInClassDeclaration() throws Exception {
final CtClass<?> ctClass = (CtClass<?>) this.factory.Type().get("spoon.test.annotation.testclasses.AnnotationsAppliedOnAnyTypeInAClass");
final CtClass<?> genericClass = ctClass.getElements(new NameFilter<CtClass<?>>("DummyGenericClass")).get(0);
// New type parameter declaration.
final List<CtTypeParameter> typeParameters = genericClass.getFormalCtTypeParameters();
assertEquals("Generic class has 2 generics parameters.", 2, typeParameters.size());
assertEquals("First generic type must have type annotation", "@spoon.test.annotation.testclasses.TypeAnnotation" + System.lineSeparator() + "T", typeParameters.get(0).toString());
assertEquals("Second generic type must have type annotation", "@spoon.test.annotation.testclasses.TypeAnnotation" + System.lineSeparator() + "K", typeParameters.get(1).toString());
final CtTypeReference<?> superInterface = genericClass.getSuperInterfaces().toArray(new CtTypeReference<?>[0])[0];
final String expected = "spoon.test.annotation.testclasses.BasicAnnotation<@spoon.test.annotation.testclasses.TypeAnnotation" + System.lineSeparator() + "T>";
assertEquals("Super interface has a generic type with type annotation", expected, superInterface.toString());
}
@Test
public void testUsageOfTypeAnnotationWithGenericTypesInStatements() throws Exception {
final CtClass<?> ctClass = (CtClass<?>) this.factory.Type().get("spoon.test.annotation.testclasses.AnnotationsAppliedOnAnyTypeInAClass");
final CtMethod<?> method = ctClass.getMethodsByName("m4").get(0);
// New type parameter declaration.
final List<CtTypeParameter> typeParameters = method.getFormalCtTypeParameters();
assertEquals("Method has 1 generic parameter", 1, typeParameters.size());
assertEquals("Method with an type annotation must be well printed", "@spoon.test.annotation.testclasses.TypeAnnotation" + System.lineSeparator() + "T", typeParameters.get(0).toString());
final CtBlock<?> body = method.getBody();
final String expectedFirstStatement =
"java.util.List<@spoon.test.annotation.testclasses.TypeAnnotation" +
System.lineSeparator() + "T> list = new java.util.ArrayList<>()";
final CtStatement firstStatement = body.getStatement(0);
assertEquals("Type annotation on generic parameter declared in the method",
expectedFirstStatement, firstStatement.toString());
final CtConstructorCall firstConstructorCall =
firstStatement.getElements(new TypeFilter<CtConstructorCall>(CtConstructorCall.class))
.get(0);
final CtTypeReference<?> firstTypeReference = firstConstructorCall.getType()
.getActualTypeArguments()
.get(0);
assertTrue(firstTypeReference.isImplicit());
assertEquals("T", firstTypeReference.getSimpleName());
final String expectedSecondStatement =
"java.util.List<@spoon.test.annotation.testclasses.TypeAnnotation" +
System.lineSeparator() + "?> list2 = new java.util.ArrayList<>()";
final CtStatement secondStatement = body.getStatement(1);
assertEquals("Wildcard with an type annotation must be well printed",
expectedSecondStatement, secondStatement.toString());
final CtConstructorCall secondConstructorCall =
secondStatement.getElements(new TypeFilter<CtConstructorCall>(CtConstructorCall.class))
.get(0);
final CtTypeReference<?> secondTypeReference = secondConstructorCall.getType()
.getActualTypeArguments()
.get(0);
assertTrue(secondTypeReference.isImplicit());
assertEquals("Object", secondTypeReference.getSimpleName());
final String expectedThirdStatement = "java.util.List<spoon.test.annotation.testclasses.@spoon.test.annotation.testclasses.TypeAnnotation" + System.lineSeparator() + "BasicAnnotation> list3 = new java.util.ArrayList<spoon.test.annotation.testclasses.@spoon.test.annotation.testclasses.TypeAnnotation" + System.lineSeparator() + "BasicAnnotation>()";
assertEquals("Type in generic parameter with an type annotation must be well printed", expectedThirdStatement, body.getStatement(2).toString());
}
@Test
public void testUsageOfParametersInTypeAnnotation() throws Exception {
final CtClass<?> ctClass = (CtClass<?>) this.factory.Type().get("spoon.test.annotation.testclasses.AnnotationsAppliedOnAnyTypeInAClass");
final CtMethod<?> method = ctClass.getMethodsByName("m5").get(0);
final String integerParam = "java.util.List<@spoon.test.annotation.testclasses.TypeAnnotation(integer = 1)" + System.lineSeparator() + "T> list";
assertEquals("integer parameter in type annotation", integerParam, method.getBody().getStatement(0).toString());
final String arrayIntegerParam = "java.util.List<@spoon.test.annotation.testclasses.TypeAnnotation(integers = { 1 })" + System.lineSeparator() + "T> list2";
assertEquals("array of integers parameter in type annotation", arrayIntegerParam, method.getBody().getStatement(1).toString());
final String stringParam = "java.util.List<@spoon.test.annotation.testclasses.TypeAnnotation(string = \"\")" + System.lineSeparator() + "T> list3";
assertEquals("string parameter in type annotation", stringParam, method.getBody().getStatement(2).toString());
final String arrayStringParam = "java.util.List<@spoon.test.annotation.testclasses.TypeAnnotation(strings = { \"\" })" + System.lineSeparator() + "T> list4";
assertEquals("array of strings parameter in type annotation", arrayStringParam, method.getBody().getStatement(3).toString());
final String classParam = "java.util.List<@spoon.test.annotation.testclasses.TypeAnnotation(clazz = java.lang.String.class)" + System.lineSeparator() + "T> list5";
assertEquals("class parameter in type annotation", classParam, method.getBody().getStatement(4).toString());
final String arrayClassParam = "java.util.List<@spoon.test.annotation.testclasses.TypeAnnotation(classes = { java.lang.String.class })" + System.lineSeparator() + "T> list6";
assertEquals("array of classes parameter in type annotation", arrayClassParam, method.getBody().getStatement(5).toString());
final String primitiveParam = "java.util.List<@spoon.test.annotation.testclasses.TypeAnnotation(b = true)" + System.lineSeparator() + "T> list7";
assertEquals("primitive parameter in type annotation", primitiveParam, method.getBody().getStatement(6).toString());
final String enumParam = "java.util.List<@spoon.test.annotation.testclasses.TypeAnnotation(e = spoon.test.annotation.testclasses.AnnotParamTypeEnum.R)" + System.lineSeparator() + "T> list8";
assertEquals("enum parameter in type annotation", enumParam, method.getBody().getStatement(7).toString());
final String annotationParam = "java.util.List<@spoon.test.annotation.testclasses.TypeAnnotation(ia = @spoon.test.annotation.testclasses.InnerAnnot(value = \"\"))" + System.lineSeparator() + "T> list9";
assertEquals("annotation parameter in type annotation", annotationParam, method.getBody().getStatement(8).toString());
final String arrayAnnotationParam = "java.util.List<@spoon.test.annotation.testclasses.TypeAnnotation(ias = { @spoon.test.annotation.testclasses.InnerAnnot(value = \"\") })" + System.lineSeparator() + "T> list10";
assertEquals("array of annotations parameter in type annotation", arrayAnnotationParam, method.getBody().getStatement(9).toString());
final String complexArrayParam = "java.util.List<@spoon.test.annotation.testclasses.TypeAnnotation(inceptions = { @spoon.test.annotation.testclasses.Inception(value = @spoon.test.annotation.testclasses.InnerAnnot(value = \"\")" + System.lineSeparator() + ", values = { @spoon.test.annotation.testclasses.InnerAnnot(value = \"\") }) })" + System.lineSeparator() + "T> list11";
assertEquals("array of complexes parameters in type annotation", complexArrayParam, method.getBody().getStatement(10).toString());
}
@Test
public void testOutputGeneratedByTypeAnnotation() throws Exception {
// we only write to disk here
launcher.setSourceOutputDirectory(new File("./target/spooned/"));
launcher.getModelBuilder().generateProcessedSourceFiles(OutputType.CLASSES);
canBeBuilt(new File("./target/spooned/spoon/test/annotation/testclasses/"), 8);
}
@Test
public void testRepeatSameAnnotationOnClass() throws Exception {
final CtClass<?> ctClass = (CtClass<?>) this.factory.Type().get(AnnotationsRepeated.class);
final List<CtAnnotation<? extends Annotation>> annotations = ctClass.getAnnotations();
assertEquals("Class must to have multi annotation of the same type", 2, annotations.size());
assertEquals("Type of the first annotation is AnnotationRepeated", AnnotationRepeated.class, annotations.get(0).getAnnotationType().getActualClass());
assertEquals("Type of the second annotation is AnnotationRepeated", AnnotationRepeated.class, annotations.get(1).getAnnotationType().getActualClass());
assertEquals("Argument of the first annotation is \"First\"", "First", ((CtLiteral) annotations.get(0).getValue("value")).getValue());
assertEquals("Argument of the second annotation is \"Second\"", "Second", ((CtLiteral) annotations.get(1).getValue("value")).getValue());
}
@Test
public void testRepeatSameAnnotationOnField() throws Exception {
final CtClass<?> ctClass = (CtClass<?>) this.factory.Type().get(AnnotationsRepeated.class);
final CtField<?> field = ctClass.getField("field");
final List<CtAnnotation<? extends Annotation>> annotations = field.getAnnotations();
assertEquals("Field must to have multi annotation of the same type", 2, annotations.size());
assertEquals("Type of the first annotation is AnnotationRepeated", AnnotationRepeated.class, annotations.get(0).getAnnotationType().getActualClass());
assertEquals("Type of the second annotation is AnnotationRepeated", AnnotationRepeated.class, annotations.get(1).getAnnotationType().getActualClass());
assertEquals("Argument of the first annotation is \"Field 1\"", "Field 1", ((CtLiteral) annotations.get(0).getValue("value")).getValue());
assertEquals("Argument of the second annotation is \"Field 2\"", "Field 2", ((CtLiteral) annotations.get(1).getValue("value")).getValue());
}
@Test
public void testRepeatSameAnnotationOnMethod() throws Exception {
final CtClass<?> ctClass = (CtClass<?>) this.factory.Type().get(AnnotationsRepeated.class);
final CtMethod<?> method = ctClass.getMethodsByName("method").get(0);
final List<CtAnnotation<? extends Annotation>> annotations = method.getAnnotations();
assertEquals("Method must to have multi annotation of the same type", 2, annotations.size());
assertEquals("Type of the first annotation is AnnotationRepeated", AnnotationRepeated.class, annotations.get(0).getAnnotationType().getActualClass());
assertEquals("Type of the second annotation is AnnotationRepeated", AnnotationRepeated.class, annotations.get(1).getAnnotationType().getActualClass());
assertEquals("Argument of the first annotation is \"Method 1\"", "Method 1", ((CtLiteral) annotations.get(0).getValue("value")).getValue());
assertEquals("Argument of the second annotation is \"Method 2\"", "Method 2", ((CtLiteral) annotations.get(1).getValue("value")).getValue());
}
@Test
public void testRepeatSameAnnotationOnConstructor() throws Exception {
final CtClass<?> ctClass = (CtClass<?>) this.factory.Type().get(AnnotationsRepeated.class);
final CtConstructor<?> ctConstructor = ctClass.getConstructors().toArray(new CtConstructor<?>[0])[0];
final List<CtAnnotation<? extends Annotation>> annotations = ctConstructor.getAnnotations();
assertEquals("Constructor must to have multi annotation of the same type", 2, annotations.size());
assertEquals("Type of the first annotation is AnnotationRepeated", AnnotationRepeated.class, annotations.get(0).getAnnotationType().getActualClass());
assertEquals("Type of the second annotation is AnnotationRepeated", AnnotationRepeated.class, annotations.get(1).getAnnotationType().getActualClass());
assertEquals("Argument of the first annotation is \"Constructor 1\"", "Constructor 1", ((CtLiteral) annotations.get(0).getValue("value")).getValue());
assertEquals("Argument of the second annotation is \"Constructor 2\"", "Constructor 2", ((CtLiteral) annotations.get(1).getValue("value")).getValue());
}
@Test
public void testRepeatSameAnnotationOnParameter() throws Exception {
final CtClass<?> ctClass = (CtClass<?>) this.factory.Type().get(AnnotationsRepeated.class);
final CtMethod<?> method = ctClass.getMethodsByName("methodWithParameter").get(0);
final CtParameter<?> ctParameter = method.getParameters().get(0);
final List<CtAnnotation<? extends Annotation>> annotations = ctParameter.getAnnotations();
assertEquals("Parameter must to have multi annotation of the same type", 2, annotations.size());
assertEquals("Type of the first annotation is AnnotationRepeated", AnnotationRepeated.class, annotations.get(0).getAnnotationType().getActualClass());
assertEquals("Type of the second annotation is AnnotationRepeated", AnnotationRepeated.class, annotations.get(1).getAnnotationType().getActualClass());
assertEquals("Argument of the first annotation is \"Param 1\"", "Param 1", ((CtLiteral) annotations.get(0).getValue("value")).getValue());
assertEquals("Argument of the second annotation is \"Param 2\"", "Param 2", ((CtLiteral) annotations.get(1).getValue("value")).getValue());
}
@Test
public void testRepeatSameAnnotationOnLocalVariable() throws Exception {
final CtClass<?> ctClass = (CtClass<?>) this.factory.Type().get(AnnotationsRepeated.class);
final CtMethod<?> method = ctClass.getMethodsByName("methodWithLocalVariable").get(0);
final CtLocalVariable<?> ctLocalVariable = method.getBody().getElements(new AbstractFilter<CtLocalVariable<?>>(CtLocalVariable.class) {
@Override
public boolean matches(CtLocalVariable<?> element) {
return true;
}
}).get(0);
final List<CtAnnotation<? extends Annotation>> annotations = ctLocalVariable.getAnnotations();
assertEquals("Local variable must to have multi annotation of the same type", 2, annotations.size());
assertEquals("Type of the first annotation is AnnotationRepeated", AnnotationRepeated.class, annotations.get(0).getAnnotationType().getActualClass());
assertEquals("Type of the second annotation is AnnotationRepeated", AnnotationRepeated.class, annotations.get(1).getAnnotationType().getActualClass());
assertEquals("Argument of the first annotation is \"Local 1\"", "Local 1", ((CtLiteral) annotations.get(0).getValue("value")).getValue());
assertEquals("Argument of the second annotation is \"Local 2\"", "Local 2", ((CtLiteral) annotations.get(1).getValue("value")).getValue());
}
@Test
public void testRepeatSameAnnotationOnPackage() throws Exception {
final CtPackage pkg = this.factory.Package().get("spoon.test.annotation.testclasses");
final List<CtAnnotation<? extends Annotation>> annotations = pkg.getAnnotations();
assertEquals("Local variable must to have multi annotation of the same type", 2, annotations.size());
assertEquals("Type of the first annotation is AnnotationRepeated", AnnotationRepeated.class, annotations.get(0).getAnnotationType().getActualClass());
assertEquals("Type of the second annotation is AnnotationRepeated", AnnotationRepeated.class, annotations.get(1).getAnnotationType().getActualClass());
assertEquals("Argument of the first annotation is \"Package 1\"", "Package 1", ((CtLiteral) annotations.get(0).getValue("value")).getValue());
assertEquals("Argument of the second annotation is \"Package 2\"", "Package 2", ((CtLiteral) annotations.get(1).getValue("value")).getValue());
}
@Test
public void testDefaultValueInAnnotationsForAnnotationFields() throws Exception {
final CtType<?> annotation = factory.Type().get(AnnotationDefaultAnnotation.class);
final CtAnnotationMethod<?> ctAnnotations = annotation.getMethods().toArray(new CtAnnotationMethod<?>[0])[0];
assertEquals("Field is typed by an annotation.", InnerAnnot.class, ctAnnotations.getType().getActualClass());
assertEquals("Default value of a field typed by an annotation must be an annotation",
InnerAnnot.class, ctAnnotations.getDefaultExpression().getType().getActualClass());
}
@Test
public void testGetAnnotationOuter() throws Exception {
final CtClass<?> ctClass = (CtClass<?>) this.factory.Type().get("spoon.test.annotation.testclasses.Foo");
final CtMethod<?> testMethod = ctClass.getMethodsByName("test").get(0);
Foo.OuterAnnotation annot = testMethod.getAnnotation(Foo.OuterAnnotation.class);
assertNotNull(annot);
assertEquals(2,annot.value().length);
}
@Test
public void testAbstractAllAnnotationProcessor() throws Exception {
Launcher spoon = new Launcher();
spoon.addInputResource("./src/test/java/spoon/test/annotation/testclasses/AnnotationsAppliedOnAnyTypeInAClass.java");
spoon.addInputResource("./src/test/java/spoon/test/annotation/testclasses/BasicAnnotation.java");
spoon.addInputResource("./src/test/java/spoon/test/annotation/testclasses/TypeAnnotation.java");
spoon.addInputResource("./src/test/java/spoon/test/annotation/testclasses/AnnotParamTypeEnum.java");
spoon.addInputResource("./src/test/java/spoon/test/annotation/testclasses/InnerAnnot.java");
spoon.addInputResource("./src/test/java/spoon/test/annotation/testclasses/Inception.java");
spoon.addInputResource("./src/test/java/spoon/test/annotation/testclasses/TestAnnotation.java");
spoon.addInputResource("./src/test/java/spoon/test/annotation/testclasses/AnnotArrayInnerClass.java");
factory = spoon.getFactory();
spoon.buildModel();
// create the processor
final ProcessingManager p = new QueueProcessingManager(factory);
final TypeAnnotationProcessor processor = new TypeAnnotationProcessor();
p.addProcessor(processor);
p.process(factory.Class().getAll());
assertEquals(29, processor.elements.size());
}
@Test
public void testAbstractAllAnnotationProcessorWithGlobalAnnotation() throws Exception {
Launcher spoon = new Launcher();
spoon.addInputResource("./src/test/java/spoon/test/annotation/testclasses/ClassProcessed.java");
spoon.addInputResource("./src/test/java/spoon/test/annotation/testclasses/TypeAnnotation.java");
spoon.addInputResource("./src/test/java/spoon/test/annotation/testclasses/AnnotParamTypeEnum.java");
spoon.addInputResource("./src/test/java/spoon/test/annotation/testclasses/InnerAnnot.java");
spoon.addInputResource("./src/test/java/spoon/test/annotation/testclasses/Inception.java");
spoon.addInputResource("./src/test/java/spoon/test/annotation/testclasses/GlobalAnnotation.java");
spoon.addInputResource("./src/test/java/spoon/test/annotation/testclasses/TestAnnotation.java");
factory = spoon.getFactory();
spoon.buildModel();
// create the processor
final ProcessingManager p = new QueueProcessingManager(factory);
final GlobalProcessor processor = new GlobalProcessor();
p.addProcessor(processor);
final TypeAnnotationMethodProcessor methodProcessor = new TypeAnnotationMethodProcessor();
p.addProcessor(methodProcessor);
p.process(factory.Class().getAll());
assertEquals(5, processor.elements.size());
assertEquals(2, methodProcessor.elements.size());
}
@Test
public void testAnnotationIntrospection() throws Exception {
CtClass<Object> aClass = factory.Class().get(AnnotationIntrospection.class);
CtMethod<?> mMethod = aClass.getMethod("m");
CtStatement statement = mMethod.getBody().getStatement(1);
assertEquals("annotation.equals(null)", statement.toString());
}
@Test
public void testFieldAndMethodInAnnotation() throws Exception {
final CtType<SuperAnnotation> aTypeAnnotation = buildClass(SuperAnnotation.class);
final CtField<?> fieldValue = aTypeAnnotation.getField("value");
assertNotNull(fieldValue);
assertEquals("java.lang.String value = \"\";", fieldValue.toString());
final CtMethod<Object> methodValue = aTypeAnnotation.getMethod("value");
assertTrue(methodValue instanceof CtAnnotationMethod);
assertEquals("java.lang.String value() default spoon.test.annotation.testclasses.SuperAnnotation.value;", methodValue.toString());
final CtMethod<Object> methodNoDefault = aTypeAnnotation.getMethod("value1");
assertTrue(methodNoDefault instanceof CtAnnotationMethod);
assertEquals("java.lang.String value1();", methodNoDefault.toString());
assertEquals(2, aTypeAnnotation.getMethods().size());
aTypeAnnotation.addMethod(methodValue.clone());
assertEquals(2, aTypeAnnotation.getMethods().size());
}
@Test
public void testAnnotationInterfacePreserveMethods() throws Exception {
final CtAnnotationType<?> ctAnnotationType = (CtAnnotationType<?>) this.factory.Type().get(PortRange.class);
List<CtMethod<?>> ctMethodMin = ctAnnotationType.getMethodsByName("min");
assertEquals("Method min is preserved after transformation", 1, ctMethodMin.size());
List<CtMethod<?>> ctMethodMax = ctAnnotationType.getMethodsByName("max");
assertEquals("Method max is preserved after transformation", 1, ctMethodMax.size());
List<CtMethod<?>> ctMethodMessage = ctAnnotationType.getMethodsByName("message");
assertEquals("Method message is preserved after transformation", 1, ctMethodMessage.size());
List<CtMethod<?>> ctMethodGroups = ctAnnotationType.getMethodsByName("groups");
assertEquals("Method groups is preserved after transformation", 1, ctMethodGroups.size());
List<CtMethod<?>> ctMethodPayload = ctAnnotationType.getMethodsByName("payload");
assertEquals("Method payload is preserved after transformation", 1, ctMethodPayload.size());
}
abstract class AbstractElementsProcessor<A extends Annotation, E extends CtElement>
extends AbstractAnnotationProcessor<A, E> {
final List<CtElement> elements = new ArrayList<>();
@Override
public void process(A annotation, E element) {
elements.add(element);
}
}
class GlobalProcessor extends AbstractElementsProcessor<GlobalAnnotation, CtElement> {
@Override
public void process(GlobalAnnotation annotation, CtElement element) {
super.process(annotation, element);
}
}
class TypeAnnotationProcessor extends AbstractElementsProcessor<TypeAnnotation, CtElement> {
@Override
public void process(TypeAnnotation annotation, CtElement element) {
super.process(annotation, element);
}
}
class TypeAnnotationMethodProcessor extends AbstractElementsProcessor<TypeAnnotation, CtTypeReference<?>> {
@Override
public void process(TypeAnnotation annotation, CtTypeReference<?> element) {
if (element.getParent() instanceof CtMethod) {
super.process(annotation, element);
}
}
}
public static Class<? extends Annotation> getActualClassFromAnnotation(CtAnnotation<? extends Annotation> annotation) {
return annotation.getAnnotationType().getActualClass();
}
private CtLiteral<?> getLiteralValueInAnnotation(CtAnnotation<?> annotation) {
return (CtLiteral<?>) annotation.getValues().get("value");
}
private CtAnnotation<?> getInnerAnnotation(CtAnnotation<?> firstAnnotationInArray) {
return (CtAnnotation<?>) firstAnnotationInArray.getValues().get("value");
}
private CtAnnotation<?> getMiddleAnnotation(CtNewArray<?> arrayAnnotations, int index) {
return (CtAnnotation<?>) arrayAnnotations.getElements().get(index);
}
@Test
public void testSpoonSpoonResult() throws Exception {
Launcher spoon = new Launcher();
spoon.addInputResource("./src/test/java/spoon/test/annotation/testclasses/dropwizard/GraphiteReporterFactory.java");
String output = "target/spooned-" + this.getClass().getSimpleName()+"-firstspoon/";
spoon.setSourceOutputDirectory(output);
factory = spoon.getFactory();
spoon.run();
Launcher spoon2 = new Launcher();
spoon2.addInputResource(output+"/spoon/test/annotation/testclasses/dropwizard/GraphiteReporterFactory.java");
//spoon2.addInputResource("./src/test/java/spoon/test/annotation/testclasses/PortRange.java");
spoon2.buildModel();
List<CtMethod<?>> methods = spoon2.getModel().getElements(new NameFilter<CtMethod<?>>("getPort"));
assertEquals("Number of method getPort should be 1", 1, methods.size());
CtMethod getport = methods.get(0);
CtTypeReference returnType = getport.getType();
List<CtAnnotation<?>> annotations = returnType.getAnnotations();
assertEquals("Number of annotation for return type of method getPort should be 1", 1, annotations.size());
CtAnnotation annotation = annotations.get(0);
assertEquals("Annotation should be @spoon.test.annotation.testclasses.PortRange", "spoon.test.annotation.testclasses.PortRange", annotation.getAnnotationType().getQualifiedName());
}
@Test
public void annotationAddValue() {
Launcher spoon = new Launcher();
spoon.addInputResource("./src/test/java/spoon/test/annotation/testclasses/Bar.java");
spoon.buildModel();
factory = spoon.getFactory();
List<CtMethod> methods = factory.getModel().getElements(new NameFilter<CtMethod>("bidule"));
assertThat(methods.size(), is(1));
CtAnnotation anno1 = factory.Annotation().annotate(methods.get(0), TypeAnnotation.class).addValue("params", new String[] { "test"});
assertThat(anno1.getValue("params").getType(), is(factory.Type().createReference(String[].class)));
CtAnnotation anno = factory.Annotation().annotate(methods.get(0), TypeAnnotation.class).addValue("params", new String[0]);
assertThat(anno.getValue("params").getType(), is(factory.Type().createReference(String[].class)));
}
}