358 lines
16 KiB
Java
358 lines
16 KiB
Java
/*
|
|
* Copyright 2010-2016 JetBrains s.r.o.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
package org.jetbrains.kotlin.codegen;
|
|
|
|
import org.jetbrains.annotations.NotNull;
|
|
import org.jetbrains.annotations.Nullable;
|
|
import org.jetbrains.kotlin.test.ConfigurationKind;
|
|
|
|
import java.lang.annotation.*;
|
|
import java.lang.reflect.*;
|
|
|
|
public class AnnotationGenTest extends CodegenTestCase {
|
|
@Override
|
|
protected void setUp() throws Exception {
|
|
super.setUp();
|
|
createEnvironmentWithMockJdkAndIdeaAnnotations(ConfigurationKind.ALL);
|
|
}
|
|
|
|
public void testVolatileProperty() throws Exception {
|
|
loadText("abstract class Foo { @Volatile public var x: String = \"\"; }");
|
|
Class<?> aClass = generateClass("Foo");
|
|
Field x = aClass.getDeclaredField("x");
|
|
assertTrue((x.getModifiers() & Modifier.VOLATILE) != 0);
|
|
}
|
|
|
|
public void testPropField() throws Exception {
|
|
loadText("@[java.lang.Deprecated] var x = 0");
|
|
Class<?> srcClass = generateFacadeClass();
|
|
assertNull(srcClass.getDeclaredMethod("getX").getAnnotation(Deprecated.class));
|
|
assertNull(srcClass.getDeclaredMethod("setX", int.class).getAnnotation(Deprecated.class));
|
|
assertNotNull(srcClass.getDeclaredField("x").getAnnotation(Deprecated.class));
|
|
}
|
|
|
|
public void testPropGetter() throws Exception {
|
|
loadText("var x = 0\n" +
|
|
"@[java.lang.Deprecated] get");
|
|
Class<?> srcClass = generateFacadeClass();
|
|
assertNotNull(srcClass.getDeclaredMethod("getX").getAnnotation(Deprecated.class));
|
|
assertNull(srcClass.getDeclaredMethod("setX", int.class).getAnnotation(Deprecated.class));
|
|
assertNull(srcClass.getDeclaredField("x").getAnnotation(Deprecated.class));
|
|
}
|
|
|
|
public void testPropSetter() throws Exception {
|
|
loadText("var x = 0\n" +
|
|
"@[java.lang.Deprecated] set");
|
|
Class<?> scrClass = generateFacadeClass();
|
|
assertNull(scrClass.getDeclaredMethod("getX").getAnnotation(Deprecated.class));
|
|
assertNotNull(scrClass.getDeclaredMethod("setX", int.class).getAnnotation(Deprecated.class));
|
|
assertNull(scrClass.getDeclaredField("x").getAnnotation(Deprecated.class));
|
|
}
|
|
|
|
public void testAnnotationForParamInTopLevelFunction() throws Exception {
|
|
loadText("fun x(@[java.lang.Deprecated] i: Int) {}");
|
|
Class<?> srcClass = generateFacadeClass();
|
|
Method srcClassMethod = srcClass.getMethod("x", int.class);
|
|
assertNotNull(srcClassMethod);
|
|
assertNotNull(getDeprecatedAnnotationFromList(srcClassMethod.getParameterAnnotations()[0]));
|
|
}
|
|
|
|
public void testAnnotationForParamInInstanceFunction() throws NoSuchMethodException {
|
|
loadText("class A() { fun x(@[java.lang.Deprecated] i: Int) {}}");
|
|
Class<?> aClass = generateClass("A");
|
|
Method x = aClass.getMethod("x", int.class);
|
|
assertNotNull(x);
|
|
// Get annotations for first parameter
|
|
Annotation[] annotations = x.getParameterAnnotations()[0];
|
|
assertNotNull(getDeprecatedAnnotationFromList(annotations));
|
|
}
|
|
|
|
public void testAnnotationForParamInInstanceExtensionFunction() throws NoSuchMethodException {
|
|
loadText("class A() { fun String.x(@[java.lang.Deprecated] i: Int) {}}");
|
|
Class<?> aClass = generateClass("A");
|
|
Method x = aClass.getMethod("x", String.class, int.class);
|
|
assertNotNull(x);
|
|
// Get annotations for first real parameter
|
|
Annotation[] annotations = x.getParameterAnnotations()[1];
|
|
assertNotNull(getDeprecatedAnnotationFromList(annotations));
|
|
}
|
|
|
|
public void testParamInConstructor() throws NoSuchMethodException {
|
|
loadText("class A (@[java.lang.Deprecated] x: Int) {}");
|
|
Class<?> aClass = generateClass("A");
|
|
Constructor constructor = aClass.getDeclaredConstructor(int.class);
|
|
assertNotNull(constructor);
|
|
// Get annotations for first parameter
|
|
Annotation[] annotations = constructor.getParameterAnnotations()[0];
|
|
assertNotNull(getDeprecatedAnnotationFromList(annotations));
|
|
}
|
|
|
|
public void testParamInEnumConstructor() throws NoSuchMethodException {
|
|
loadText("enum class E(@[java.lang.Deprecated] p: String)");
|
|
Class<?> klass = generateClass("E");
|
|
Constructor constructor = klass.getDeclaredConstructor(String.class, int.class, String.class);
|
|
assertNotNull(constructor);
|
|
// Get annotations for first parameter
|
|
Annotation[] annotations = constructor.getParameterAnnotations()[0];
|
|
assertNotNull(getDeprecatedAnnotationFromList(annotations));
|
|
}
|
|
|
|
public void testParamInInnerConstructor() throws NoSuchMethodException {
|
|
loadText("class Outer { inner class Inner(@[java.lang.Deprecated] x: Int) }");
|
|
Class<?> outer = generateClass("Outer");
|
|
Class<?> inner = outer.getDeclaredClasses()[0];
|
|
Constructor constructor = inner.getDeclaredConstructor(outer, int.class);
|
|
assertNotNull(constructor);
|
|
// Get annotations for first parameter
|
|
Annotation[] annotations = constructor.getParameterAnnotations()[0];
|
|
assertNotNull(getDeprecatedAnnotationFromList(annotations));
|
|
}
|
|
|
|
public void testPropFieldInConstructor() throws NoSuchFieldException, NoSuchMethodException {
|
|
loadText("class A (@field:java.lang.Deprecated @param:java.lang.Deprecated var x: Int) {}");
|
|
Class<?> aClass = generateClass("A");
|
|
Constructor constructor = aClass.getDeclaredConstructor(int.class);
|
|
assertNotNull(constructor);
|
|
// Get annotations for first parameter
|
|
Annotation[] annotations = constructor.getParameterAnnotations()[0];
|
|
assertNotNull(getDeprecatedAnnotationFromList(annotations));
|
|
assertNull(aClass.getDeclaredMethod("getX").getAnnotation(Deprecated.class));
|
|
assertNull(aClass.getDeclaredMethod("setX", int.class).getAnnotation(Deprecated.class));
|
|
assertNotNull(aClass.getDeclaredField("x").getAnnotation(Deprecated.class));
|
|
}
|
|
|
|
public void testAnnotationWithParamForParamInFunction() throws Exception {
|
|
loadText("import java.lang.annotation.*\n" +
|
|
"@java.lang.annotation.Retention(RetentionPolicy.RUNTIME) annotation class A(val a: String)\n" +
|
|
"fun x(@A(\"239\") i: Int) {}");
|
|
Class<?> packageClass = generateFacadeClass();
|
|
Method packageClassMethod = packageClass.getMethod("x", int.class);
|
|
assertNotNull(packageClassMethod);
|
|
assertNotNull(getAnnotationByName(packageClassMethod.getParameterAnnotations()[0], "A"));
|
|
}
|
|
|
|
@Nullable
|
|
private static Annotation getAnnotationByName(@NotNull Annotation[] annotations, @NotNull String name) {
|
|
for (Annotation annotation : annotations) {
|
|
if (annotation.annotationType().getCanonicalName().equals(name)) {
|
|
return annotation;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
private static Deprecated getDeprecatedAnnotationFromList(Annotation[] annotations) {
|
|
for (Annotation annotation : annotations) {
|
|
if (annotation instanceof Deprecated) {
|
|
return (Deprecated) annotation;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public void testConstructor() throws NoSuchFieldException, NoSuchMethodException {
|
|
loadText("class A @[java.lang.Deprecated] constructor() {}");
|
|
Class<?> aClass = generateClass("A");
|
|
Constructor<?> x = aClass.getDeclaredConstructor();
|
|
Deprecated annotation = x.getAnnotation(Deprecated.class);
|
|
assertNotNull(annotation);
|
|
}
|
|
|
|
public void testMethod() throws Exception {
|
|
loadText("@[java.lang.Deprecated] fun x () {}");
|
|
Class<?> srcClass = generateFacadeClass();
|
|
Method srcClassMethod = srcClass.getDeclaredMethod("x");
|
|
assertNotNull(srcClassMethod.getAnnotation(Deprecated.class));
|
|
}
|
|
|
|
public void testClass() throws NoSuchFieldException, NoSuchMethodException {
|
|
loadText("@[java.lang.Deprecated] class A () {}");
|
|
Class<?> aClass = generateClass("A");
|
|
Deprecated annotation = aClass.getAnnotation(Deprecated.class);
|
|
assertNotNull(annotation);
|
|
}
|
|
|
|
public void testSimplestAnnotationClass() {
|
|
loadText("annotation class A");
|
|
Class<?> aClass = generateClass("A");
|
|
Class[] interfaces = aClass.getInterfaces();
|
|
assertEquals(0, aClass.getDeclaredMethods().length);
|
|
assertTrue(aClass.isAnnotation());
|
|
assertEquals(1, interfaces.length);
|
|
assertEquals("java.lang.annotation.Annotation", interfaces[0].getName());
|
|
}
|
|
|
|
public void testAnnotationClassWithStringProperty() throws ClassNotFoundException, IllegalAccessException, InvocationTargetException {
|
|
loadText("import java.lang.annotation.*\n" +
|
|
"" +
|
|
"@java.lang.annotation.Retention(RetentionPolicy.RUNTIME) annotation class A(val a: String)\n" +
|
|
"" +
|
|
"@A(\"239\") class B()");
|
|
@SuppressWarnings("unchecked")
|
|
Class<? extends Annotation> aClass = (Class) generateClass("A");
|
|
|
|
Retention annotation = aClass.getAnnotation(Retention.class);
|
|
RetentionPolicy value = annotation.value();
|
|
assertEquals(RetentionPolicy.RUNTIME, value);
|
|
|
|
Method[] methods = aClass.getDeclaredMethods();
|
|
assertEquals(1, methods.length);
|
|
assertEquals("a", methods[0].getName());
|
|
assertEquals(String.class, methods[0].getReturnType());
|
|
assertEquals(0, methods[0].getParameterTypes().length);
|
|
assertTrue(aClass.isAnnotation());
|
|
|
|
Class<?> bClass = aClass.getClassLoader().loadClass("B");
|
|
Annotation bClassAnnotation = bClass.getAnnotation(aClass);
|
|
assertNotNull(bClassAnnotation);
|
|
|
|
assertEquals("239", methods[0].invoke(bClassAnnotation));
|
|
}
|
|
|
|
public void testAnnotationClassWithAnnotationProperty()
|
|
throws NoSuchMethodException, ClassNotFoundException, IllegalAccessException, InvocationTargetException {
|
|
loadText("import java.lang.annotation.*\n" +
|
|
"" +
|
|
"annotation class C(val c: String)\n" +
|
|
"@java.lang.annotation.Retention(RetentionPolicy.RUNTIME) annotation class A(val a: C)\n" +
|
|
"" +
|
|
"@A(C(\"239\")) class B()");
|
|
@SuppressWarnings("unchecked")
|
|
Class<? extends Annotation> aClass = (Class) generateClass("A");
|
|
|
|
Retention annotation = aClass.getAnnotation(Retention.class);
|
|
RetentionPolicy value = annotation.value();
|
|
assertEquals(RetentionPolicy.RUNTIME, value);
|
|
|
|
Method[] methods = aClass.getDeclaredMethods();
|
|
assertEquals(1, methods.length);
|
|
assertEquals("a", methods[0].getName());
|
|
assertEquals("C", methods[0].getReturnType().getName());
|
|
assertEquals(0, methods[0].getParameterTypes().length);
|
|
assertTrue(aClass.isAnnotation());
|
|
|
|
Class<?> bClass = aClass.getClassLoader().loadClass("B");
|
|
Annotation bClassAnnotation = bClass.getAnnotation(aClass);
|
|
assertNotNull(bClassAnnotation);
|
|
|
|
Object invoke = methods[0].invoke(bClassAnnotation);
|
|
// there is some Proxy here
|
|
Class<?> cClass = invoke.getClass().getInterfaces()[0];
|
|
assertEquals("C", cClass.getName());
|
|
assertEquals("239", cClass.getDeclaredMethod("c").invoke(invoke));
|
|
}
|
|
|
|
public void testAnnotationClassWithStringArrayProperty()
|
|
throws ClassNotFoundException, IllegalAccessException, InvocationTargetException {
|
|
loadText("import java.lang.annotation.*\n" +
|
|
"" +
|
|
"@java.lang.annotation.Retention(RetentionPolicy.RUNTIME) annotation class A(val a: Array<String>)\n" +
|
|
"" +
|
|
"@A(arrayOf(\"239\",\"932\")) class B()");
|
|
@SuppressWarnings("unchecked")
|
|
Class<? extends Annotation> aClass = (Class) generateClass("A");
|
|
|
|
Retention annotation = aClass.getAnnotation(Retention.class);
|
|
RetentionPolicy value = annotation.value();
|
|
assertEquals(RetentionPolicy.RUNTIME, value);
|
|
|
|
Method[] methods = aClass.getDeclaredMethods();
|
|
assertEquals(1, methods.length);
|
|
assertEquals("a", methods[0].getName());
|
|
assertEquals(String[].class, methods[0].getReturnType());
|
|
assertEquals(0, methods[0].getParameterTypes().length);
|
|
assertTrue(aClass.isAnnotation());
|
|
|
|
Class<?> bClass = aClass.getClassLoader().loadClass("B");
|
|
Annotation bClassAnnotation = bClass.getAnnotation(aClass);
|
|
assertNotNull(bClassAnnotation);
|
|
|
|
Object invoke = methods[0].invoke(bClassAnnotation);
|
|
assertEquals("239", ((String[]) invoke)[0]);
|
|
assertEquals("932", ((String[]) invoke)[1]);
|
|
}
|
|
|
|
public void testAnnotationClassWithIntArrayProperty() throws ClassNotFoundException, IllegalAccessException, InvocationTargetException {
|
|
loadText("import java.lang.annotation.*\n" +
|
|
"" +
|
|
"@java.lang.annotation.Retention(RetentionPolicy.RUNTIME) annotation class A(val a: IntArray)\n" +
|
|
"" +
|
|
"@A(intArrayOf(239,932)) class B()");
|
|
@SuppressWarnings("unchecked")
|
|
Class<? extends Annotation> aClass = (Class) generateClass("A");
|
|
|
|
Retention annotation = aClass.getAnnotation(Retention.class);
|
|
RetentionPolicy value = annotation.value();
|
|
assertEquals(RetentionPolicy.RUNTIME, value);
|
|
|
|
Method[] methods = aClass.getDeclaredMethods();
|
|
assertEquals(1, methods.length);
|
|
assertEquals("a", methods[0].getName());
|
|
assertEquals(int[].class, methods[0].getReturnType());
|
|
assertEquals(0, methods[0].getParameterTypes().length);
|
|
assertTrue(aClass.isAnnotation());
|
|
|
|
Class<?> bClass = aClass.getClassLoader().loadClass("B");
|
|
Annotation bClassAnnotation = bClass.getAnnotation(aClass);
|
|
assertNotNull(bClassAnnotation);
|
|
|
|
Object invoke = methods[0].invoke(bClassAnnotation);
|
|
assertEquals(239, ((int[]) invoke)[0]);
|
|
assertEquals(932, ((int[]) invoke)[1]);
|
|
}
|
|
|
|
public void testAnnotationClassWithEnumArrayProperty() {
|
|
loadText("import java.lang.annotation.*\n" +
|
|
"" +
|
|
"@java.lang.annotation.Target(ElementType.TYPE, ElementType.METHOD) annotation class A");
|
|
Class<?> aClass = generateClass("A");
|
|
|
|
Target annotation = aClass.getAnnotation(Target.class);
|
|
ElementType[] value = annotation.value();
|
|
assertEquals(2, value.length);
|
|
|
|
assertEquals(ElementType.TYPE, value[0]);
|
|
assertEquals(ElementType.METHOD, value[1]);
|
|
}
|
|
|
|
public void testAnnotationClassWithAnnotationArrayProperty()
|
|
throws ClassNotFoundException, IllegalAccessException, InvocationTargetException {
|
|
loadText("import java.lang.annotation.*\n" +
|
|
"import java.lang.annotation.Retention\n" +
|
|
"" +
|
|
"@Retention(RetentionPolicy.RUNTIME) annotation class A(val a: Array<Retention>)\n" +
|
|
"" +
|
|
"@A(arrayOf(Retention(RetentionPolicy.RUNTIME),Retention(RetentionPolicy.SOURCE))) class B()");
|
|
@SuppressWarnings("unchecked")
|
|
Class<? extends Annotation> aClass = (Class) generateClass("A");
|
|
|
|
Method[] methods = aClass.getDeclaredMethods();
|
|
assertEquals(1, methods.length);
|
|
assertEquals("a", methods[0].getName());
|
|
|
|
Class<?> bClass = aClass.getClassLoader().loadClass("B");
|
|
Annotation bClassAnnotation = bClass.getAnnotation(aClass);
|
|
assertNotNull(bClassAnnotation);
|
|
|
|
Object invoke = methods[0].invoke(bClassAnnotation);
|
|
Retention[] invoke1 = (Retention[]) invoke;
|
|
assertEquals(2, invoke1.length);
|
|
assertEquals(invoke1[0].value(), RetentionPolicy.RUNTIME);
|
|
assertEquals(invoke1[1].value(), RetentionPolicy.SOURCE);
|
|
}
|
|
}
|