Anil Gowda
Anil Gowda

Reputation: 446

This vs Static in Groovy

In java:

protected static final Logger LOG = LoggerFactory.getLogger(this.getClass())

is not allowed as this would mean that we are trying to access non static member from a static context.

However Groovy allows same piece of code. How would it be resolved?

Would it give priority to static thus making the code to look like:

protected static final Logger LOG = LoggerFactory.getLogger(MyClass.class)

or would it give priority to non static reference and make code look like:

protected final Logger LOG = LoggerFactory.getLogger(this.getClass())

Upvotes: 1

Views: 2916

Answers (1)

Szymon Stepniak
Szymon Stepniak

Reputation: 42184

Groovy adds static constructor to satisfy this initialization. Take a look at following class:

import org.slf4j.Logger
import org.slf4j.LoggerFactory

class ClassWithLog {

    protected static final Logger LOG = LoggerFactory.getLogger(this.getClass())

    static void main(String[] args) {
        LOG.info("Hello, world!")
    }
}

Let's compile it to the .class file:

groovyc -cp ~/.m2/repository/org/slf4j/slf4j-api/1.7.25/slf4j-api-1.7.25.jar ClassWithLog.groovy

And now let's take a look what the bytecode looks like using javap command:

javap -l -c ClassWithLog

I will skip all unrelated stuff and go directly to: (full listing can be found here: https://gist.github.com/wololock/8d5a7cd049ef69a0d67567142e25b449)

  static {};
    Code:
       0: invokestatic  #23                 // Method $getCallSiteArray:()[Lorg/codehaus/groovy/runtime/callsite/CallSite;
       3: ldc           #89                 // int 1
       5: aaload
       6: ldc           #91                 // class org/slf4j/LoggerFactory
       8: invokestatic  #23                 // Method $getCallSiteArray:()[Lorg/codehaus/groovy/runtime/callsite/CallSite;
      11: ldc           #92                 // int 2
      13: aaload
      14: ldc           #2                  // class ClassWithLog
      16: invokeinterface #96,  2           // InterfaceMethod org/codehaus/groovy/runtime/callsite/CallSite.callStatic:(Ljava/lang/Class;)Ljava/lang/Object;
      21: invokeinterface #44,  3           // InterfaceMethod org/codehaus/groovy/runtime/callsite/CallSite.call:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
      26: astore_0
      27: aload_0
      28: ldc           #98                 // class org/slf4j/Logger
      30: invokestatic  #102                // Method org/codehaus/groovy/runtime/ScriptBytecodeAdapter.castToType:(Ljava/lang/Object;Ljava/lang/Class;)Ljava/lang/Object;
      33: checkcast     #98                 // class org/slf4j/Logger
      36: putstatic     #36                 // Field LOG:Lorg/slf4j/Logger;
      39: aload_0
      40: pop
      41: return
    LineNumberTable:
      line 6: 0

As you can see in the bytecode listed, Groovy added a static constructor (we haven't defined one) and it did invokestatic in place of this.getClass() when used in the static context.

If we remove line 6 from this exemplary Groovy class and then compile it to the bytecode, static constructor does not exist any more.

Full bytecode listing after removing static LOG field: https://gist.github.com/wololock/ad0284a0065166585dcba6a3db1475dc

Upvotes: 3

Related Questions