From 8daba1f09fd8196118607b3141bf13c072ef23a1 Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Fri, 19 Jun 2015 19:42:06 +0400 Subject: [PATCH] Add support of annotation fields and default values --- .../org/teavm/classlib/java/lang/TClass.java | 2 +- .../java/lang/annotation/TAnnotation.java | 4 ++++ .../reflect/AnnotationClassTransformer.java | 8 ++++--- .../reflect/AnnotationDependencyListener.java | 6 ++++++ .../cache/DiskCachedClassHolderSource.java | 14 ++++++++----- .../java/org/teavm/model/AnnotationValue.java | 6 +++--- .../java/org/teavm/model/MethodHolder.java | 12 ++++++++++- .../java/org/teavm/model/MethodReader.java | 2 ++ .../java/org/teavm/model/util/ModelUtils.java | 3 +++ .../main/java/org/teavm/parsing/Parser.java | 3 +++ .../teavm/classlib/java/lang/ClassTest.java | 21 +++++++++++++++++++ 11 files changed, 68 insertions(+), 13 deletions(-) diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TClass.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TClass.java index 01598c839..662f9bcd3 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TClass.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/TClass.java @@ -237,7 +237,7 @@ public class TClass extends TObject implements TAnnotatedElement { } annotationsByType = new HashMap<>(); for (TAnnotation annot : getAnnotations()) { - annotationsByType.put((TClass)(Object)annot.getClass(), annot); + annotationsByType.put((TClass)(Object)annot.annotationType(), annot); } } } diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/annotation/TAnnotation.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/annotation/TAnnotation.java index f33747d15..ad8c330b5 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/annotation/TAnnotation.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/annotation/TAnnotation.java @@ -15,9 +15,13 @@ */ package org.teavm.classlib.java.lang.annotation; +import org.teavm.javascript.spi.Rename; + /** * * @author Alexey Andreev */ public @interface TAnnotation { + @Rename("annotationType") + Class annotationType0(); } diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/reflect/AnnotationClassTransformer.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/reflect/AnnotationClassTransformer.java index bd41e8df4..f83417120 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/reflect/AnnotationClassTransformer.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/reflect/AnnotationClassTransformer.java @@ -85,9 +85,11 @@ public class AnnotationClassTransformer implements ClassHolderTransformer { List params = new ArrayList<>(); for (MethodReader methodDecl : annotationClass.getMethods()) { ctorSignature.add(methodDecl.getResultType()); - AnnotationValue value = annotation.getValue(className); - params.add(value != null ? generateAnnotationValue(classSource, pe, methodDecl.getResultType(), value) : - pe.constantNull()); + AnnotationValue value = annotation.getValue(methodDecl.getName()); + if (value == null) { + value = methodDecl.getAnnotationDefault(); + } + params.add(generateAnnotationValue(classSource, pe, methodDecl.getResultType(), value)); } ctorSignature.add(ValueType.VOID); diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/reflect/AnnotationDependencyListener.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/reflect/AnnotationDependencyListener.java index 3a8be55ea..8838c74ec 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/reflect/AnnotationDependencyListener.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/lang/reflect/AnnotationDependencyListener.java @@ -122,6 +122,12 @@ public class AnnotationDependencyListener implements DependencyListener { pe.exit(); implementor.addMethod(ctor); + MethodHolder annotTypeMethod = new MethodHolder("annotationType", ValueType.parse(Class.class)); + pe = ProgramEmitter.create(annotTypeMethod); + pe.wrapNew(); + pe.constant(ValueType.object(annotationType)).returnValue(); + implementor.addMethod(annotTypeMethod); + return implementor; } diff --git a/teavm-core/src/main/java/org/teavm/cache/DiskCachedClassHolderSource.java b/teavm-core/src/main/java/org/teavm/cache/DiskCachedClassHolderSource.java index 4f8ec49f8..b513194e0 100644 --- a/teavm-core/src/main/java/org/teavm/cache/DiskCachedClassHolderSource.java +++ b/teavm-core/src/main/java/org/teavm/cache/DiskCachedClassHolderSource.java @@ -239,12 +239,16 @@ public class DiskCachedClassHolderSource implements ClassHolderSource { } } - private void writeAnnotation(DataOutput output, AnnotationHolder annotation) throws IOException { + private void writeAnnotation(DataOutput output, AnnotationReader annotation) throws IOException { output.writeInt(symbolTable.lookup(annotation.getType())); - output.writeShort(annotation.getValues().size()); - for (Map.Entry entry : annotation.getValues().entrySet()) { - output.writeInt(symbolTable.lookup(entry.getKey())); - writeAnnotationValue(output, entry.getValue()); + int fieldCount = 0; + for (@SuppressWarnings("unused") String field : annotation.getAvailableFields()) { + ++fieldCount; + } + output.writeShort(fieldCount); + for (String field : annotation.getAvailableFields()) { + output.writeInt(symbolTable.lookup(field)); + writeAnnotationValue(output, annotation.getValue(field)); } } diff --git a/teavm-core/src/main/java/org/teavm/model/AnnotationValue.java b/teavm-core/src/main/java/org/teavm/model/AnnotationValue.java index 3efcf9d89..e112a94a3 100644 --- a/teavm-core/src/main/java/org/teavm/model/AnnotationValue.java +++ b/teavm-core/src/main/java/org/teavm/model/AnnotationValue.java @@ -88,7 +88,7 @@ public class AnnotationValue { this.value = value; } - public AnnotationValue(AnnotationHolder value) { + public AnnotationValue(AnnotationReader value) { this.type = ANNOTATION; this.value = value; } @@ -176,11 +176,11 @@ public class AnnotationValue { return (FieldReference)value; } - public AnnotationHolder getAnnotation() { + public AnnotationReader getAnnotation() { if (type != ANNOTATION) { throw new IllegalStateException("There is no annotation value"); } - return (AnnotationHolder)value; + return (AnnotationReader)value; } public byte getType() { diff --git a/teavm-core/src/main/java/org/teavm/model/MethodHolder.java b/teavm-core/src/main/java/org/teavm/model/MethodHolder.java index 345a1314a..d55ad57c6 100644 --- a/teavm-core/src/main/java/org/teavm/model/MethodHolder.java +++ b/teavm-core/src/main/java/org/teavm/model/MethodHolder.java @@ -22,7 +22,8 @@ package org.teavm.model; public class MethodHolder extends MemberHolder implements MethodReader { private MethodDescriptor descriptor; private ClassHolder owner; - private volatile Program program; + private Program program; + private AnnotationValue annotationDefault; public MethodHolder(MethodDescriptor descriptor) { super(descriptor.getName()); @@ -95,4 +96,13 @@ public class MethodHolder extends MemberHolder implements MethodReader { this.program.setMethod(this); } } + + @Override + public AnnotationValue getAnnotationDefault() { + return annotationDefault; + } + + public void setAnnotationDefault(AnnotationValue annotationDefault) { + this.annotationDefault = annotationDefault; + } } diff --git a/teavm-core/src/main/java/org/teavm/model/MethodReader.java b/teavm-core/src/main/java/org/teavm/model/MethodReader.java index 152767e27..edceb3d90 100644 --- a/teavm-core/src/main/java/org/teavm/model/MethodReader.java +++ b/teavm-core/src/main/java/org/teavm/model/MethodReader.java @@ -35,4 +35,6 @@ public interface MethodReader extends MemberReader { MethodReference getReference(); ProgramReader getProgram(); + + AnnotationValue getAnnotationDefault(); } diff --git a/teavm-core/src/main/java/org/teavm/model/util/ModelUtils.java b/teavm-core/src/main/java/org/teavm/model/util/ModelUtils.java index 9fb039bc7..cfde95dde 100644 --- a/teavm-core/src/main/java/org/teavm/model/util/ModelUtils.java +++ b/teavm-core/src/main/java/org/teavm/model/util/ModelUtils.java @@ -52,6 +52,9 @@ public final class ModelUtils { copy.setProgram(ProgramUtils.copy(method.getProgram())); } copyAnnotations(method.getAnnotations(), copy.getAnnotations()); + if (method.getAnnotationDefault() != null) { + copy.setAnnotationDefault(copyAnnotationValue(method.getAnnotationDefault())); + } return copy; } diff --git a/teavm-core/src/main/java/org/teavm/parsing/Parser.java b/teavm-core/src/main/java/org/teavm/parsing/Parser.java index d48165e5b..e43eb2f2d 100644 --- a/teavm-core/src/main/java/org/teavm/parsing/Parser.java +++ b/teavm-core/src/main/java/org/teavm/parsing/Parser.java @@ -53,6 +53,9 @@ public final class Parser { while (program.variableCount() <= method.parameterCount()) { program.createVariable(); } + if (node.annotationDefault != null) { + method.setAnnotationDefault(parseAnnotationValue(node.annotationDefault)); + } return method; } diff --git a/teavm-tests/src/test/java/org/teavm/classlib/java/lang/ClassTest.java b/teavm-tests/src/test/java/org/teavm/classlib/java/lang/ClassTest.java index 95d2a4fea..29abcf039 100644 --- a/teavm-tests/src/test/java/org/teavm/classlib/java/lang/ClassTest.java +++ b/teavm-tests/src/test/java/org/teavm/classlib/java/lang/ClassTest.java @@ -119,11 +119,32 @@ public class ClassTest { assertTrue(TestAnnot.class.isAssignableFrom(annotations[0].getClass())); } + @Test + public void annotationFieldsExposed() { + AnnotWithDefaultField annot = B.class.getAnnotation(AnnotWithDefaultField.class); + assertEquals(2, annot.x()); + annot = C.class.getAnnotation(AnnotWithDefaultField.class); + assertEquals(3, annot.x()); + } + @TestAnnot private static class A { } + @AnnotWithDefaultField + private static class B { + } + + @AnnotWithDefaultField(x = 3) + private static class C { + } + @Retention(RetentionPolicy.RUNTIME) static @interface TestAnnot { } + + @Retention(RetentionPolicy.RUNTIME) + static @interface AnnotWithDefaultField { + int x() default 2; + } }