more annotations
This commit is contained in:
@@ -17,20 +17,17 @@
|
||||
package org.jetbrains.jet.codegen;
|
||||
|
||||
import com.intellij.psi.PsiElement;
|
||||
import org.jetbrains.jet.codegen.intrinsics.IntrinsicMethod;
|
||||
import org.jetbrains.jet.codegen.intrinsics.IntrinsicMethods;
|
||||
import org.jetbrains.jet.lang.descriptors.*;
|
||||
import org.jetbrains.jet.lang.descriptors.annotations.Annotated;
|
||||
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.resolve.calls.DefaultValueArgument;
|
||||
import org.jetbrains.jet.lang.resolve.calls.ResolvedCall;
|
||||
import org.jetbrains.jet.lang.resolve.calls.ResolvedValueArgument;
|
||||
import org.jetbrains.jet.lang.resolve.calls.*;
|
||||
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
import org.objectweb.asm.AnnotationVisitor;
|
||||
import org.objectweb.asm.ClassVisitor;
|
||||
import org.objectweb.asm.FieldVisitor;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.*;
|
||||
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.List;
|
||||
@@ -80,12 +77,67 @@ public abstract class AnnotationCodegen {
|
||||
ResolvedValueArgument valueArgument = entry.getValue();
|
||||
if (!(valueArgument instanceof DefaultValueArgument)) {
|
||||
List<ValueArgument> valueArguments = valueArgument.getArguments();
|
||||
assert valueArguments.size() == 1 : "Number of assertions on " + resolvedCall.getResultingDescriptor() + " = " + valueArguments.size(); // todo
|
||||
CompileTimeConstant<?> compileTimeConstant = bindingContext.get(BindingContext.COMPILE_TIME_VALUE, valueArguments.get(0).getArgumentExpression());
|
||||
assert compileTimeConstant != null;
|
||||
assert valueArguments.size() == 1 : "Number of arguments on " + resolvedCall.getResultingDescriptor() + " = " + valueArguments.size(); // todo
|
||||
CompileTimeConstant<?> compileTimeConstant =
|
||||
bindingContext.get(BindingContext.COMPILE_TIME_VALUE, valueArguments.get(0).getArgumentExpression());
|
||||
|
||||
Object value = compileTimeConstant.getValue();
|
||||
annotationVisitor.visit(entry.getKey().getName(), value);
|
||||
String keyName = entry.getKey().getName();
|
||||
if(compileTimeConstant != null) {
|
||||
Object value = compileTimeConstant.getValue();
|
||||
annotationVisitor.visit(keyName, value);
|
||||
continue;
|
||||
}
|
||||
|
||||
ExpressionValueArgument expressionValueArgument = (ExpressionValueArgument)valueArgument;
|
||||
JetExpression expression = expressionValueArgument.getArguments().get(0).getArgumentExpression();
|
||||
if(expression instanceof JetDotQualifiedExpression) {
|
||||
JetDotQualifiedExpression qualifiedExpression = (JetDotQualifiedExpression)expression;
|
||||
ResolvedCall<? extends CallableDescriptor> call =
|
||||
bindingContext.get(BindingContext.RESOLVED_CALL, qualifiedExpression.getSelectorExpression());
|
||||
if(call != null) {
|
||||
if(call.getResultingDescriptor() instanceof PropertyDescriptor) {
|
||||
PropertyDescriptor descriptor = (PropertyDescriptor)call.getResultingDescriptor();
|
||||
annotationVisitor.visitEnum(keyName, typeMapper.mapType(descriptor.getReturnType()).getDescriptor(),descriptor.getName());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(expression instanceof JetCallExpression) {
|
||||
JetCallExpression callExpression = (JetCallExpression)expression;
|
||||
ResolvedCall<? extends CallableDescriptor> call =
|
||||
bindingContext.get(BindingContext.RESOLVED_CALL, callExpression.getCalleeExpression());
|
||||
if(call != null) {
|
||||
List<AnnotationDescriptor> annotations = call.getResultingDescriptor().getOriginal().getAnnotations();
|
||||
String value = null;
|
||||
if (annotations != null) {
|
||||
for (AnnotationDescriptor annotation : annotations) {
|
||||
if("Intrinsic".equals(annotation.getType().getConstructor().getDeclarationDescriptor().getName())) {
|
||||
value = (String) annotation.getValueArguments().get(0).getValue();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(IntrinsicMethods.KOTLIN_JAVA_CLASS_FUNCTION.equals(value)) {
|
||||
annotationVisitor.visit(keyName, typeMapper.mapType(call.getResultingDescriptor().getReturnType().getArguments().get(0).getType()));
|
||||
continue;
|
||||
}
|
||||
if(IntrinsicMethods.KOTLIN_ARRAYS_ARRAY.equals(value)) {
|
||||
AnnotationVisitor visitor = annotationVisitor.visitArray(keyName);
|
||||
VarargValueArgument next = (VarargValueArgument)call.getValueArguments().values().iterator().next();
|
||||
for (ValueArgument argument : next.getArguments()) {
|
||||
CompileTimeConstant<?> constant =
|
||||
bindingContext.get(BindingContext.COMPILE_TIME_VALUE, argument.getArgumentExpression());
|
||||
visitor.visit(null, constant.getValue());
|
||||
}
|
||||
visitor.visitEnd();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalStateException("Don't know how to compile annotation value");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -29,6 +29,9 @@ import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static org.objectweb.asm.Opcodes.ACC_ABSTRACT;
|
||||
import static org.objectweb.asm.Opcodes.ACC_PUBLIC;
|
||||
|
||||
/**
|
||||
* @author max
|
||||
* @author yole
|
||||
@@ -99,27 +102,33 @@ public abstract class ClassBodyCodegen {
|
||||
functionCodegen.gen(declaration);
|
||||
}
|
||||
|
||||
private void generatePrimaryConstructorProperties(PropertyCodegen propertyCodegen, PsiElement origin) {
|
||||
private void generatePrimaryConstructorProperties(PropertyCodegen propertyCodegen, JetClassOrObject origin) {
|
||||
boolean isAnnotation = origin instanceof JetClass && ((JetClass)origin).isAnnotation();
|
||||
OwnerKind kind = context.getContextKind();
|
||||
for (JetParameter p : getPrimaryConstructorParameters()) {
|
||||
if (p.getValOrVarNode() != null) {
|
||||
PropertyDescriptor propertyDescriptor = state.getBindingContext().get(BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER, p);
|
||||
if (propertyDescriptor != null) {
|
||||
propertyCodegen.generateDefaultGetter(propertyDescriptor, Opcodes.ACC_PUBLIC, p);
|
||||
if (propertyDescriptor.isVar()) {
|
||||
propertyCodegen.generateDefaultSetter(propertyDescriptor, Opcodes.ACC_PUBLIC, origin);
|
||||
}
|
||||
if(!isAnnotation) {
|
||||
propertyCodegen.generateDefaultGetter(propertyDescriptor, ACC_PUBLIC, p);
|
||||
if (propertyDescriptor.isVar()) {
|
||||
propertyCodegen.generateDefaultSetter(propertyDescriptor, ACC_PUBLIC, origin);
|
||||
}
|
||||
|
||||
//noinspection ConstantConditions
|
||||
if (!(kind instanceof OwnerKind.DelegateKind) && state.getBindingContext().get(BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor)) {
|
||||
int modifiers = JetTypeMapper.getAccessModifiers(propertyDescriptor, 0);
|
||||
if (!propertyDescriptor.isVar()) {
|
||||
modifiers |= Opcodes.ACC_FINAL;
|
||||
//noinspection ConstantConditions
|
||||
if (!(kind instanceof OwnerKind.DelegateKind) && state.getBindingContext().get(BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor)) {
|
||||
int modifiers = JetTypeMapper.getAccessModifiers(propertyDescriptor, 0);
|
||||
if (!propertyDescriptor.isVar()) {
|
||||
modifiers |= Opcodes.ACC_FINAL;
|
||||
}
|
||||
if(state.getInjector().getJetStandardLibrary().isVolatile(propertyDescriptor)) {
|
||||
modifiers |= Opcodes.ACC_VOLATILE;
|
||||
}
|
||||
v.newField(p, modifiers, p.getName(), state.getInjector().getJetTypeMapper().mapType(propertyDescriptor.getType()).getDescriptor(), null, null);
|
||||
}
|
||||
if(state.getInjector().getJetStandardLibrary().isVolatile(propertyDescriptor)) {
|
||||
modifiers |= Opcodes.ACC_VOLATILE;
|
||||
}
|
||||
v.newField(p, modifiers, p.getName(), state.getInjector().getJetTypeMapper().mapType(propertyDescriptor.getType()).getDescriptor(), null, null);
|
||||
}
|
||||
else {
|
||||
v.newMethod(p, ACC_PUBLIC|ACC_ABSTRACT, p.getName(), "()" + state.getInjector().getJetTypeMapper().mapType(propertyDescriptor.getType()).getDescriptor(), null, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -135,7 +144,7 @@ public abstract class ClassBodyCodegen {
|
||||
|
||||
private void generateStaticInitializer() {
|
||||
if (staticInitializerChunks.size() > 0) {
|
||||
final MethodVisitor mv = v.newMethod(null, Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC,"<clinit>", "()V", null, null);
|
||||
final MethodVisitor mv = v.newMethod(null, ACC_PUBLIC | Opcodes.ACC_STATIC,"<clinit>", "()V", null, null);
|
||||
if (v.generateCode() == ClassBuilder.Mode.FULL) {
|
||||
mv.visitCode();
|
||||
|
||||
|
||||
@@ -72,7 +72,8 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||
boolean isInterface = false;
|
||||
boolean isFinal = false;
|
||||
boolean isStatic = false;
|
||||
|
||||
boolean isAnnotation = false;
|
||||
|
||||
if(myClass instanceof JetClass) {
|
||||
JetClass jetClass = (JetClass) myClass;
|
||||
if (jetClass.hasModifier(JetTokens.ABSTRACT_KEYWORD))
|
||||
@@ -81,6 +82,12 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||
isAbstract = true;
|
||||
isInterface = true;
|
||||
}
|
||||
if (jetClass.isAnnotation()) {
|
||||
isAbstract = true;
|
||||
isInterface = true;
|
||||
isAnnotation = true;
|
||||
signature.getInterfaces().add("java/lang/annotation/Annotation");
|
||||
}
|
||||
if (!jetClass.hasModifier(JetTokens.OPEN_KEYWORD) && !isAbstract) {
|
||||
isFinal = true;
|
||||
}
|
||||
@@ -103,6 +110,9 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||
if (isStatic) {
|
||||
access |= ACC_STATIC;
|
||||
}
|
||||
if (isAnnotation) {
|
||||
access |= ACC_ANNOTATION;
|
||||
}
|
||||
v.defineClass(myClass, V1_6,
|
||||
access,
|
||||
signature.getName(),
|
||||
@@ -407,8 +417,14 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
||||
}
|
||||
|
||||
protected void generatePrimaryConstructor() {
|
||||
if(myClass instanceof JetClass && ((JetClass) myClass).isTrait())
|
||||
return;
|
||||
if(myClass instanceof JetClass) {
|
||||
JetClass aClass = (JetClass)myClass;
|
||||
if(aClass.isTrait())
|
||||
return;
|
||||
if(aClass.isAnnotation()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ConstructorDescriptor constructorDescriptor = bindingContext.get(BindingContext.CONSTRUCTOR, myClass);
|
||||
|
||||
|
||||
@@ -63,6 +63,9 @@ public class IntrinsicMethods {
|
||||
public static final ArraySet ARRAY_SET = new ArraySet();
|
||||
public static final ArrayGet ARRAY_GET = new ArrayGet();
|
||||
public static final StringPlus STRING_PLUS = new StringPlus();
|
||||
public static final String KOTLIN_JAVA_CLASS_FUNCTION = "kotlin.javaClass.function";
|
||||
public static final String KOTLIN_ARRAYS_ARRAY = "kotlin.arrays.array";
|
||||
public static final String KOTLIN_JAVA_CLASS_PROPERTY = "kotlin.javaClass.property";
|
||||
|
||||
private Project myProject;
|
||||
private JetStandardLibrary myStdLib;
|
||||
@@ -83,9 +86,9 @@ public class IntrinsicMethods {
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
namedMethods.put("kotlin.javaClass.function", new JavaClassFunction());
|
||||
namedMethods.put("kotlin.javaClass.property", new JavaClassProperty());
|
||||
namedMethods.put("kotlin.arrays.array", new JavaClassArray());
|
||||
namedMethods.put(KOTLIN_JAVA_CLASS_FUNCTION, new JavaClassFunction());
|
||||
namedMethods.put(KOTLIN_JAVA_CLASS_PROPERTY, new JavaClassProperty());
|
||||
namedMethods.put(KOTLIN_ARRAYS_ARRAY, new JavaClassArray());
|
||||
|
||||
List<String> primitiveCastMethods = OperatorConventions.NUMBER_CONVERSIONS.asList();
|
||||
for (String method : primitiveCastMethods) {
|
||||
@@ -249,6 +252,21 @@ public class IntrinsicMethods {
|
||||
return descriptor.getMemberScope(typeParameters);
|
||||
}
|
||||
|
||||
public IntrinsicMethod isIntrinsicMethod(DeclarationDescriptor descriptor) {
|
||||
List<AnnotationDescriptor> annotations = descriptor.getAnnotations();
|
||||
if (annotations != null) {
|
||||
for (AnnotationDescriptor annotation : annotations) {
|
||||
if("Intrinsic".equals(annotation.getType().getConstructor().getDeclarationDescriptor().getName())) {
|
||||
String value = (String) annotation.getValueArguments().get(0).getValue();
|
||||
IntrinsicMethod intrinsicMethod = namedMethods.get(value);
|
||||
if(intrinsicMethod != null)
|
||||
return intrinsicMethod;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public IntrinsicMethod getIntrinsic(DeclarationDescriptor descriptor) {
|
||||
IntrinsicMethod intrinsicMethod = myMethods.get(descriptor.getOriginal());
|
||||
if(intrinsicMethod == null) {
|
||||
|
||||
@@ -143,6 +143,10 @@ public class JetClass extends JetTypeParameterListOwner
|
||||
return findChildByType(JetTokens.TRAIT_KEYWORD) != null;
|
||||
}
|
||||
|
||||
public boolean isAnnotation() {
|
||||
return hasModifier(JetTokens.ANNOTATION_KEYWORD);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IStubElementType getElementType() {
|
||||
// TODO (stubs)
|
||||
|
||||
@@ -16,7 +16,13 @@
|
||||
|
||||
package org.jetbrains.jet.codegen;
|
||||
|
||||
import jet.JetObject;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
public class AnnotationGenTest extends CodegenTestCase {
|
||||
@@ -70,4 +76,48 @@ public class AnnotationGenTest extends CodegenTestCase {
|
||||
Deprecated annotation = (Deprecated) aClass.getAnnotation(Deprecated.class);
|
||||
assertNotNull(annotation);
|
||||
}
|
||||
}
|
||||
|
||||
public void testSimplestAnnotationClass() throws NoSuchFieldException, NoSuchMethodException {
|
||||
loadText("annotation class A");
|
||||
Class aClass = generateClass("A");
|
||||
Class[] interfaces = aClass.getInterfaces();
|
||||
assertEquals(2, interfaces.length);
|
||||
assertEquals(0, aClass.getDeclaredMethods().length);
|
||||
assertTrue(Annotation.class == interfaces[0] || Annotation.class == interfaces[1]);
|
||||
assertTrue(JetObject.class == interfaces[0] || JetObject.class == interfaces[1]);
|
||||
assertTrue(aClass.isAnnotation());
|
||||
}
|
||||
|
||||
public void testAnnotationClassWithStringProperty()
|
||||
throws
|
||||
NoSuchFieldException,
|
||||
NoSuchMethodException,
|
||||
ClassNotFoundException,
|
||||
IllegalAccessException,
|
||||
InstantiationException,
|
||||
InvocationTargetException {
|
||||
loadText("import java.lang.annotation.*\n" +
|
||||
"" +
|
||||
"Retention(RetentionPolicy.RUNTIME) annotation class A(val a: String)\n" +
|
||||
"" +
|
||||
"A(\"239\") class B()");
|
||||
Class aClass = generateClass("A");
|
||||
|
||||
Retention annotation = (Retention)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));
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,8 @@ import org.jetbrains.jet.lang.psi.JetPsiUtil;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.MalformedURLException;
|
||||
@@ -164,4 +166,107 @@ public class StdlibTest extends CodegenTestCase {
|
||||
loader.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public void testAnnotationClassWithClassProperty()
|
||||
throws
|
||||
NoSuchFieldException,
|
||||
NoSuchMethodException,
|
||||
ClassNotFoundException,
|
||||
IllegalAccessException,
|
||||
InstantiationException,
|
||||
InvocationTargetException {
|
||||
loadText("import java.lang.annotation.*\n" +
|
||||
"" +
|
||||
"Retention(RetentionPolicy.RUNTIME) annotation class A(val a: java.lang.Class<*>)\n" +
|
||||
"" +
|
||||
"A(javaClass<String>()) class B()");
|
||||
Class aClass = generateClass("A");
|
||||
|
||||
Retention annotation = (Retention)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(Class.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(String.class, methods[0].invoke(bClassAnnotation));
|
||||
}
|
||||
|
||||
public void testAnnotationClassWithStringArrayProperty()
|
||||
throws
|
||||
NoSuchFieldException,
|
||||
NoSuchMethodException,
|
||||
ClassNotFoundException,
|
||||
IllegalAccessException,
|
||||
InstantiationException,
|
||||
InvocationTargetException {
|
||||
loadText("import java.lang.annotation.*\n" +
|
||||
"" +
|
||||
"Retention(RetentionPolicy.RUNTIME) annotation class A(val a: Array<String>)\n" +
|
||||
"" +
|
||||
"A(array(\"239\",\"932\")) class B()");
|
||||
Class aClass = generateClass("A");
|
||||
|
||||
Retention annotation = (Retention)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
|
||||
NoSuchFieldException,
|
||||
NoSuchMethodException,
|
||||
ClassNotFoundException,
|
||||
IllegalAccessException,
|
||||
InstantiationException,
|
||||
InvocationTargetException {
|
||||
loadText("import java.lang.annotation.*\n" +
|
||||
"" +
|
||||
"Retention(RetentionPolicy.RUNTIME) annotation class A(val a: IntArray)\n" +
|
||||
"" +
|
||||
"A(intArray(239,932)) class B()");
|
||||
Class aClass = generateClass("A");
|
||||
|
||||
Retention annotation = (Retention)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]);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user