How to get the Groovy generated java source code
Asked Answered
D

4

6

We have some legacy code with Groovy, and we want to remove Groovy from the application, so, we need to get the java source code generated after using the gmaven plug-in.

Basically, in other words I am dynamically generating new classes (using gmaven Groovy maven plug in) and I would like to be able to obtain the java source code of such generated classes.

I researched a little bit and can see that the only goals for this plug in are

<goal>generateStubs</goal>
<goal>compile</goal>
<goal>generateTestStubs</goal>
<goal>testCompile</goal>

I can't see any goal that allows you to obtain the fully implemented java source code, the stub code is not enough for us as we need the final implementation source code in order to get rid of Groovy.

Dibru answered 31/10, 2012 at 7:2 Comment(3)
I am not familiar with Groovy, but is compilation of Groovy actually generates an intermediate Java source? I doubt it. If compilation of Groovy is directly to bytecode, you have no choice but only decompiling the bytecode and turn it to corresponding Java source. Anyway, instead of going through such process which probably need a lot of code tidy-up, why not simply rewrite it using Java?Phone
Why not just re-write the Groovy classes into Java? I assume you have source code if you're building it. This question doesn't make much sense in its current form. Can you elaborate?Cornelie
Adrian , Tim thanks for answering, Adrian: Thanks Adrian, maybe your right. Tim: The question makes sense to me at least, because I don't want to deal with Groovy :-). I just don't want/have time to get that done, that groovy code is legacy, so I didn't do it, I'm just trying to avoid doing that. Maybe the groovy source code is converted to java bytecode before creating the java class, I just want to know if there is a quick and easy way get to ask Groovy for the generated java source code. If compilation of Groovy does not generate java source code, then I'll use a decompiler.Dibru
L
5

I'm not very familiar with the gmaven plugin, but I assume it compiles the groovy code into byte code. In this case, you can use a byte code decompiler, there is a nice list here. In the past I've used JAD and it was quite nice. The best ones will also try to create meaningful variable names based on class names.

One warning though - Groovy objects are derived from GObject, not java.lang.Object, so you would probably need to keep the groovy jar until the groovy->java porting is done. Also, be prepared that it won't be a very easy to read java...

Liss answered 31/10, 2012 at 7:35 Comment(1)
Thanks David !, I thought about the decompilers, yes, but it looked weird/annoying to me that groovy doesn't allow you to get your java source code ... Best Regards !Dibru
S
3

It may be out of your scope (1 year old) but I fought against the same problem and found a method to retrieve the algorithm (not the java source code) from the decompiled groovy classes.

You may want to take a look : http://michael.laffargue.fr/blog/2013/11/02/decompiling-groovy-made-classes/

Samuelson answered 19/11, 2013 at 8:33 Comment(1)
The link is now dead but can be found in the WaybackMachine web.archive.org/web/20140414205924/http://michael.laffargue.fr/…Latvia
B
1

The generated stubs will be useless for you. They are just what their names suggests: stubs.

The stubs are only useful when doing joint java/groovy compilation. That's because there are two compilers involved in a java/groovy mixed project.

  1. Parse groovy
  2. Create stubs
  3. Compile java and stubs (using javac)
  4. Continue groovy compilation (using groovyc)

The groovy code will be compiled using groovyc compiler and the result is byte code.

This is an example of a generated stub:

package maba.groovy;

import java.lang.*;
import java.io.*;
import java.net.*;
import java.util.*;
import groovy.lang.*;
import groovy.util.*;

