You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@groovy.apache.org by "Jochen Theodorou (JIRA)" <ji...@apache.org> on 2016/07/13 19:39:20 UTC

[jira] [Comment Edited] (GROOVY-7885) referencing method in outer class from inner class throws Exception when using newInstance()

    [ https://issues.apache.org/jira/browse/GROOVY-7885?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=15375605#comment-15375605 ] 

Jochen Theodorou edited comment on GROOVY-7885 at 7/13/16 7:38 PM:
-------------------------------------------------------------------

Short answer: NPE is maybe unexpected, newInstance not working is expected though.
Longer version:
In Java an inner class comes in two kinds, the static ones and the non-static ones. The static ones cannot call instance methods of the outer class, the non-static ones can. This is realized by supplying the inner class with an instance of  the outer class, normally stored as this$0. This also means, that the inner class constructor you declare is not really the constructor that will be used. Instead B(){} will be transformed to something like {code}B(A x){this.this$0 = x;}{code}. This is also true for the default constructor in B. So if you want to create an instance of B, you will need an instance of A. The new-instance-operator in Java will do this for you and hide those implementation details. the newInstance-method cannot do this, since it has no access to the instance that did the call and is just a normal method. So the right way to make an instance of B is in your code B.newInstance(this). This will call the B(A) constructor Groovy generated, just the same way the java compiler would have done. If you wanted to create a newinstance of B using reflection, you would have the exact same problem.


was (Author: blackdrag):
Short answer: NPE is maybe unexpected, newInstance not working is expected though.
Longer version:
In Java an inner class comes in two kinds, the static ones and the non-static ones. The static ones cannot call instance methods of the outer class, the non-static ones can. This is realized by supplying the inner class with an instance of  the outer class, normally stored as this$0. This also means, that the inner class constructor you declare is not really the constructor that will be used. Instead B(){} will be transformed to something like B(A x){this.this$0 = x;}. This is also true for the default constructor in B. So if you want to create an instance of B, you will need an instance of A. The new-instance-operator in Java will do this for you and hide those implementation details. the newInstance-method cannot do this, since it has no access to the instance that did the call and is just a normal method. So the right way to make an instance of B is in your code B.newInstance(this). This will call the B(A) constructor Groovy generated, just the same way the java compiler would have done. If you wanted to create a newinstance of B using reflection, you would have the exact same problem.

> referencing method in outer class from inner class throws Exception when using newInstance()
> --------------------------------------------------------------------------------------------
>
>                 Key: GROOVY-7885
>                 URL: https://issues.apache.org/jira/browse/GROOVY-7885
>             Project: Groovy
>          Issue Type: Bug
>    Affects Versions: 2.4.6
>            Reporter: Jörg Prante
>            Priority: Minor
>
> This code throws an error
> class A {
>    Object o
>    A() {
>      def b = B.newInstance()                   
>      o = "Hello"
>      b.execute()
>    }
>    Object val() {
>        o
>    }
>    class B {
>       void execute() {
>          println val()
>       }
>    }
> }
> def a = new A()
> groovy Test.groovy
> Caught: java.lang.NullPointerException
> java.lang.NullPointerException
> 	at A$B.methodMissing(Test.groovy)
> 	at A$B.execute(Test.groovy:18)
> 	at A$B$execute.call(Unknown Source)
> 	at A.<init>(Test.groovy:9)
> 	at Test.run(Test.groovy:24)
> but this code works
> class A {
>    Object o
>    A() {
>      def b = new B()        
>      o = "Hello"
>      b.execute()
>    }
>    Object val() {
>        o
>    }
>    class B {
>       void execute() {
>          println val()
>       }
>    }
> }
> def a = new A()
> Is this expected?



--
This message was sent by Atlassian JIRA
(v6.3.4#6332)