|
Groovy example source code file (AnnotationTest.groovy)
The Groovy AnnotationTest.groovy source code/* * Copyright 2003-2011 the original author or authors. * * 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 gls.annotations import gls.CompilableTestSupport /** * Tests various properties of annotation definitions. * * @author Jochen Theodorou * @author Guillaume Laforge * @author Paul King */ class AnnotationTest extends CompilableTestSupport { /** * Check that it is possible to annotate an annotation definition with field and method target elements. */ void testAnnotateAnnotationDefinitionWithMethodAndFieldTargetElementTypes() { shouldCompile """ import java.lang.annotation.* import static java.lang.annotation.RetentionPolicy.* import static java.lang.annotation.ElementType.* @Retention(RUNTIME) @Target([METHOD, FIELD]) @interface MyAnnotation { } """ } void testCannotAnnotateAnotationDefinitionIfTargetIsNotOfType() { shouldNotCompile """ import java.lang.annotation.* import static java.lang.annotation.ElementType.* // all target elements except ANNOTATION_TYPE @Target([CONSTRUCTOR, METHOD, FIELD, LOCAL_VARIABLE, PACKAGE, PARAMETER, TYPE]) @interface MyAnnotation { } @MyAnnotation @interface AnotherAnnotation {} """ } /** * The @OneToMany cascade parameter takes an array of CascadeType. * To use this annotation in Java with this parameter, you do <code>@OneToMany(cascade = { CascadeType.ALL }) * In Groovy, you do <code>@OneToMany(cascade = [ CascadeType.ALL ]) (brackets instead of braces) * But when there's just one value in the array, the curly braces or brackets can be omitted: * <code>@OneToMany(cascade = [ CascadeType.ALL ]) */ void testOmittingBracketsForSingleValueArrayParameter() { shouldCompile """ import gls.annotations.* class Book {} class Author { @OneToMany(cascade = CascadeType.ALL) Set<Book> books } def annotation = Author.class.getDeclaredField('books').annotations[0] assert annotation instanceof OneToMany assert annotation.cascade() == [CascadeType.ALL] """ } void testPrimitiveDefault() { // NOTE: for int anything else than a plain number will fail. // For example 1l will fail too, even if it could be converted. // If this should be changed, then further discussion is needed. shouldNotCompile """ @interface X { int x() default "1" // must be integer } """ shouldCompile """ @interface X { int x() default 1 } """ } void testConstant() { assertScript """ class Baz { // static final int OTHER = 5 // below we would like to but can't use: // constant field expressions, e.g. OTHER, or // constant property expressions, e.g. Short.MAX_VALUE @Foo(5) void run() { assert Baz.class.getMethod('run').annotations[0].value() == 5 } } import java.lang.annotation.* @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) @interface Foo { int value() default -3 } new Baz().run() """ } void testArrayDefault() { shouldNotCompile """ @interface X { String[] x() default "1" // must be list } """ shouldNotCompile """ @interface X { String[] x() default ["1",2] // list must contain elements of correct type } """ shouldCompile """ @interface X { String[] x() default ["a","b"] } """ } void testClassDefault() { shouldNotCompile """ @interface X { Class x() default "1" // must be list } """ shouldCompile """ @interface X { Class x() default Number.class // class with .class } """ shouldCompile """ @interface X { Class x() default Number } """ } void testEnumDefault() { shouldNotCompile """ @interface X { ElementType x() default "1" // must be Enum } """ shouldNotCompile """ @interface X { ElementType x() default Target.TYPE // must be Enum of correct type } """ shouldCompile """ import java.lang.annotation.* @interface X { ElementType x() default ElementType.METHOD } """ } void testAnnotationDefault() { shouldNotCompile """ import java.lang.annotation.* @interface X { Target x() default "1" // must be Annotation } """ shouldNotCompile """ import java.lang.annotation.* @interface X { Target x() default @Retentention // must be correct type } """ shouldCompile """ import java.lang.annotation.* @interface X { Target x() default @Target([ElementType.TYPE]) } """ } void testSelfReference() { shouldNotCompile """ @interface X { X x() default @X // self reference must not work } """ } void testCyclicReference() { shouldNotCompile """ @interface X { Y x() default @Y } @interface Y { X x() default @X } """ } void testParameter() { shouldNotCompile """ @interface X { String x(int x) default "" // annotation members can't have parameters } """ } void testThrowsClause() { shouldNotCompile """ @interface X { String x() throws IOException // annotation members can't have exceptions } """ } void testExtends() { shouldNotCompile """ @interface X extends Serializable{} // annotation members can't extend """ } void testInvalidMemberType() { shouldNotCompile """ @interface X { Object x() // Object is no type for constants } """ } void testNull() { shouldNotCompile """ @interface X { String x() default null // null is no constant for annotations } """ } void testUsage() { assertScript """ import java.lang.annotation.* // a random annnotation type @Retention(RetentionPolicy.RUNTIME) @interface MyAnnotation { String stringValue() int intValue() int defaultInt() default 1 String defaultString() default "" Class defaultClass() default Integer.class ElementType defaultEnum() default ElementType.TYPE Target defaultAnnotation() default @Target([ElementType.TYPE]) } @MyAnnotation(stringValue = "for class", intValue = 100) class Foo {} Annotation[] annotations = Foo.class.annotations assert annotations.size() == 1 MyAnnotation my = annotations[0] assert my.stringValue() == "for class" assert my.intValue() == 100 assert my.defaultInt() == 1 assert my.defaultString() == "" assert my.defaultClass() == Integer assert my.defaultEnum() == ElementType.TYPE assert my.defaultAnnotation() instanceof Target """ } void testJavaAnnotationUsageWithGroovyKeyword() { assertScript """ package gls.annotations import java.lang.annotation.* @JavaAnnotation(in = 3) class Foo {} Annotation[] annotations = Foo.class.annotations assert annotations.size() == 1 JavaAnnotation my = annotations[0] assert my.in() == 3 """ } void testUsageOnClass() { assertScript """ import java.lang.annotation.* @Deprecated class Foo{} assert Foo.class.annotations.size() == 1 """ } void testFieldAndPropertyRuntimeRetention() { assertScript """ import org.codehaus.groovy.ast.ClassNode import java.lang.annotation.* @Retention(RetentionPolicy.RUNTIME) @interface Annotation1 {} @Annotation1 class A { @Annotation1 method1(){} @Annotation1 public field1 @Annotation1 prop1 } new ClassNode(A).with { assert annotations: "ClassNode for class 'A' has an annotation as it should" getMethod('method1').with { assert annotations: "Annotation on 'method1' not found" } getField('field1').with { assert annotations: "Annotation on 'field1' not found" } getField('prop1').with { assert annotations: "Annotation on 'property1' not found" } } """ } void testSingletonArrayUsage() { assertScript """ import java.lang.annotation.* // a random annnotation type @Retention(RetentionPolicy.RUNTIME) @interface MyAnnotation { String[] things() } @MyAnnotation(things = "x") class Foo {} Annotation[] annotations = Foo.class.annotations assert annotations.size() == 1 MyAnnotation my = annotations[0] assert my.things().size() == 1 assert my.things()[0] == "x" """ } void testSettingAnnotationMemberTwice() { shouldNotCompile """ package gls.annotations @JavaAnnotation(in = 1, in = 2) class Foo {} """ } void testGetterCallWithSingletonAnnotation() { assertScript """ @Singleton class MyService3410{} assert MyService3410.instance != null assert MyService3410.getInstance() != null """ } void testAttributePropertyConstants() { assertScript """ import java.lang.annotation.* import static Constants.* @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) @interface Anno { double value() default 0.0d String[] array() default [] } class Constants { public static final String BAR = "bar" public static final APPROX_PI = 3.14d } interface IConstants { String FOO = "foo" } class ClassWithAnnotationUsingConstant { @Anno(array = [IConstants.FOO, BAR, groovy.inspect.Inspector.GROOVY]) public annotatedStrings @Anno(Math.PI) public annotatedMath1 @Anno(APPROX_PI) public annotatedMath2 } assert ClassWithAnnotationUsingConstant.getDeclaredField('annotatedStrings').annotations[0].array() == ['foo', 'bar', "GROOVY"] assert ClassWithAnnotationUsingConstant.getDeclaredField('annotatedMath1').annotations[0].value() == Math.PI assert ClassWithAnnotationUsingConstant.getDeclaredField('annotatedMath2').annotations[0].value() == Constants.APPROX_PI """ } void testNestedAttributePropertyConstants() { assertScript """ import java.lang.annotation.* import static Constants.* @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) @interface Outer { Inner value() String[] array() default [] } @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) @interface Inner { String[] value() default [] } class Constants { public static final String BAR = "bar" public static final String BAZ = "baz" } interface IConstants { String FOO = "foo" String FOOBAR = "foobar" } class ClassWithNestedAnnotationUsingConstant { @Outer(value = @Inner([IConstants.FOOBAR, BAR, groovy.inspect.Inspector.GROOVY]), array = [IConstants.FOO, groovy.inspect.Inspector.GROOVY, BAZ]) public outer } assert ClassWithNestedAnnotationUsingConstant.getDeclaredField('outer').annotations[0].array() == ['foo', 'GROOVY', 'baz'] assert ClassWithNestedAnnotationUsingConstant.getDeclaredField('outer').annotations[0].value().value() == ['foobar', 'bar', 'GROOVY'] """ } void testRuntimeRetentionAtAllLevels() { assertScript """ import java.lang.annotation.* @Retention(RetentionPolicy.RUNTIME) @Target([ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER, ElementType.CONSTRUCTOR, ElementType.FIELD]) @interface MyAnnotation { String value() default "" } @MyAnnotation('class') class MyClass { @MyAnnotation('field') public myField @MyAnnotation('constructor') MyClass(@MyAnnotation('constructor param') arg){} @MyAnnotation('method') def myMethod(@MyAnnotation('method param') arg) {} } def c1 = new MyClass() assert c1.class.annotations[0].value() == 'class' def field = c1.class.fields.find{ it.name == 'myField' } assert field.annotations[0].value() == 'field' def method = c1.class.methods.find{ it.name == 'myMethod' } assert method.annotations[0].value() == 'method' assert method.parameterAnnotations[0][0].value() == 'method param' def constructor = c1.class.constructors[0] assert constructor.annotations[0].value() == 'constructor' assert constructor.parameterAnnotations[0][0].value() == 'constructor param' """ } void testAnnotationWithValuesNotGivenForAttributesWithoutDefaults() { def scriptStr scriptStr = """ import java.lang.annotation.Retention import java.lang.annotation.RetentionPolicy @Retention(RetentionPolicy.RUNTIME) @interface Annot3454V1 { String x() } @Annot3454V1 class Bar {} """ // compiler should not allow this, because there is no default value for x shouldNotCompile(scriptStr) scriptStr = """ import java.lang.annotation.Retention import java.lang.annotation.RetentionPolicy @Retention(RetentionPolicy.RUNTIME) @interface Annot3454V2 { String x() default 'xxx' String y() } @Annot3454V2 class Bar {} """ // compiler should not allow this, because there is no default value for y shouldNotCompile(scriptStr) scriptStr = """ import java.lang.annotation.Retention import java.lang.annotation.RetentionPolicy @Retention(RetentionPolicy.RUNTIME) @interface Annot3454V3 { String x() default 'xxx' String y() } @Annot3454V3(y = 'yyy') class Bar {} def anno = Bar.class.getAnnotation(Annot3454V3) assert anno.x() == 'xxx' assert anno.y() == 'yyy' """ // compiler should allow this, because there is default value for x and value provided for y assertScript(scriptStr) } void testAllowedTargetsCheckAlsoWorksForAnnotationTypesDefinedOutsideThisCompilationUnit() { shouldCompile """ @java.lang.annotation.Documented @interface Foo {} """ shouldNotCompile """ @java.lang.annotation.Documented class Foo { def bar } """ shouldNotCompile """ class Foo { @java.lang.annotation.Documented def bar } """ shouldCompile """ import org.junit.* class Foo { @Test void foo() {} } """ shouldNotCompile """ import org.junit.* @Test class Foo { void foo() {} } """ } } Other Groovy examples (source code examples)Here is a short list of links related to this Groovy AnnotationTest.groovy source code file: |
... this post is sponsored by my books ... | |
#1 New Release! |
FP Best Seller |
Copyright 1998-2024 Alvin Alexander, alvinalexander.com
All Rights Reserved.
A percentage of advertising revenue from
pages under the /java/jwarehouse
URI on this website is
paid back to open source projects.