@groovy.util.logging.Log4j() public class Order
    extends java.lang.Object  implements
    groovy.lang.GroovyObject {
    public  groovy.lang.MetaClass getMetaClass() { return (groovy.lang.MetaClass)null;}
    public  void setMetaClass(groovy.lang.MetaClass mc) { }
    public  java.lang.Object invokeMethod(java.lang.String method, java.lang.Object arguments) { return null;}
    public  java.lang.Object getProperty(java.lang.String property) { return null;}
    public  void setProperty(java.lang.String property, java.lang.Object value) { }
    public  int getPrice() { return (int)0;}
    public  void setPrice(int value) { }
    public  int getQuantity() { return (int)0;}
    public  void setQuantity(int value) { }
    @java.lang.Override() public  java.lang.String toString() { return (java.lang.String)null;}
}

As you can see there is nothing useful. And you will still depend on some groovy libraries.

Besant answered 31/10, 2012 at 7:47 Comment(1)
Hi maba, maybe my question wasn't clear, sorry for that, but I can get the Stubs, yes, I just can't get the implemented java source files, that's the problem. :-). Thanks for answering ! CheersDibru
B
1

This question has been on the mailing-list some time ago [0]. To summarize: Groovy to Java is hard to achieve since there are language constructs and APIs (if you do want to totally remove the Groovy dependency) that are not available in Java.

Especially with the introduction of call-site caching and other performance optimizing techniques the generated Java code would look a lot like this (for the matter of simplicity I just threw some script into JD-GUI [1]):

public class script1351632333660 extends Script
{
public script1351632333660()
{
script1351632333660 this;
CallSite[] arrayOfCallSite = $getCallSiteArray();
}

public script1351632333660(Binding arg1)
{
Binding context;
CallSite[] arrayOfCallSite = $getCallSiteArray();
ScriptBytecodeAdapter.invokeMethodOnSuperN($get$$class$groovy$lang$Script(), this, "setBinding", new Object[] { context });
}

public Object run()
{
CallSite[] arrayOfCallSite = $getCallSiteArray(); Object items = ScriptBytecodeAdapter.createList(new Object[0]);
Object[] item = (Object[])ScriptBytecodeAdapter.castToType(ScriptBytecodeAdapter.createList(new Object[] { "Fluff", arrayOfCallSite[1].callConstructor($get$$class$java$util$Date()), (Integer)DefaultTypeTransformation.box(11235813) }), $get$array$$class$java$lang$Object());

arrayOfCallSite[2].call(items, item);

arrayOfCallSite[3].callCurrent(this, items);

ValueRecorder localValueRecorder = new ValueRecorder();
try
{
Object tmp102_101 = items; localValueRecorder.record(tmp102_101, 8);
Object tmp126_121 = arrayOfCallSite[4].call(tmp102_101, new script1351632333660._run_closure1(this)); localValueRecorder.record(tmp126_121, 14); if (DefaultTypeTransformation.booleanUnbox(tmp126_121)) localValueRecorder.clear(); else ScriptBytecodeAdapter.assertFailed(AssertionRenderer.render("assert items.findAll { it }", localValueRecorder), null);  } finally {
localValueRecorder.clear(); throw finally; } return null; return null; } 
static { __$swapInit();
Long localLong1 = (Long)DefaultTypeTransformation.box(0L);
__timeStamp__239_neverHappen1351632333665 = localLong1.longValue();
Long localLong2 = (Long)DefaultTypeTransformation.box(1351632333665L);
__timeStamp = localLong2.longValue(); } 
class _run_closure1 extends Closure implements GeneratedClosure { public _run_closure1(Object _thisObject) { super(_thisObject); } 
public Object doCall(Object it) { CallSite[] arrayOfCallSite = $getCallSiteArray(); return it; return null;
}

// ...

[0] http://groovy.329449.n5.nabble.com/Java-lt-gt-Groovy-converters-td337442.html

[1] http://java.decompiler.free.fr

Betoken answered 31/10, 2012 at 9:26 Comment(1)
Andre, thanks, it looks complex ... Now I understand why it just goes from groovy to java bytecode ... will try to get something qith the decompiler them ... Thanks a lot for your precise answer. Best regards JavierDibru

© 2022 - 2024 — McMap. All rights reserved.