blob: 129981c7ea69c3094d15063edc2fdd58be1eeda9 [file] [log] [blame]
/*
* Copyright 2010 Google Inc.
*
* 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 com.google.gwt.dev.jjs.impl;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.dev.javac.impl.MockJavaResource;
import com.google.gwt.dev.jjs.ast.JAnnotation;
import com.google.gwt.dev.jjs.ast.JClassLiteral;
import com.google.gwt.dev.jjs.ast.JDeclaredType;
import com.google.gwt.dev.jjs.ast.JField;
import com.google.gwt.dev.jjs.ast.JLocal;
import com.google.gwt.dev.jjs.ast.JMethod;
import com.google.gwt.dev.jjs.ast.JParameter;
import com.google.gwt.dev.jjs.ast.JProgram;
import com.google.gwt.dev.jjs.ast.JAnnotation.Property;
import com.google.gwt.dev.jjs.ast.JAnnotation.SourceOnlyClassException;
/**
* Tests AST setup of JAnnotation nodes as well as the reflective proxy for
* accessing their data.
*/
public class JAnnotationTest extends JJSTestBase {
/**
* A test class for binary-only annotations.
*/
public @interface BinaryAnnotation {
Class<?> c() default Object.class;
int i() default 2;
int[] iOne() default 1;
int[] iTwo() default {1, 2};
int[] iZero() default {};
OtherAnnotation[] o() default {
@OtherAnnotation("Hello 1"), @OtherAnnotation("Hello 2")};
String s() default "Hello String";
}
/**
* Used to test binary-only class literal behavior.
*/
public @interface ClassAnnotation {
Class<?> value();
}
/**
* A test case for meta-annotations.
*/
public @interface OtherAnnotation {
String value();
}
private static void assertEquals(int[] a, int[] b) {
assertEquals(a.length, b.length);
for (int i = 0, j = a.length; i < j; i++) {
assertEquals(a[i], b[i]);
}
}
public void setUp() {
// These packages have annotations required by this test
JProgram.RECORDED_ANNOTATION_PACKAGES.add("com.google.gwt.dev.jjs");
JProgram.RECORDED_ANNOTATION_PACKAGES.add("test");
sourceOracle.addOrReplace(new MockJavaResource("test.SourceClassAnnotation") {
@Override
protected CharSequence getContent() {
StringBuffer code = new StringBuffer();
code.append("package test;\n");
code.append("public @interface SourceClassAnnotation {\n");
code.append(" Class<?> value();\n");
code.append("}\n");
return code;
}
});
sourceOracle.addOrReplace(new MockJavaResource("test.Tag") {
@Override
protected CharSequence getContent() {
StringBuffer code = new StringBuffer();
code.append("package test;\n");
code.append("@Tag\n");
code.append("public @interface Tag {\n");
code.append("}\n");
return code;
}
});
sourceOracle.addOrReplace(new MockJavaResource("test.WithTag") {
@Override
protected CharSequence getContent() {
StringBuffer code = new StringBuffer();
code.append("package test;\n");
code.append("@Tag\n");
code.append("public class WithTag {\n");
code.append(" @Tag String field;\n");
code.append(" @Tag WithTag(){}\n");
code.append(" @Tag void method(@Tag String p) {@Tag String local;}\n");
code.append("}\n");
return code;
}
});
sourceOracle.addOrReplace(new MockJavaResource("test.WithBinary") {
@Override
protected CharSequence getContent() {
StringBuffer code = new StringBuffer();
code.append("package test;\n");
code.append("import " + BinaryAnnotation.class.getCanonicalName()
+ ";\n");
code.append("import " + ClassAnnotation.class.getCanonicalName()
+ ";\n");
code.append("import " + OtherAnnotation.class.getCanonicalName()
+ ";\n");
code.append("public class WithBinary {\n");
code.append(" public static final String EXPR = \"Expression\";\n");
code.append(" @ClassAnnotation("
+ JAnnotationTest.class.getCanonicalName() + ".class)\n");
code.append(" void useBinaryClassReference() {}\n");
code.append(" @BinaryAnnotation\n");
code.append(" void useDefaults() {}\n");
code.append(" @SourceClassAnnotation("
+ JAnnotationTest.class.getCanonicalName() + ".class)\n");
code.append(" void useSourceClassAnnotation() {}\n");
code.append(" @BinaryAnnotation(c=Tag.class, i=42, s=\"foo\", o= @OtherAnnotation(\"Hello \" + EXPR))\n");
code.append(" void useValues() {}\n");
code.append("}\n");
return code;
}
});
}
public void testAllElementTypes() throws UnableToCompleteException {
JProgram program = compileSnippet("void", "new test.WithTag();");
// ANNOTATION_TYPE
JDeclaredType tag = findType(program, "test.Tag");
assertEquals(1, tag.getAnnotations().size());
// TYPE
JDeclaredType withTag = findType(program, "test.WithTag");
assertEquals(1, withTag.getAnnotations().size());
// CONSTRUCTOR
JMethod constructor = findMethod(withTag, "WithTag");
assertEquals(1, constructor.getAnnotations().size());
// METHOD
JMethod method = findMethod(withTag, "method");
assertEquals(1, method.getAnnotations().size());
// FIELD
JField field = findField(withTag, "field");
assertEquals(1, field.getAnnotations().size());
// LOCAL_VARIABLE
JLocal local = findLocal(method, "local");
assertEquals(1, local.getAnnotations().size());
// PARAMETER
JParameter param = method.getParams().get(0);
assertEquals(1, param.getAnnotations().size());
// There are no representations for PACKAGE in our AST
}
public void testAnnotationBinaryOnlyClassLiterals()
throws UnableToCompleteException {
JProgram program = compileSnippet("void", "new test.WithBinary();");
JDeclaredType t = findType(program, "test.WithBinary");
JMethod m = findMethod(t, "useBinaryClassReference");
JAnnotation a = JAnnotation.findAnnotation(m,
ClassAnnotation.class.getName());
assertNotNull(a);
ClassAnnotation instance = JAnnotation.createAnnotation(
ClassAnnotation.class, a);
assertSame(JAnnotationTest.class, instance.value());
}
public void testAnnotationProxyCustomValues()
throws UnableToCompleteException {
JProgram program = compileSnippet("void", "new test.WithBinary();");
JDeclaredType t = findType(program, "test.WithBinary");
JMethod useValues = findMethod(t, "useValues");
JAnnotation a = JAnnotation.findAnnotation(useValues,
BinaryAnnotation.class.getName());
assertNotNull(a);
BinaryAnnotation instance = JAnnotation.createAnnotation(
BinaryAnnotation.class, a);
assertNotNull(instance);
// A source-only annotation, unavailable to the JVM
try {
instance.c();
} catch (SourceOnlyClassException e) {
// Expected
assertEquals(findType(program, "test.Tag"), e.getLiteral().getRefType());
}
assertEquals(42, instance.i());
assertEquals("foo", instance.s());
assertEquals(1, instance.o().length);
assertEquals("Hello Expression", instance.o()[0].value());
}
public void testAnnotationProxyDefaultValues()
throws UnableToCompleteException {
JProgram program = compileSnippet("void", "new test.WithBinary();");
JDeclaredType t = findType(program, "test.WithBinary");
JMethod useDefaults = findMethod(t, "useDefaults");
JAnnotation a = JAnnotation.findAnnotation(useDefaults,
BinaryAnnotation.class.getName());
assertNotNull(a);
assertTrue(a.getType().isExternal());
BinaryAnnotation instance = JAnnotation.createAnnotation(
BinaryAnnotation.class, a);
assertNotNull(instance);
// Test Object methods
assertEquals(instance.hashCode(), instance.hashCode());
assertNotNull(instance.toString());
// Test default-valued
assertSame(Object.class, instance.c());
assertEquals(2, instance.i());
assertEquals(new int[] {1}, instance.iOne());
assertEquals(new int[] {1, 2}, instance.iTwo());
assertEquals(new int[] {}, instance.iZero());
assertNotNull(instance.o());
assertEquals(2, instance.o().length);
assertEquals("Hello 1", instance.o()[0].value());
assertEquals("Hello 2", instance.o()[1].value());
assertEquals("Hello String", instance.s());
}
public void testSourceAnnotationWithBinaryClass()
throws UnableToCompleteException {
JProgram program = compileSnippet("void", "new test.WithBinary();");
JDeclaredType t = findType(program, "test.WithBinary");
JMethod m = findMethod(t, "useSourceClassAnnotation");
JAnnotation a = JAnnotation.findAnnotation(m, "test.SourceClassAnnotation");
assertNotNull(a);
Property p = a.getProperty("value");
JClassLiteral literal = (JClassLiteral) p.getSingleValue();
JDeclaredType type = (JDeclaredType) literal.getRefType();
assertTrue(type.isExternal());
assertEquals(JAnnotationTest.class.getName(), type.getName());
}
}