| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you 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 org.codehaus.groovy.transform |
| |
| import gls.CompilableTestSupport |
| |
| /** |
| * Tests for the {@code @Delegate} AST transform. |
| */ |
| class DelegateTransformTest extends CompilableTestSupport { |
| |
| /** fix for GROOVY-3380 */ |
| void testDelegateImplementingANonPublicInterface() { |
| assertScript """ |
| import org.codehaus.groovy.transform.ClassImplementingANonPublicInterface |
| |
| class DelegatingToClassImplementingANonPublicInterface { |
| @Delegate ClassImplementingANonPublicInterface delegate = new ClassImplementingANonPublicInterface() |
| } |
| |
| def constant = new DelegatingToClassImplementingANonPublicInterface().returnConstant() |
| assert constant == "constant" |
| """ |
| } |
| |
| /** fix for GROOVY-3380 */ |
| void testDelegateImplementingANonPublicInterfaceWithZipFileConcreteCase() { |
| assertScript """ |
| import java.util.zip.* |
| |
| class ZipWrapper{ |
| @Delegate ZipFile zipFile |
| } |
| |
| new ZipWrapper() |
| """ |
| } |
| |
| /** test for GROOVY-5974 */ |
| void testDelegateExcludes() { |
| assertScript """ |
| class MapSet { |
| @Delegate(interfaces=false, excludes=['remove','clear']) Map m = [a: 1] |
| @Delegate Set s = new LinkedHashSet([2, 3, 4] as Set) // HashSet not good enough in JDK 1.5 |
| String toString() { m.toString() + ' ' + s } |
| } |
| |
| def ms = new MapSet() |
| assert ms.size() == 1 |
| assert ms.toString() == '[a:1] [2, 3, 4]' |
| ms.remove(3) |
| assert ms.size() == 1 |
| assert ms.toString() == '[a:1] [2, 4]' |
| ms.clear() |
| assert ms.toString() == '[a:1] []' |
| """ |
| } |
| |
| void testDelegateCompileStatic() { |
| assertScript """ |
| @groovy.transform.CompileStatic |
| class MapSet { |
| @Delegate(interfaces=false, excludes=['remove','clear']) Map m = [a: 1] |
| @Delegate Set s = new LinkedHashSet([2, 3, 4] as Set) |
| String toString() { m.toString() + ' ' + s } |
| } |
| |
| def ms = new MapSet() |
| assert ms.size() == 1 |
| assert ms.toString() == '{a=1} [2, 3, 4]' |
| ms.remove(3) |
| assert ms.size() == 1 |
| assert ms.toString() == '{a=1} [2, 4]' |
| ms.clear() |
| assert ms.toString() == '{a=1} []' |
| """ |
| } |
| |
| void testLock() { |
| def res = new GroovyShell().evaluate(""" |
| import java.util.concurrent.locks.* |
| |
| class LockableMap { |
| @Delegate private Map map = [:] |
| |
| @Delegate private Lock lock = new ReentrantLock () |
| |
| @Delegate(interfaces=false) private List list = new ArrayList () |
| } |
| |
| new LockableMap () |
| """) |
| |
| res.lock() |
| try { |
| res[0] = 0 |
| res[1] = 1 |
| res[2] = 2 |
| |
| res.add("in list") |
| } |
| finally { |
| res.unlock() |
| } |
| |
| assertEquals([0: 0, 1: 1, 2: 2], res.@map) |
| assertEquals("in list", res.@list[0]) |
| |
| assertTrue res instanceof Map |
| assertTrue res instanceof java.util.concurrent.locks.Lock |
| assertFalse res instanceof List |
| } |
| |
| void testMultiple() { |
| def res = new GroovyShell().evaluate(""" |
| class X { |
| def value = 10 |
| } |
| |
| class Y { |
| @Delegate X x = new X () |
| @Delegate XX xx = new XX () |
| |
| void setValue (v) { |
| this.@x.@value = 12 |
| } |
| } |
| |
| class XX { |
| def value2 = 11 |
| } |
| |
| new Y () |
| """) |
| |
| assertEquals 10, res.value |
| assertEquals 11, res.value2 |
| res.value = 123 |
| assertEquals 12, res.value |
| } |
| |
| void testUsingDateCompiles() { |
| assertScript """ |
| class Foo { |
| @Delegate Date d = new Date(); |
| } |
| Foo |
| """ |
| } |
| |
| /** fix for GROOVY-3471 */ |
| void testDelegateOnAMapTypeFieldWithInitializationUsingConstructorProperties() { |
| assertScript """ |
| class Test3471 { @Delegate Map mp } |
| def t = new Test3471(mp: new HashMap()) // this was resulting in a NPE due to MetaClassImpl's special handling of Map |
| assert t.keySet().size() == 0 |
| """ |
| } |
| |
| /** GROOVY-3323 */ |
| void testDelegateTransformCorrectlyDelegatesMethodsFromSuperInterfaces() { |
| assert new DelegateBarImpl(new DelegateFooImpl()).bar() == 'bar impl' |
| assert new DelegateBarImpl(new DelegateFooImpl()).foo() == 'foo impl' |
| } |
| |
| /** GROOVY-3555 */ |
| void testDelegateTransformIgnoresDeprecatedMethodsByDefault() { |
| def b1 = new DelegateBarForcingDeprecated(baz: new BazWithDeprecatedFoo()) |
| def b2 = new DelegateBarWithoutDeprecated(baz: new BazWithDeprecatedFoo()) |
| assert b1.bar() == 'bar' |
| assert b2.bar() == 'bar' |
| assert b1.foo() == 'foo' |
| shouldFail(MissingMethodException) { |
| assert b2.foo() == 'foo' |
| } |
| } |
| |
| /** GROOVY-4163 */ |
| void testDelegateTransformAllowsInterfacesAndDelegation() { |
| assertScript """ |
| class Temp implements Runnable { |
| @Delegate |
| private Thread runnable |
| |
| static main(args) { |
| def thread = Thread.currentThread() |
| def temp = new Temp(runnable: thread) |
| } |
| } |
| """ |
| } |
| |
| void testDelegateToSelfTypeShouldFail() { |
| shouldNotCompile """ |
| class B { |
| @Delegate B b = new B() |
| static main(args){ |
| new B() |
| } |
| } |
| """ |
| } |
| |
| // GROOVY-4265 |
| void testShouldPreferDelegatedOverStaticSuperMethod() { |
| assertScript """ |
| class A { |
| static foo(){"A->foo()"} |
| } |
| class B extends A { |
| @Delegate C c = new C() |
| } |
| class C { |
| def foo(){"C->foo()"} |
| } |
| assert new B().foo() == 'C->foo()' |
| """ |
| } |
| |
| void testDelegateToObjectShouldFail() { |
| shouldNotCompile """ |
| class B { |
| @Delegate b = new Object() |
| } |
| """ |
| } |
| |
| /** GROOVY-4244 */ |
| void testSetPropertiesThroughDelegate() { |
| def foo = new Foo4244() |
| |
| assert foo.nonFinalBaz == 'Initial value - nonFinalBaz' |
| foo.nonFinalBaz = 'New value - nonFinalBaz' |
| assert foo.nonFinalBaz == 'New value - nonFinalBaz' |
| |
| assert foo.finalBaz == 'Initial value - finalBaz' |
| shouldFail(ReadOnlyPropertyException) { |
| foo.finalBaz = 'New value - finalBaz' |
| } |
| } |
| |
| void testDelegateSuperInterfaces_Groovy4619() { |
| assert 'doSomething' in SomeClass4619.class.methods*.name |
| } |
| |
| // GROOVY-5112 |
| void testGenericsOnArray() { |
| assertScript ''' |
| class ListWrapper { |
| @Delegate |
| List myList |
| |
| @Delegate |
| URL homepage |
| } |
| new ListWrapper() |
| ''' |
| } |
| |
| // GROOVY-5732 |
| void testInterfacesFromSuperClasses() { |
| assertScript ''' |
| interface I5732 { |
| void aMethod() |
| } |
| |
| abstract class AbstractBaseClass implements I5732 { } |
| |
| abstract class DelegatedClass extends AbstractBaseClass { |
| void aMethod() {} |
| } |
| |
| class Delegator { |
| @Delegate private DelegatedClass delegate |
| } |
| |
| assert I5732.isAssignableFrom(Delegator) |
| ''' |
| } |
| |
| // GROOVY-5729 |
| void testDeprecationWithInterfaces() { |
| assertScript ''' |
| interface I5729 { |
| @Deprecated |
| void aMethod() |
| } |
| |
| class Delegator1 { |
| @Delegate private I5729 delegate |
| } |
| assert I5729.isAssignableFrom(Delegator1) |
| assert Delegator1.methods*.name.contains('aMethod') |
| |
| class Delegator2 { |
| @Delegate(interfaces=false) private I5729 delegate |
| } |
| assert !I5729.isAssignableFrom(Delegator2) |
| assert !Delegator2.methods*.name.contains('aMethod') |
| |
| class Delegator3 { |
| @Delegate(interfaces=false, deprecated=true) private I5729 delegate |
| } |
| assert !I5729.isAssignableFrom(Delegator3) |
| assert Delegator3.methods*.name.contains('aMethod') |
| ''' |
| } |
| |
| // GROOVY-5446 |
| void testDelegateWithParameterAnnotations() { |
| assertScript """ |
| import java.lang.annotation.* |
| |
| @Retention(RetentionPolicy.RUNTIME) |
| @Target([ElementType.PARAMETER]) |
| public @interface SomeAnnotation { |
| } |
| |
| class A { |
| def method(@SomeAnnotation def param) { "Test" } |
| } |
| |
| class A_Delegate { |
| @Delegate(parameterAnnotations = true) |
| A a = new A() |
| } |
| |
| def originalMethod = A.getMethod('method', [Object.class] as Class[]) |
| def originalAnno = originalMethod.parameterAnnotations[0][0] |
| |
| def delegateMethod = A_Delegate.getMethod('method', [Object.class] as Class[]) |
| def delegateAnno = delegateMethod.parameterAnnotations[0][0] |
| println delegateMethod.parameterAnnotations |
| |
| assert delegateAnno == originalAnno |
| """ |
| } |
| |
| void testDelegateWithMethodAnnotations() { |
| assertScript """ |
| import java.lang.annotation.* |
| |
| @Retention(RetentionPolicy.RUNTIME) |
| @Target([ElementType.METHOD]) |
| public @interface SomeAnnotation { |
| int value() |
| } |
| |
| class A { |
| @SomeAnnotation(42) |
| def method( def param) { "Test" } |
| } |
| |
| class A_Delegate { |
| @Delegate(methodAnnotations = true) |
| A a = new A() |
| } |
| |
| def originalMethod = A.getMethod('method', [Object.class] as Class[]) |
| def originalAnno = originalMethod.declaredAnnotations[0] |
| |
| def delegateMethod = A_Delegate.getMethod('method', [Object.class] as Class[]) |
| def delegateAnno = delegateMethod.declaredAnnotations[1] |
| |
| assert delegateAnno == originalAnno |
| |
| assert delegateAnno.value() == 42 |
| assert delegateAnno.value() == originalAnno.value() |
| """ |
| } |
| |
| void testParameterAnnotationsShouldNotBeCarriedOverByDefault() { |
| assertScript """ |
| import java.lang.annotation.* |
| |
| @Retention(RetentionPolicy.RUNTIME) |
| @Target([ElementType.PARAMETER]) |
| public @interface SomeAnnotation { |
| } |
| |
| class A { |
| def method(@SomeAnnotation def param) { "Test" } |
| } |
| |
| class A_Delegate { |
| @Delegate |
| A a = new A() |
| } |
| |
| def originalMethod = A.getMethod('method', [Object.class] as Class[]) |
| def originalAnno = originalMethod.parameterAnnotations[0][0] |
| |
| def delegateMethod = A_Delegate.getMethod('method', [Object.class] as Class[]) |
| assert delegateMethod.parameterAnnotations[0].length == 0 |
| """ |
| } |
| |
| // this test reflects that we currently don't support carrying over |
| // Closure Annotations rather than a desired design goal |
| // TODO: support Closure Annotations and then remove/change this test |
| void testAnnotationWithClosureMemberIsNotSupported() { |
| def message = shouldFail { |
| assertScript """ |
| import java.lang.annotation.* |
| |
| @Retention(RetentionPolicy.RUNTIME) |
| @Target([ElementType.METHOD]) |
| public @interface SomeAnnotation { |
| Class value() |
| } |
| |
| class A { |
| @SomeAnnotation({ param != null }) |
| def method(def param) { "Test" } |
| } |
| |
| class A_Delegate { |
| @Delegate(methodAnnotations = true) |
| A a = new A() |
| } |
| """ |
| } |
| |
| assert message.contains('@Delegate does not support keeping Closure annotation members.') |
| } |
| |
| // this test reflects that we currently don't support carrying over |
| // Closure Annotations rather than a desired design goal |
| // TODO: support Closure Annotations and then remove/change this test |
| void testAnnotationWithClosureClassDescendantIsNotSupported() { |
| def message = shouldFail { |
| assertScript """ |
| import java.lang.annotation.* |
| |
| @Retention(RetentionPolicy.RUNTIME) |
| @Target([ElementType.METHOD]) |
| public @interface SomeAnnotation { |
| Class value() |
| } |
| |
| class A { |
| @SomeAnnotation(org.codehaus.groovy.runtime.GeneratedClosure.class) |
| def method(def param) { "Test" } |
| } |
| |
| class A_Delegate { |
| @Delegate(methodAnnotations = true) |
| A a = new A() |
| } |
| """ |
| } |
| assert message.contains('@Delegate does not support keeping Closure annotation members.') |
| } |
| |
| // GROOVY-5445 |
| void testDelegateToSuperProperties() { |
| assertScript """ |
| class Foo { |
| @Delegate Bar delegate = new Bar() |
| def foo() { |
| bar = "bar" |
| baz = "baz" |
| } |
| } |
| |
| class Bar extends Baz { String bar } |
| class Baz { String baz } |
| |
| def f = new Foo() |
| f.foo() |
| assert f.bar + f.baz == 'barbaz' |
| """ |
| } |
| |
| // GROOVY-7243 |
| void testInclude() { |
| assertScript ''' |
| class Book { |
| String title |
| String author |
| |
| String getTitleAndAuthor() { |
| "${title} : ${author}" |
| } |
| |
| String getAuthorAndTitle() { |
| "${author} : ${title}" |
| } |
| } |
| |
| class OwnedBook { |
| String owner |
| |
| @Delegate(includes=['author', 'getTitleAndAuthor']) |
| Book book |
| } |
| |
| Book book = new Book(title: 'Ulysses', author: 'James Joyce') |
| OwnedBook ownedBook = new OwnedBook(owner: 'John Smith', book: book) |
| |
| ownedBook.author = 'John Smith' |
| assert book.author == 'John Smith' |
| |
| assert ownedBook.getTitleAndAuthor() == 'Ulysses : John Smith' |
| |
| try { |
| ownedBook.getAuthorAndTitle() |
| assert false, 'Non-included methods should not be delegated' |
| } catch(groovy.lang.MissingMethodException expected) { |
| } |
| |
| try { |
| ownedBook.title = 'Finnegans Wake' |
| assert false, 'Non-included properties should not be delegated' |
| } catch(groovy.lang.MissingPropertyException expected) { |
| } |
| ''' |
| } |
| |
| // GROOVY-6329 |
| void testIncludeAndExcludeByType() { |
| assertScript """ |
| interface OddInclusionsTU<T, U> { |
| boolean addAll(Collection<? extends T> t) |
| boolean add(U u) |
| T remove(int index) |
| } |
| |
| interface OddInclusionsU<U> extends OddInclusionsTU<Integer, U> { } |
| |
| interface OddInclusions extends OddInclusionsU<Integer> { } |
| |
| interface OtherInclusions { |
| void clear() |
| } |
| |
| interface EvenExclusions extends OddInclusions, OtherInclusions { } |
| |
| class MixedNumbers { |
| // collection variant of addAll and remove will work on odd list |
| @Delegate(includeTypes=OddInclusions) List<Integer> odds = [1, 3] |
| // clear will work on other list |
| @Delegate(includeTypes=OtherInclusions) List<Integer> others = [0] |
| // all other methods will work on even list |
| @Delegate(excludeTypes=EvenExclusions) List<Integer> evens = [2, 4, 6] |
| def getAll() { evens + odds + others } |
| } |
| |
| def list = new MixedNumbers() |
| assert list.all == [2, 4, 6, 1, 3, 0] |
| list.add(5) |
| list.addAll([7, 9]) |
| list.addAll(1, [8]) |
| list.remove(0) |
| assert list.indexOf(8) == 1 |
| list.clear() |
| assert list.all == [2, 8, 4, 6, 3, 5, 7, 9] |
| """ |
| } |
| |
| // GROOVY-5211 |
| void testAvoidFieldNameClashWithParameterName() { |
| assertScript """ |
| class A { |
| def foo(a) { a * 2 } |
| } |
| |
| class B { |
| @Delegate A a = new A() |
| } |
| |
| assert new B().foo(10) == 20 |
| """ |
| } |
| |
| // GROOVY-6542 |
| void testLineNumberInStackTrace() { |
| try { |
| assertScript '''import groovy.transform.ASTTest |
| import org.codehaus.groovy.control.CompilePhase |
| |
| @ASTTest(phase=CompilePhase.CANONICALIZATION, value={ |
| def fieldNode = node.getDeclaredField('thingie') |
| def blowupMethod = node.getDeclaredMethod('blowup') |
| def mce = blowupMethod.code.expression |
| assert mce.lineNumber==fieldNode.lineNumber |
| assert mce.lineNumber>0 |
| }) |
| class Upper { |
| @Delegate Lower thingie |
| |
| Upper() { |
| thingie = new Lower() |
| } |
| } |
| |
| class Lower { |
| def foo() { |
| println("Foo!") |
| } |
| |
| def blowup(String a) { |
| throw new Exception("blow up with ${a}") |
| } |
| |
| def blowup() { |
| throw new Exception("blow up") |
| } |
| } |
| |
| def up = new Upper() |
| up.foo() |
| up.blowup("bar") |
| ''' |
| } catch (e) { |
| // ok |
| } |
| } |
| |
| // |
| void testShouldNotReuseRawClassNode() { |
| assertScript '''import org.codehaus.groovy.transform.DelegateMap |
| class Foo { |
| DelegateMap dm = new DelegateMap() |
| } |
| def foo = new Foo() |
| assert foo.dm.x == '123' |
| ''' |
| } |
| |
| // GROOVY-7118 |
| void testDelegateOfMethodHavingPlaceholder() { |
| assertScript """ |
| interface FooInt { |
| public <T extends Throwable> T get(Class<T> clazz) throws Exception |
| } |
| |
| class Foo implements FooInt { |
| public <T extends Throwable> T get(Class<T> clazz) throws Exception { |
| clazz.newInstance() |
| } |
| } |
| |
| class FooMain { |
| @Delegate Foo foo = new Foo() |
| } |
| |
| @groovy.transform.CompileStatic |
| class FooMain2 { |
| @Delegate Foo foo = new Foo() |
| } |
| |
| assert new FooMain().get(Exception).class == Exception |
| assert new FooMain2().get(Exception).class == Exception |
| |
| import org.codehaus.groovy.transform.Bar |
| class BarMain { |
| @Delegate Bar bar = new Bar() |
| } |
| assert new BarMain().get(Exception).class == Exception |
| """ |
| } |
| |
| // GROOVY-7261 |
| void testShouldWorkWithLazyTransform() { |
| assertScript ''' |
| class Foo { |
| private @Delegate @Lazy ArrayList list = ['bar', 'baz'] |
| // fragile: $list is an internal implementation detail that may change |
| def getInternalDelegate() { $list } |
| } |
| |
| def f = new Foo() |
| assert f.internalDelegate == null |
| assert f.size() == 2 |
| assert f.internalDelegate == ['bar', 'baz'] |
| ''' |
| } |
| |
| // GROOVY-6454 |
| void testMethodsWithInternalNameShouldNotBeDelegatedTo() { |
| assertScript ''' |
| class HasMethodWithInternalName { |
| void $() { |
| } |
| } |
| |
| class DelegatesToHasMethodWithInternalName { |
| @Delegate |
| HasMethodWithInternalName hasMethodWithInternalName |
| } |
| |
| assert !new DelegatesToHasMethodWithInternalName().respondsTo('$') |
| ''' |
| } |
| |
| // GROOVY-6454 |
| void testMethodsWithInternalNameShouldBeDelegatedToIfRequested() { |
| assertScript ''' |
| interface HasMethodWithInternalName { |
| void $() |
| } |
| |
| class DelegatesToHasMethodWithInternalName { |
| @Delegate(allNames = true) |
| HasMethodWithInternalName hasMethodWithInternalName |
| } |
| |
| assert new DelegatesToHasMethodWithInternalName().respondsTo('$') |
| ''' |
| } |
| |
| // GROOVY-6454 |
| void testProperitesWithInternalNameShouldBeDelegatedToIfRequested() { |
| assertScript ''' |
| class HasPropertyWithInternalName { |
| def $ |
| } |
| |
| class DelegatesToHasPropertyWithInternalName { |
| @Delegate(allNames = true) |
| HasPropertyWithInternalName hasPropertyWithInternalName |
| } |
| |
| def delegates = new DelegatesToHasPropertyWithInternalName() |
| assert delegates.respondsTo('get$') |
| assert delegates.respondsTo('set$') |
| ''' |
| } |
| |
| void testDelegateToGetterMethod() { |
| // given: |
| def delegate = { new DelegateFooImpl() } |
| // when: |
| def foo = new FooToMethod(delegate) |
| // then: |
| assert foo.foo() == delegate().foo() |
| } |
| |
| // GROOVY-5752 |
| void testDelegationShouldAccountForPrimitiveBooleanProperties() { |
| assertScript """ |
| class A { |
| boolean a |
| boolean b |
| boolean isB() { b } |
| boolean c |
| boolean getC() { c } |
| } |
| |
| class B { |
| @Delegate A a = new A(a: true, b: true, c: true) |
| } |
| |
| def a = new A(a: true, b: true, c: true) |
| assert a.getA() |
| assert a.isA() |
| assert a.isB() |
| assert a.getC() |
| |
| def b = new B() |
| assert b.getA() |
| assert b.isA() |
| assert b.isB() |
| assert b.getC() |
| """ |
| } |
| |
| //GROOVY-8132 |
| void testOwnerPropertyPreferredToDelegateProperty() { |
| assertScript ''' |
| class Foo { |
| String pls |
| @groovy.lang.Delegate |
| Bar bar |
| } |
| |
| class Bar { |
| String pls |
| } |
| assert new Foo(pls: 'ok').pls == 'ok' |
| ''' |
| } |
| |
| void testOwnerMethodPreferredToDelegateMethod() { |
| assertScript ''' |
| class Foo { |
| String pls() { 'foo pls' } |
| @groovy.lang.Delegate |
| Bar bar |
| } |
| |
| class Bar { |
| String pls() { 'bar pls' } |
| } |
| assert new Foo(bar: new Bar()).pls() == 'foo pls' |
| ''' |
| } |
| |
| // GROOVY-8204 |
| void testDelegateToArray() { |
| assertScript ''' |
| import groovy.lang.Delegate |
| |
| class BugsMe { |
| @Delegate |
| String[] content = ['foo', 'bar'] |
| } |
| |
| assert new BugsMe().content.join() == 'foobar' |
| assert new BugsMe().content.length == 2 |
| assert new BugsMe().length == 2 |
| ''' |
| } |
| |
| // GROOVY-9289 |
| void testExcludesWithInvalidPropertyNameResultsInError() { |
| def message = shouldFail """ |
| class WMap { |
| String name |
| @Delegate(excludes = "name") |
| Map<String, String> data |
| |
| WMap(String name, Map<String, String> data) { |
| this.name = name |
| this.data = data |
| } |
| } |
| |
| new WMap('example', [name: 'weird']) |
| """ |
| assert message.contains("Error during @Delegate processing: 'excludes' property or method 'name' does not exist.") |
| } |
| |
| // GROOVY-8825 |
| void testDelegateToPrecompiledGroovyGeneratedMethod() { |
| assertScript ''' |
| import org.codehaus.groovy.transform.CompiledClass8825 |
| class B { |
| @Delegate(methodAnnotations = true) |
| private final CompiledClass8825 delegate = new CompiledClass8825() |
| } |
| assert new B().s == '456' |
| ''' |
| } |
| } |
| |
| interface DelegateFoo { |
| def foo() |
| } |
| |
| class DelegateFooImpl implements DelegateFoo { |
| def foo() { 'foo impl' } |
| } |
| |
| interface DelegateBar extends DelegateFoo { |
| def bar() |
| } |
| |
| class DelegateBarImpl implements DelegateBar { |
| @Delegate DelegateFoo foo; |
| |
| DelegateBarImpl(DelegateFoo f) { this.foo = f} |
| |
| def bar() { 'bar impl'} |
| } |
| |
| class BazWithDeprecatedFoo { |
| @Deprecated foo() { 'foo' } |
| def bar() { 'bar' } |
| } |
| |
| class DelegateBarWithoutDeprecated { |
| @Delegate BazWithDeprecatedFoo baz |
| } |
| |
| class DelegateBarForcingDeprecated { |
| @Delegate(deprecated=true) BazWithDeprecatedFoo baz |
| } |
| |
| class Foo4244 { |
| @Delegate Bar4244 bar = new Bar4244() |
| } |
| |
| class FooToMethod { |
| private final Closure<DelegateFoo> strategy |
| |
| FooToMethod(Closure<DelegateFoo> strategy) { |
| this.strategy = strategy |
| } |
| |
| @Delegate |
| DelegateFoo getStrategy() { strategy() } |
| } |
| |
| class Bar4244 { |
| String nonFinalBaz = "Initial value - nonFinalBaz" |
| final String finalBaz = "Initial value - finalBaz" |
| } |
| |
| interface SomeInterface4619 { |
| void doSomething() |
| } |
| |
| interface SomeOtherInterface4619 extends SomeInterface4619 {} |
| |
| class SomeClass4619 { |
| @Delegate |
| SomeOtherInterface4619 delegate |
| } |
| |
| interface BarInt { |
| public <T extends Throwable> T get(Class<T> clazz) throws Exception |
| } |
| |
| class Bar implements BarInt { |
| public <T extends Throwable> T get(Class<T> clazz) throws Exception { |
| clazz.newInstance() |
| } |
| } |
| |
| class CompiledClass8825 { |
| final String s = '456' |
| } |
| |
| // DO NOT MOVE INSIDE THE TEST SCRIPT OR IT WILL NOT TEST |
| // WHAT IT IS SUPPOSED TO TEST ANYMORE ! |
| class DelegateMap { |
| protected final @Delegate Map props = [x:'123'] |
| } |