Fixes issue 2033. Leveraged JDT's computed constant value for an expression instead of the actual written expression. Also dealt with:
* Implicit conversion of primitives in the annotation value expressions.
* Implicit array initializers in default annotation value expressions.
* Erroneous assertions in the AnnotationProxyInvocationHandler when the return type was a primitive.
Found by: tobyr
Patch by: mmendez
Review by: jat
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@1796 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/dev/jdt/AnnotationProxyFactory.java b/dev/core/src/com/google/gwt/dev/jdt/AnnotationProxyFactory.java
index c93536a..c7a9e03 100644
--- a/dev/core/src/com/google/gwt/dev/jdt/AnnotationProxyFactory.java
+++ b/dev/core/src/com/google/gwt/dev/jdt/AnnotationProxyFactory.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2007 Google Inc.
+ * Copyright 2008 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
@@ -40,6 +40,40 @@
private static class AnnotationProxyInvocationHandler implements
InvocationHandler {
/**
+ * Returns <code>true</code> if the expected return type is assignable from
+ * the actual return type or if the expected return type is a primitive and
+ * the actual return type is the corresponding wrapper type.
+ */
+ private static boolean isValidReturnType(Class<?> expectedReturnType,
+ Class<? extends Object> actualReturnType) {
+ if (expectedReturnType.isAssignableFrom(actualReturnType)) {
+ return true;
+ }
+
+ if (expectedReturnType.isPrimitive()) {
+ if (expectedReturnType == boolean.class) {
+ return actualReturnType == Boolean.class;
+ } else if (expectedReturnType == byte.class) {
+ return actualReturnType == Byte.class;
+ } else if (expectedReturnType == char.class) {
+ return actualReturnType == Character.class;
+ } else if (expectedReturnType == double.class) {
+ return actualReturnType == Double.class;
+ } else if (expectedReturnType == float.class) {
+ return actualReturnType == Float.class;
+ } else if (expectedReturnType == int.class) {
+ return actualReturnType == Integer.class;
+ } else if (expectedReturnType == long.class) {
+ return actualReturnType == Long.class;
+ } else if (expectedReturnType == short.class) {
+ return actualReturnType == Short.class;
+ }
+ }
+
+ return false;
+ }
+
+ /**
* The resolved class of this annotation.
*/
private Class<? extends Annotation> annotationClass;
@@ -183,26 +217,30 @@
String name = method.getName();
- // See if the value was explicitly declared
- Object value = identifierToValue.get(name);
+ Object value = null;
+ if (identifierToValue.containsKey(name)) {
+ // The value was explicitly provided
+ value = identifierToValue.get(name);
+ assert (value != null);
+ } else {
+ JMethod jMethod = annotationType.findMethod(name, new JType[0]);
+ if (jMethod != null) {
+ // The value will be the default value.
+ JAnnotationMethod annotationMethod = jMethod.isAnnotationMethod();
+ assert (annotationMethod != null);
+ value = annotationMethod.getDefaultValue();
+ assert (value != null);
+ } else if (method.getDeclaringClass() == Annotation.class
+ && "annotationType".equals(method.getName())) {
+ value = annotationClass;
+ }
+ }
+
if (value != null) {
- assert (method.getReturnType().isAssignableFrom(value.getClass()));
+ assert (isValidReturnType(method.getReturnType(), value.getClass()));
return value;
}
- // Try to find a method on the interface.
- JMethod jMethod = annotationType.findMethod(name, new JType[0]);
- if (jMethod != null) {
- JAnnotationMethod annotationMethod = jMethod.isAnnotationMethod();
- assert (annotationMethod != null);
- return annotationMethod.getDefaultValue();
- }
-
- if (method.getDeclaringClass() == Annotation.class
- && "annotationType".equals(method.getName())) {
- return annotationClass;
- }
-
/*
* Maybe it's an Object method, just delegate to myself.
*/
diff --git a/dev/core/src/com/google/gwt/dev/jdt/TypeOracleBuilder.java b/dev/core/src/com/google/gwt/dev/jdt/TypeOracleBuilder.java
index 12056ea..2c7f5ec 100644
--- a/dev/core/src/com/google/gwt/dev/jdt/TypeOracleBuilder.java
+++ b/dev/core/src/com/google/gwt/dev/jdt/TypeOracleBuilder.java
@@ -44,8 +44,8 @@
import com.google.gwt.core.ext.typeinfo.TypeOracle;
import com.google.gwt.dev.jdt.CacheManager.Mapper;
import com.google.gwt.dev.util.Empty;
-import com.google.gwt.dev.util.Util;
import com.google.gwt.dev.util.PerfLogger;
+import com.google.gwt.dev.util.Util;
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.core.compiler.IProblem;
@@ -60,21 +60,13 @@
import org.eclipse.jdt.internal.compiler.ast.ClassLiteralAccess;
import org.eclipse.jdt.internal.compiler.ast.Clinit;
import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
-import org.eclipse.jdt.internal.compiler.ast.ConditionalExpression;
import org.eclipse.jdt.internal.compiler.ast.Expression;
-import org.eclipse.jdt.internal.compiler.ast.FalseLiteral;
import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
import org.eclipse.jdt.internal.compiler.ast.Initializer;
import org.eclipse.jdt.internal.compiler.ast.Javadoc;
-import org.eclipse.jdt.internal.compiler.ast.MagicLiteral;
import org.eclipse.jdt.internal.compiler.ast.MemberValuePair;
import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;
import org.eclipse.jdt.internal.compiler.ast.NameReference;
-import org.eclipse.jdt.internal.compiler.ast.NullLiteral;
-import org.eclipse.jdt.internal.compiler.ast.NumberLiteral;
-import org.eclipse.jdt.internal.compiler.ast.SingleMemberAnnotation;
-import org.eclipse.jdt.internal.compiler.ast.StringLiteral;
-import org.eclipse.jdt.internal.compiler.ast.TrueLiteral;
import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
import org.eclipse.jdt.internal.compiler.ast.TypeParameter;
import org.eclipse.jdt.internal.compiler.ast.TypeReference;
@@ -104,7 +96,6 @@
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Array;
-import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
@@ -301,13 +292,6 @@
}
}
- /**
- * Returns the number associated with a JDT numeric literal.
- */
- private static Object getNumericLiteralValue(NumberLiteral expression) {
- return getConstantValue(expression.constant);
- }
-
private static boolean isAnnotation(TypeDeclaration typeDecl) {
if (typeDecl.kind() == IGenericType.ANNOTATION_TYPE_DECL) {
return true;
@@ -660,32 +644,21 @@
// Value
Expression expressionValue = mvp.value;
- Object value = evaluateConstantExpression(logger, expressionValue);
- if (value == null) {
+ TypeBinding expectedElementValueType = mvp.binding.returnType;
+ Object elementValue = getAnnotationElementValue(logger,
+ expectedElementValueType, expressionValue);
+ if (elementValue == null) {
return null;
}
- try {
- Method method = clazz.getMethod(identifier, new Class[0]);
- Class<?> expectedClass = method.getReturnType();
- Class<? extends Object> actualClass = value.getClass();
- if (expectedClass.isArray() && !actualClass.isArray()) {
- /*
- * JSL3 Section 9.7 single element annotations can skip the curly
- * braces; means we do not get an array
- */
- assert (expression instanceof SingleMemberAnnotation);
- Object array = Array.newInstance(expectedClass.getComponentType(), 1);
- Array.set(array, 0, value);
- value = array;
- }
- } catch (SecurityException e) {
- return null;
- } catch (NoSuchMethodException e) {
- return null;
- }
+ /*
+ * If the expected value is supposed to be an array then the element value
+ * had better be an array.
+ */
+ assert (expectedElementValueType.isArrayType() == false || expectedElementValueType.isArrayType()
+ && elementValue.getClass().isArray());
- identifierToValue.put(identifier, value);
+ identifierToValue.put(identifier, elementValue);
}
// Create the Annotation proxy
@@ -698,43 +671,6 @@
identifierToValue);
}
- private Object createArrayConstant(TreeLogger logger,
- ArrayInitializer arrayInitializer) {
- Class<?> leafComponentClass = getClassLiteral(logger,
- arrayInitializer.binding.leafComponentType);
- if (leafComponentClass == null) {
- return null;
- }
-
- int[] dimensions = new int[arrayInitializer.binding.dimensions];
-
- Expression[] initExpressions = arrayInitializer.expressions;
- if (initExpressions != null) {
- dimensions[0] = initExpressions.length;
- }
-
- Object array = Array.newInstance(leafComponentClass, dimensions);
- boolean failed = false;
- if (initExpressions != null) {
- for (int i = 0; i < initExpressions.length; ++i) {
- Expression arrayInitExp = initExpressions[i];
- Object value = evaluateConstantExpression(logger, arrayInitExp);
- if (value != null) {
- Array.set(array, i, value);
- } else {
- failed = true;
- break;
- }
- }
- }
-
- if (!failed) {
- return array;
- }
-
- return null;
- }
-
private JUpperBound createTypeParameterBounds(TreeLogger logger,
TypeVariableBinding tvBinding) {
TypeBinding firstBound = tvBinding.firstBound;
@@ -813,69 +749,136 @@
return jtypeParamArray;
}
- private Object evaluateConstantExpression(TreeLogger logger,
- Expression expression) {
- if (expression instanceof MagicLiteral) {
- if (expression instanceof FalseLiteral) {
- return Boolean.FALSE;
- } else if (expression instanceof NullLiteral) {
- // null is not a valid annotation value; JLS Third Ed. Section 9.7
- } else if (expression instanceof TrueLiteral) {
- return Boolean.TRUE;
- }
- } else if (expression instanceof NumberLiteral) {
- Object value = getNumericLiteralValue((NumberLiteral) expression);
- if (value != null) {
- return value;
- }
- } else if (expression instanceof StringLiteral) {
- StringLiteral stringLiteral = (StringLiteral) expression;
- return stringLiteral.constant.stringValue();
- } else if (expression instanceof ClassLiteralAccess) {
- ClassLiteralAccess classLiteral = (ClassLiteralAccess) expression;
- Class<?> clazz = getClassLiteral(logger, classLiteral.targetType);
- if (clazz != null) {
- return clazz;
- }
- } else if (expression instanceof ArrayInitializer) {
- Object value = createArrayConstant(logger, (ArrayInitializer) expression);
- if (value != null) {
- return value;
- }
- } else if (expression instanceof NameReference) {
+ /**
+ * Returns an annotation element value as defined in JLS 3.0 section 9.7.
+ *
+ * @param logger
+ * @param expectedElementValueType the expected element value type
+ * @param elementValueExpression the expression that defines the element value
+ *
+ * @return annotation element value as defined in JLS 3.0 section 9.7
+ */
+ private Object getAnnotationElementValue(TreeLogger logger,
+ TypeBinding expectedElementValueType, Expression elementValueExpression) {
+
+ Object elementValue = null;
+
+ if (elementValueExpression.constant != null
+ && elementValueExpression.constant != Constant.NotAConstant) {
/*
- * This name reference can only be to something that is a constant value,
- * or an enumerated type since annotation values must be constants.
+ * Rely on JDT's computed constant value to deal with an
+ * AnnotationElementValue expression whose resolved type is a primitive or
+ * a string.
*/
- NameReference nameRef = (NameReference) expression;
+ Constant constant = elementValueExpression.constant;
+ int expectedTypeId = expectedElementValueType.id;
- if (nameRef.constant != Constant.NotAConstant) {
- return getConstantValue(nameRef.constant);
- } else {
- Class clazz = getClassLiteral(logger, nameRef.actualReceiverType);
- if (clazz.isEnum()) {
- String enumName = String.valueOf(nameRef.fieldBinding().name);
- return Enum.valueOf(clazz, enumName);
- } else {
- /*
- * If this is not an enumeration, then fall through to failure case
- * below.
- */
- }
- }
- } else if (expression instanceof Annotation) {
- Object annotationInstance = createAnnotationInstance(logger, expression);
- if (annotationInstance != null) {
- return annotationInstance;
- }
- } else if (expression instanceof ConditionalExpression) {
- ConditionalExpression condExpression = (ConditionalExpression) expression;
- assert (condExpression.constant != Constant.NotAConstant);
+ if (expectedElementValueType.isArrayType()) {
+ /*
+ * This can happen when an element value is an array with a single
+ * element. In this case JLS 3.0 section 9.7 allows for the
+ * ArrayInitializer expression to be implicit. Since, element values can
+ * only be single dimensional arrays, we take the leaf type of the
+ * expected array type as our resultant element value type.
+ */
+ assert (!elementValueExpression.resolvedType.isArrayType() && expectedElementValueType.dimensions() == 1);
- return getConstantValue(condExpression.constant);
+ expectedTypeId = expectedElementValueType.leafComponentType().id;
+ }
+
+ if (elementValueExpression.resolvedType.id != expectedTypeId) {
+ /*
+ * Narrowing and widening conversions are handled by the following
+ * Constant.castTo call. JDT wants the upper four bits of this mask to
+ * be the target type id and the lower four bits to be the source type
+ * id. See Constant.castTo for more details.
+ */
+ constant = constant.castTo((expectedTypeId << 4)
+ + elementValueExpression.resolvedType.id);
+ }
+
+ elementValue = getConstantValue(constant);
+ } else if (elementValueExpression instanceof ClassLiteralAccess) {
+ ClassLiteralAccess classLiteral = (ClassLiteralAccess) elementValueExpression;
+ elementValue = getClassLiteral(logger, classLiteral.targetType);
+ } else if (elementValueExpression instanceof ArrayInitializer) {
+ elementValue = getAnnotationElementValueArray(logger,
+ (ArrayInitializer) elementValueExpression);
+ } else if (elementValueExpression instanceof NameReference) {
+ /*
+ * Any primitive types, conditionals, strings, arrays and name references
+ * to constant fields will have all been handled by the constant
+ * expression block above. This name reference can only be for an
+ * enumerated type.
+ */
+ NameReference nameRef = (NameReference) elementValueExpression;
+
+ assert (nameRef.constant == null || nameRef.constant == Constant.NotAConstant);
+ assert (nameRef.actualReceiverType.isEnum());
+
+ Class<?> clazz = getClassLiteral(logger, nameRef.actualReceiverType);
+ Class<? extends Enum> enumClass = clazz.asSubclass(Enum.class);
+
+ String enumName = String.valueOf(nameRef.fieldBinding().name);
+ elementValue = Enum.valueOf(enumClass, enumName);
+ } else if (elementValueExpression instanceof Annotation) {
+ elementValue = createAnnotationInstance(logger, elementValueExpression);
+ } else {
+ assert (false);
+ return null;
}
- assert (false);
+ assert (elementValue != null);
+
+ if (expectedElementValueType.isArrayType()
+ && !elementValue.getClass().isArray()) {
+ /*
+ * Handle single element arrays where no explicit array initializer was
+ * given.
+ */
+ Object array = Array.newInstance(elementValue.getClass(), 1);
+ Array.set(array, 0, elementValue);
+ elementValue = array;
+ }
+
+ return elementValue;
+ }
+
+ /**
+ * Returns an annotation element value array. These arrays can only have a
+ * single dimension.
+ */
+ private Object getAnnotationElementValueArray(TreeLogger logger,
+ ArrayInitializer arrayInitializer) {
+ assert (arrayInitializer.binding.dimensions == 1);
+
+ Class<?> leafComponentClass = getClassLiteral(logger,
+ arrayInitializer.binding.leafComponentType);
+ if (leafComponentClass == null) {
+ return null;
+ }
+
+ Expression[] initExpressions = arrayInitializer.expressions;
+ int arrayLength = initExpressions != null ? initExpressions.length : 0;
+
+ Object array = Array.newInstance(leafComponentClass, arrayLength);
+ boolean failed = false;
+ for (int i = 0; i < arrayLength; ++i) {
+ Expression arrayInitExp = initExpressions[i];
+ Object value = getAnnotationElementValue(logger,
+ arrayInitializer.binding.leafComponentType, arrayInitExp);
+ if (value != null) {
+ Array.set(array, i, value);
+ } else {
+ failed = true;
+ break;
+ }
+ }
+
+ if (!failed) {
+ return array;
+ }
+
return null;
}
@@ -1209,7 +1212,8 @@
AnnotationMethodDeclaration annotationMethod = (AnnotationMethodDeclaration) jmethod;
Object defaultValue = null;
if (annotationMethod.defaultValue != null) {
- defaultValue = evaluateConstantExpression(logger,
+ defaultValue = getAnnotationElementValue(logger,
+ annotationMethod.returnType.resolvedType,
annotationMethod.defaultValue);
}
method = new JAnnotationMethod(enclosingType, name, declStart, declEnd,
diff --git a/dev/core/test/com/google/gwt/core/ext/typeinfo/TypeOracleAnnotationSupportTest.java b/dev/core/test/com/google/gwt/core/ext/typeinfo/TypeOracleAnnotationSupportTest.java
index 3158eb9..6da80ab 100644
--- a/dev/core/test/com/google/gwt/core/ext/typeinfo/TypeOracleAnnotationSupportTest.java
+++ b/dev/core/test/com/google/gwt/core/ext/typeinfo/TypeOracleAnnotationSupportTest.java
@@ -20,6 +20,8 @@
import com.google.gwt.core.ext.typeinfo.test.AnnotatedClass;
import com.google.gwt.core.ext.typeinfo.test.ClassAnnotatedWithBinaryOnlyAnnotation;
import com.google.gwt.core.ext.typeinfo.test.ClassLiteralReferenceAnnotation;
+import com.google.gwt.core.ext.typeinfo.test.PrimitiveValuesAnnotation;
+import com.google.gwt.core.ext.typeinfo.test.PrimitivesAnnotatedClass;
import com.google.gwt.core.ext.typeinfo.test.TestAnnotation;
import com.google.gwt.dev.cfg.ModuleDef;
import com.google.gwt.dev.cfg.ModuleDefLoader;
@@ -73,6 +75,17 @@
// Tests default value that is a class literal.
assertEquals(realAnnotation.classLiteral(), testAnnotation.classLiteral());
+
+ // Tests implicit array initializers
+ Class<?>[] expectedArrayValue = realAnnotation.arrayWithImplicitArrayInitializer();
+ Class<?>[] actualArrayValue = testAnnotation.arrayWithImplicitArrayInitializer();
+ assertTrue(expectedArrayValue.length > 0);
+ assertEquals(expectedArrayValue.length, actualArrayValue.length);
+ assertEquals(expectedArrayValue[0], actualArrayValue[0]);
+
+ // Tests that empty array initializers are also handled correctly.
+ assertEquals(realAnnotation.emptyArray().length,
+ testAnnotation.emptyArray().length);
}
private final TreeLogger logger = TreeLogger.NULL;
@@ -191,4 +204,37 @@
assertNull(classType.getAnnotation(BinaryOnlyAnnotation.class));
}
+
+ /**
+ * Ensures that we properly handle primitive value attributes on annotations.
+ * (Special-cased, because of how JDT handles char/numeric literals)
+ */
+ public void testPrimitiveValuesAnnotations() throws NotFoundException {
+ JClassType primitivesAnnotatedClass = typeOracle.getType(PrimitivesAnnotatedClass.class.getName());
+ PrimitiveValuesAnnotation annotation = primitivesAnnotatedClass.getAnnotation(PrimitiveValuesAnnotation.class);
+
+ boolean bool = annotation.bool();
+ assertTrue(bool);
+
+ byte b = annotation.b();
+ assertTrue(b > 0);
+
+ char c = annotation.c();
+ assertTrue(c > 0);
+
+ double d = annotation.d();
+ assertTrue(d > 0);
+
+ float f = annotation.f();
+ assertTrue(f > 0);
+
+ int i = annotation.i();
+ assertTrue(i > 0);
+
+ long l = annotation.l();
+ assertTrue(l > 0);
+
+ short s = annotation.s();
+ assertTrue(s > 0);
+ }
}
diff --git a/dev/core/test/com/google/gwt/core/ext/typeinfo/test/PrimitiveValuesAnnotation.java b/dev/core/test/com/google/gwt/core/ext/typeinfo/test/PrimitiveValuesAnnotation.java
new file mode 100644
index 0000000..22fd71f
--- /dev/null
+++ b/dev/core/test/com/google/gwt/core/ext/typeinfo/test/PrimitiveValuesAnnotation.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2008 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.core.ext.typeinfo.test;
+
+import java.io.Serializable;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Test annotation containing primitive values.
+ *
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+public @interface PrimitiveValuesAnnotation {
+ boolean bool() default true;
+
+ byte b() default 0;
+
+ char c() default '\0';
+
+ short s() default 0;
+
+ int i() default 0;
+
+ long l() default 0;
+
+ float f() default 0;
+
+ double d() default 0;
+
+ int[] ia() default {};
+}
diff --git a/dev/core/test/com/google/gwt/core/ext/typeinfo/test/PrimitivesAnnotatedClass.java b/dev/core/test/com/google/gwt/core/ext/typeinfo/test/PrimitivesAnnotatedClass.java
new file mode 100644
index 0000000..bd4b377
--- /dev/null
+++ b/dev/core/test/com/google/gwt/core/ext/typeinfo/test/PrimitivesAnnotatedClass.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2008 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.core.ext.typeinfo.test;
+
+/**
+ * Test class for annotations with primitive values.
+ *
+ */
+@PrimitiveValuesAnnotation(b = PrimitivesAnnotatedClass.byteAsInt,
+ c = (byte) 12, s = 'a', i = (short) 1452,
+ l = 12345, f = (byte) 15, d = 123412312L)
+public class PrimitivesAnnotatedClass {
+ static final int byteAsInt = 123;
+}
+
diff --git a/dev/core/test/com/google/gwt/core/ext/typeinfo/test/TestAnnotation.java b/dev/core/test/com/google/gwt/core/ext/typeinfo/test/TestAnnotation.java
index bb88bfc..e776051 100644
--- a/dev/core/test/com/google/gwt/core/ext/typeinfo/test/TestAnnotation.java
+++ b/dev/core/test/com/google/gwt/core/ext/typeinfo/test/TestAnnotation.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2007 Google Inc.
+ * Copyright 2008 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
@@ -33,16 +33,6 @@
ElementType.TYPE})
public @interface TestAnnotation {
/**
- * Default value for the annotation.
- */
- String value();
-
- /**
- * Tests element default values that are themselves annotations.
- */
- NestedAnnotation nestedAnnotation() default @NestedAnnotation("Not assigned");
-
- /**
* Used to test initialization using conditional statements.
*/
boolean useMinLong = true;
@@ -51,11 +41,21 @@
* Used to test initialization using SingleNameReferences.
*/
String defaultStringValue = "Hello There";
+
+ /**
+ * Tests that implicit array initializers are handled correctly.
+ */
+ Class<?>[] arrayWithImplicitArrayInitializer() default Object.class;
+
+ /**
+ * Tests default value initialization of class literals.
+ */
+ Class<?> classLiteral() default Object.class;
/**
- * Tests default values using conditional statements.
+ * Tests that an empty array initializer is handled correctly.
*/
- long longValue() default useMinLong ? Long.MIN_VALUE : Long.MAX_VALUE;
+ int[] emptyArray() default {};
/**
* Tests array default values.
@@ -63,13 +63,23 @@
int[] intArrayValue() default {1,2,3};
/**
+ * Tests default values using conditional statements.
+ */
+ long longValue() default useMinLong ? Long.MIN_VALUE : Long.MAX_VALUE;
+
+ /**
+ * Tests element default values that are themselves annotations.
+ */
+ NestedAnnotation nestedAnnotation() default @NestedAnnotation("Not assigned");
+
+ /**
* Tests default value initialization via a QualifiedNameReference.
*/
String stringValue() default TestAnnotation.defaultStringValue;
-
+
/**
- * Tests default value initialization of class literals.
+ * Default value for the annotation.
*/
- Class<?> classLiteral() default Object.class;
+ String value();
}