groovy looking up weird properties - groovy

I have the following groovy script compiled from an html file
package org.webpieces.plugins.fortesting
import org.webpieces.ctx.api.Current
class notFound_html extends org.webpieces.templating.impl.GroovyTemplateSuperclass {
public Object run() {
use(org.webpieces.templating.impl.source.GroovyExtensions) {
__out.print("<html>\n"); //htmlLine 0:2 groovyLine=8
__out.print(" <head>\n"); //htmlLine 2:3 groovyLine=9
__out.print(" </head>\n"); //htmlLine 3:4 groovyLine=10
__out.print(" <body>\n"); //htmlLine 4:5 groovyLine=11
__out.print(" Your page was not found\n"); //htmlLine 5:6 groovyLine=12
__out.print(" </body>\n"); //htmlLine 6:7 groovyLine=13
__out.print("</html>"); //htmlLine 7:7 groovyLine=14
}
}
}
This then compiles to a *.class file which decompiled I see looks like this
package org.webpieces.plugins.fortesting;
import groovy.lang.Closure;
import groovy.transform.Generated;
import org.codehaus.groovy.runtime.GeneratedClosure;
import org.codehaus.groovy.runtime.callsite.CallSite;
import org.webpieces.templating.impl.GroovyTemplateSuperclass;
public class notFound_html extends GroovyTemplateSuperclass {
#Generated
public notFound_html() {
CallSite[] var1 = $getCallSiteArray();
super();
}
public Object run() {
CallSite[] var1 = $getCallSiteArray();
final class _run_closure1 extends Closure implements GeneratedClosure {
public _run_closure1(Object _outerInstance, Object _thisObject) {
CallSite[] var3 = $getCallSiteArray();
super(_outerInstance, _thisObject);
}
public Object doCall(Object it) {
CallSite[] var2 = $getCallSiteArray();
var2[0].call(var2[1].callGroovyObjectGetProperty(this), "<html>\n");
var2[2].call(var2[3].callGroovyObjectGetProperty(this), " <head>\n");
var2[4].call(var2[5].callGroovyObjectGetProperty(this), " </head>\n");
var2[6].call(var2[7].callGroovyObjectGetProperty(this), " <body>\n");
var2[8].call(var2[9].callGroovyObjectGetProperty(this), " Your page was not found\n");
var2[10].call(var2[11].callGroovyObjectGetProperty(this), " </body>\n");
return var2[12].call(var2[13].callGroovyObjectGetProperty(this), "</html>");
}
#Generated
public Object doCall() {
CallSite[] var1 = $getCallSiteArray();
return this.doCall((Object)null);
}
}
return var1[0].callCurrent(this, var1[1].callGetProperty(var1[2].callGetProperty(var1[3].callGetProperty(var1[4].callGetProperty(var1[5].callGetProperty(var1[6].callGroovyObjectGetProperty(this)))))), new _run_closure1(this, this));
}
}
When running this template, I get an exception on looking up the property 'org'. Specifically, the superclass I control GroovyTemplateSuperclass which has a getProperty method like so ->
#Override
public Object getProperty(String property) {
String srcLocation = modifySourceLocation2(sourceLocal.get());
boolean isOptional = false;
if(property.endsWith("$")) {
isOptional = true;
property = property.substring(0, property.length()-1);
}
try {
return super.getProperty(property);
} catch (MissingPropertyException e) {
if(isOptional)
return null;
throw new IllegalArgumentException("No such property '"+property+"' but perhaps you forgot quotes "
+ "around it or you forgot to pass it in from the controller's return value(with the RouteId) OR "
+ "lastly, if this is inside a custom tag, perhaps the tag did not pass in the correct arguments."+srcLocation, e);
}
}
Groovy appears to be going through this line ->
use(org.webpieces.templating.impl.source.GroovyExtensions) {
and each of those is in an array and being called as a property. I am not sure why this is failing now and was working before though so I am providing all the info I have.
Specifically, I get ""No such property 'org'" and upon further inspection that comes from an array which has org, webpieces, templating, impl, source, GroovyExtensions.
I find this very strange and am still digging but thought I might post as I have a feeling I may waste hours on this one.

Related

Groovy $getCallSiteArray implementation

I am using groovy 2.4.12 with Oracle JVM 1.8. I am trying to understand a bit how groovyc converts the scripts written by end users.
To that end I wrote this simple script:
println 'Hello World`
This was compiled to bytecode using groovyc hello.groovy. Finally, I decompiled the hello.class to get the following code:
import groovy.lang.Binding;
import groovy.lang.Script;
import org.codehaus.groovy.runtime.InvokerHelper;
import org.codehaus.groovy.runtime.callsite.CallSite;
public class hello extends Script {
public hello() {
CallSite[] var1 = $getCallSiteArray();
}
public hello(Binding context) {
CallSite[] var2 = $getCallSiteArray();
super(context);
}
public static void main(String... args) {
CallSite[] var1 = $getCallSiteArray();
var1[0].call(InvokerHelper.class, hello.class, args);
}
public Object run() {
CallSite[] var1 = $getCallSiteArray();
return var1[1].callCurrent(this, "Hello World");
}
}
This looks like a typical Java class except I cannot figure out where $getCallSiteArray() method is defined. It is definitely not in this class and neither is it a public or protected member of groovy.lang.Script. So my question is where is this method implemented?
use another decompiler to see it
//
// Decompiled by Procyon v0.5.36
//
public class A extends Script
{
private static /* synthetic */ SoftReference $callSiteArray;
public A() {
$getCallSiteArray();
}
public A(final Binding context) {
$getCallSiteArray();
super(context);
}
public static void main(final String... args) {
$getCallSiteArray()[0].call((Object)InvokerHelper.class, (Object)A.class, (Object)args);
}
public Object run() {
return $getCallSiteArray()[1].callCurrent((GroovyObject)this, (Object)"hello world");
}
private static /* synthetic */ CallSiteArray $createCallSiteArray() {
final String[] array = new String[2];
$createCallSiteArray_1(array);
return new CallSiteArray((Class)A.class, array);
}
private static /* synthetic */ CallSite[] $getCallSiteArray() {
CallSiteArray $createCallSiteArray;
if (A.$callSiteArray == null || ($createCallSiteArray = A.$callSiteArray.get()) == null) {
$createCallSiteArray = $createCallSiteArray();
A.$callSiteArray = new SoftReference($createCallSiteArray);
}
return $createCallSiteArray.array;
}
}

How to override Groovy variable and method using anonymous class?

I have the following code. I have an abstract JobParams, a class extending that abstract GradleJobParams, and a gjp variable with value using anonymous class declaration.
I want to test the overriding behavior of groovy. I can override the method setupRoot() but not the property testVar, why is that?
Tested on: https://groovyconsole.appspot.com/script/5146436232544256
abstract class JobParams {
int root
def testVar=1
def setupRoot () {
println("The root");
}
def printTestVar () {
println("The testVar:" + testVar);
}
}
class GradleJobParams extends JobParams {
}
def gjp = [
testVar:3,
setupRoot:{
println("Override root");
}
] as GradleJobParams;
println("Starting");
gjp.printTestVar();
gjp.setupRoot();
The result is:
Starting
The testVar:1
Override root
Java (and thus Groovy) does not support overriding fields from the parent class with subclassing. Instead, it uses a mechanism called hiding fields:
Hiding Fields
Within a class, a field that has the same name as a field in the superclass hides the superclass's field, even if their types are different. Within the subclass, the field in the superclass cannot be referenced by its simple name. Instead, the field must be accessed through super, which is covered in the next section. Generally speaking, we don't recommend hiding fields as it makes code difficult to read.
Source: https://docs.oracle.com/javase/tutorial/java/IandI/hidevariables.html
It can be simply illustrated with the following example in Java:
final class SubclassHiddingFieldExample {
static abstract class A {
int value = 10;
void printValue1() {
System.out.println(value);
}
void printValue2() {
System.out.println(this.value);
}
void printValue3() {
System.out.println(((B)this).value);
}
}
static class B extends A {
int value = 12;
}
public static void main(String[] args) {
final B b = new B();
b.printValue1();
b.printValue2();
b.printValue3();
}
}
Output:
10
10
12
As you can see, only printValue3 prints out 3, because it cast this explicitly to B class.
Now, if you look at the decompiled bytecode of your JobParams class, you can see that the printTestVar method code is an equivalent of the following Java code:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
import groovy.lang.GroovyObject;
import groovy.lang.MetaClass;
import org.codehaus.groovy.runtime.callsite.CallSite;
public abstract class JobParams implements GroovyObject {
private int root;
private Object testVar;
public JobParams() {
CallSite[] var1 = $getCallSiteArray();
byte var2 = 1;
this.testVar = Integer.valueOf(var2);
MetaClass var3 = this.$getStaticMetaClass();
this.metaClass = var3;
}
public Object setupRoot() {
CallSite[] var1 = $getCallSiteArray();
return var1[0].callCurrent(this, "The root");
}
public Object printTestVar() {
CallSite[] var1 = $getCallSiteArray();
return var1[1].callCurrent(this, var1[2].call("The testVar:", this.testVar));
}
public MetaClass getMetaClass() {
MetaClass var10000 = this.metaClass;
if (var10000 != null) {
return var10000;
} else {
this.metaClass = this.$getStaticMetaClass();
return this.metaClass;
}
}
public void setMetaClass(MetaClass var1) {
this.metaClass = var1;
}
public Object invokeMethod(String var1, Object var2) {
return this.getMetaClass().invokeMethod(this, var1, var2);
}
public Object getProperty(String var1) {
return this.getMetaClass().getProperty(this, var1);
}
public void setProperty(String var1, Object var2) {
this.getMetaClass().setProperty(this, var1, var2);
}
public int getRoot() {
return this.root;
}
public void setRoot(int var1) {
this.root = var1;
}
public Object getTestVar() {
return this.testVar;
}
public void setTestVar(Object var1) {
this.testVar = var1;
}
}
You can see that the line that prints out the value of the testVar field is represented by:
return var1[1].callCurrent(this, var1[2].call("The testVar:", this.testVar));
It means that no matter what value of testVar your subclass defines, the printTestVar method uses testVar field defined in the JobParams class. Period.
Using Groovy auto getter methods
There is one way you to implement the expected behavior. Every class field in Groovy has a getter method associated with that field compiled by Groovy for you. It means that you can access testVar by calling the getTestVar() method generated by the Groovy compiler. You can use it to override the value returned by a getter method for any field from the subclass. Consider the following example:
abstract class JobParams {
int root
def testVar=1
def setupRoot () {
println("The root");
}
def printTestVar () {
println("The testVar:" + getTestVar()); // <-- using a getTestVar() method instead a testVar field
}
}
class GradleJobParams extends JobParams {
}
def gjp = [
getTestVar: 3, // <-- stubbing getTestVar() method to return a different value
setupRoot:{
println("Override root");
}
] as GradleJobParams;
println("Starting");
gjp.printTestVar();
gjp.setupRoot();
Output:
Starting
The testVar:3
Override root

Groovy Collection setting empty inside method issue

I have a Groovy script with a function func(Map data) that takes a map and reinitializes passed variable with an empty map - data = [:]. The problem I face is that passing non-empty map to this function does not override a map with an empty one. Why is that?
Here is my Groovy code snippet:
Map x = [data1 : 10, data2 : 20]
def func(Map data) {
data = [:]
}
def func2(Map data) {
data.clear()
}
func(x)
// Setting x = [:] outside function does set x to empty
print x // prints [data1:10, data2:20]
func2(x)
print x // prints [:] (as .clear() is working)
BTW: it behaves the same for lists.
It happens, because Groovy compiler creates a new local variable data inside func(Map data) function. Take a look at decompiled code:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
import groovy.lang.Binding;
import groovy.lang.Script;
import java.util.Map;
import org.codehaus.groovy.runtime.InvokerHelper;
import org.codehaus.groovy.runtime.ScriptBytecodeAdapter;
import org.codehaus.groovy.runtime.callsite.CallSite;
public class test extends Script {
public test() {
CallSite[] var1 = $getCallSiteArray();
}
public test(Binding context) {
CallSite[] var2 = $getCallSiteArray();
super(context);
}
public static void main(String... args) {
CallSite[] var1 = $getCallSiteArray();
var1[0].call(InvokerHelper.class, test.class, args);
}
public Object run() {
CallSite[] var1 = $getCallSiteArray();
Map x = ScriptBytecodeAdapter.createMap(new Object[]{"data1", 10, "data2", 20});
var1[1].callCurrent(this, x);
var1[2].callCurrent(this, x);
var1[3].callCurrent(this, x);
return var1[4].callCurrent(this, x);
}
public Object func(Map data) {
CallSite[] var2 = $getCallSiteArray();
var2[5].callCurrent(this, "test");
Map var3 = ScriptBytecodeAdapter.createMap(new Object[0]);
return var3;
}
public Object func2(Map data) {
CallSite[] var2 = $getCallSiteArray();
return var2[6].call(data);
}
}
Check what func method is represented by at the bytecode level:
public Object func(Map data) {
CallSite[] var2 = $getCallSiteArray();
var2[5].callCurrent(this, "test");
Map var3 = ScriptBytecodeAdapter.createMap(new Object[0]);
return var3;
}
As you can see following Groovy code:
data = [:]
gets translated to something like this:
Map var3 = ScriptBytecodeAdapter.createMap(new Object[0]);
However, this kind of behavior is specific not only to Groovy, but for Java as well. Take a look at pretty similar example in Java:
import java.util.HashMap;
import java.util.Map;
final class TestJava {
public static void main(String[] args) {
Map<String, Object> map = new HashMap<>();
map.put("test", "foo");
func(map);
System.out.println("map outside = " + map);
}
static void func(Map<String, Object> map) {
map = new HashMap<>();
map.put("1", 2);
System.out.println("map inside = " + map);
}
}
If we run it we will see something similar to the Groovy use case:
map inside = {1=2}
map outside = {test=foo}
We could expect that func method should override map, but it is not happening here. If we decompile class file we will see something like this:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
import java.util.HashMap;
import java.util.Map;
final class TestJava {
TestJava() {
}
public static void main(String[] var0) {
HashMap var1 = new HashMap();
var1.put("test", "foo");
func(var1);
System.out.println("map outside = " + var1);
}
static void func(Map<String, Object> var0) {
HashMap var1 = new HashMap();
var1.put("1", 2);
System.out.println("map inside = " + var1);
}
}
As you can see from JRE perspective we are creating a new HashMap stored as var1 variable instead of overriding var0 variable passed to the method.
Btw, the Java version I used: OpenJDK 1.8.0_191

Anonymous Inner Class in Groovy not capturing final outer variable state

I'm running a test where I take 1,000 Strings that represent an ID. I create an ExecutorService with 100 threads, loop over the 1,000 Strings, and create a Callable for each. This works fine in Java, but I found in Groovy that the anonymous inner class Callable is not storing the iterated value.
Here is my test:
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
class CallableTest {
public static void main( String[] args ) throws InterruptedException, ExecutionException {
CallableTest test = new CallableTest();
test.runTest();
}
public List<String> setupTest(){
List<String> ids = new ArrayList<String>();
for(int i = 0; i < 1000; i++) {
ids.add( "ID_" + i );
}
return ids;
}
public void runTest() throws InterruptedException, ExecutionException {
ExecutorService executor = Executors.newFixedThreadPool(100);
List<Future<String>> futures = new ArrayList<Future<String>>();
List<String> ids = setupTest();
for(final String id : ids) {
Future<String> future = executor.submit(new Callable<String>() {
#Override
public String call() throws Exception {
return doSomethingWithId(id);
}
});
futures.add( future );
}
for(Future<String> future : futures) {
String message = future.get();
System.out.println(message);
}
}
public String doSomethingWithId(String id) {
return "Doing something with ID: " + id;
}
}
The problem in Groovy is here:
for(final String id : ids) {
Future<String> future = executor.submit(new Callable<String>() {
#Override
public String call() throws Exception {
// The ID value here is not the ID value from when the Callable was created
return doSomethingWithId(id);
}
});
futures.add( future );
}
As you can see in my comment, the id value when calling the method doSomethingWithId is not the same value as it was when the Callable was created. This leads to Doing something with ID: ID_999 being printed majority of the time.
If I copy this over to a Java project and run it, it runs as expected. I get Doing something with ID: ID_x from 0-999 with no duplicates.
Why doesn't this work in Groovy? My understanding is that Groovy should support anonymous inner classes, but it appears that the anonymous inner class Callable is not capturing the outer variable id state when it creates the anonymous class. I'm using Java 7 with Groovy 2.3.10.
UPDATE
I found that adding the following made this work:
for(final String id : ids) {
final String myId = id // This makes it work
Future<String> future = executor.submit(new Callable<String>() {
#Override
public String call() throws Exception {
return doSomethingWithId(myId);
}
});
futures.add( future );
}
Seems like Groovy isn't actually making the value returned from the iterator final?

Groovy closure does not modify a value in delegated object

The Groovy code shown below contains closures and a method. That format changed label and expected to receive that change label shows the problem and the requirement.
def method (String a, Closure c) {
Query q = new Query()
q.a = a
c.delegate = q
c.call()
def str = q.str
}
class Query
{
def str
def a
void key (String str, Closure cls) {
this.str = str
Pass p = new Pass()
p.a=a
cls.delegate=p
cls.call()
def val=p.a // Expcted to receive that change
println val
}
class Pass
{
String a
}
}
method("got") {
key ("got"){
a=a.toUpperCase() // Format Changed here
println a
}
}
Actual Output is :
GOT
got
But my expected output is:
GOT
GOT
Why that a = a.toUpperCase() doesn't change a value in p object after the cls.call()? How to pass this change ?
You have to change delegate resolving strategy for cls in key(String str, Closure cls) method to:
cls.resolveStrategy = Closure.DELEGATE_FIRST
Default strategy is Closure.OWNER_FIRST. In case of a Groovy script it means that the owner of this closure is an instance of a class that was generated by Groovy to run the script. In case of your Groovy script this class looks like this:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
import groovy.lang.Binding;
import groovy.lang.Closure;
import groovy.lang.Script;
import org.codehaus.groovy.runtime.GeneratedClosure;
import org.codehaus.groovy.runtime.InvokerHelper;
import org.codehaus.groovy.runtime.ScriptBytecodeAdapter;
import org.codehaus.groovy.runtime.callsite.CallSite;
public class my_groovy_script extends Script {
public my_groovy_script() {
CallSite[] var1 = $getCallSiteArray();
}
public my_groovy_script(Binding context) {
CallSite[] var2 = $getCallSiteArray();
super(context);
}
public static void main(String... args) {
CallSite[] var1 = $getCallSiteArray();
var1[0].call(InvokerHelper.class, my_groovy_script.class, args);
}
public Object run() {
CallSite[] var1 = $getCallSiteArray();
class _run_closure1 extends Closure implements GeneratedClosure {
public _run_closure1(Object _thisObject) {
CallSite[] var3 = $getCallSiteArray();
super(my_groovy_script.this, _thisObject);
}
public Object doCall(Object it) {
CallSite[] var2 = $getCallSiteArray();
class _closure2 extends Closure implements GeneratedClosure {
public _closure2(Object _thisObject) {
CallSite[] var3 = $getCallSiteArray();
super(_run_closure1.this, _thisObject);
}
public Object doCall(Object it) {
CallSite[] var2 = $getCallSiteArray();
Object var3 = var2[0].call(var2[1].callGroovyObjectGetProperty(this));
ScriptBytecodeAdapter.setGroovyObjectProperty(var3, _closure2.class, this, (String)"a");
return var2[2].callCurrent(this, var2[3].callGroovyObjectGetProperty(this));
}
public Object doCall() {
CallSite[] var1 = $getCallSiteArray();
return this.doCall((Object)null);
}
}
return var2[0].callCurrent(this, "got", new _closure2(this.getThisObject()));
}
public Object doCall() {
CallSite[] var1 = $getCallSiteArray();
return this.doCall((Object)null);
}
}
return var1[1].callCurrent(this, "got", new _run_closure1(this));
}
public Object method(String a, Closure c) {
CallSite[] var3 = $getCallSiteArray();
Query q = (Query)ScriptBytecodeAdapter.castToType(var3[2].callConstructor(Query.class), Query.class);
ScriptBytecodeAdapter.setGroovyObjectProperty(a, my_groovy_script.class, q, (String)"a");
ScriptBytecodeAdapter.setGroovyObjectProperty(q, my_groovy_script.class, c, (String)"delegate");
var3[3].call(c);
Object str = var3[4].callGroovyObjectGetProperty(q);
return str;
}
}
As you can see every Groovy script is actually a class that extends groovy.lang.Script class. There is one important thing about this class - it overrides:
public Object getProperty(String property)
public void setProperty(String property, Object newValue)
If you take a look at the source code of both methods you will see that it uses binding object to store and access all variables in scope of the closure. That's why the closure you pass to Query.key(String str, Closure cls) does not modify a a field of class Pass but instead it creates a local binding a with a value GOT. You can change this behavior by changing Closure's resolve strategy to Closure.DELEGATE_FIRST. This will do the trick because you explicitly set cls.delegate to p instance so the closure will firstly look for a field a in p instance. I hope it helps.
Updated Groovy script
def method(String a, Closure c) {
Query q = new Query()
q.a = a
c.delegate = q
c.call()
def str = q.str
}
class Query {
def str
def a
void key(String str, Closure cls) {
this.str = str
Pass p = new Pass()
p.a = a
cls.delegate = p
cls.resolveStrategy = Closure.DELEGATE_FIRST
cls.call()
def val = p.a // Expcted to receive that change
println val
}
class Pass {
String a
}
}
method("got") {
key("got") {
a = a.toUpperCase() // Format Changed here
println a
}
Output
GOT
GOT

Resources