如何获取由Groovy生成的Java源代码

5
我们有一些使用Groovy编写的遗留代码,现在想从应用程序中移除Groovy。因此需要获取使用gmaven插件生成后的Java源代码。
换句话说,我正在动态生成新类(使用gmaven Groovy Maven插件),并且希望能够获得这些生成类的Java源代码。
我做了一些研究,发现该插件唯一的目标是:
<goal>generateStubs</goal>
<goal>compile</goal>
<goal>generateTestStubs</goal>
<goal>testCompile</goal>

我看不到任何目标可以让您获取完整的Java源代码实现,桩代码对我们来说是不够的,因为我们需要最终的实现源代码才能摆脱Groovy。


1
我不熟悉Groovy,但是它的编译是否实际上生成了一个中间的Java源代码呢?我表示怀疑。如果Groovy的编译直接到字节码,那么你只能反编译字节码并将其转换为相应的Java源代码。无论如何,与其经历这样的过程,可能需要大量的代码整理,为什么不直接使用Java重写呢? - Adrian Shum
为什么不将Groovy类重写为Java?我假设您有源代码,因为您正在构建它。以目前的形式,这个问题并不是很有意义。您能详细说明一下吗? - tim_yates
Adrian,Tim感谢你们的回答。Adrian:谢谢Adrian,也许你是对的。Tim:至少这个问题对我来说是有意义的,因为我不想处理Groovy :-)。我只是不想/没有时间去完成那个Groovy代码,因为它是遗留的,所以我没有做它,我只是试图避免这样做。也许在创建Java类之前,Groovy源代码被转换为Java字节码,我只想知道是否有一种快速简便的方法询问Groovy生成的Java源代码。如果Groovy的编译不生成Java源代码,那么我将使用反编译器。 - jhack
4个回答

4
我不太熟悉gmaven插件,但我认为它将Groovy代码编译成字节码。在这种情况下,您可以使用字节码反编译器,有一个很好的列表在这里。过去我曾使用过JAD,效果还不错。最好的工具也会尝试根据类名创建有意义的变量名。
但是要注意,Groovy对象源于GObject而不是java.lang.Object,因此在进行Groovy-> Java移植之前,您可能需要保留Groovy jar文件。另外,请准备好它可能不是很容易理解的Java代码...

谢谢David!我考虑过反编译器,但是groovy不允许你获取Java源代码,这看起来很奇怪/令人烦恼...最好的祝福! - jhack

2

1
该链接已失效,但可以在WaybackMachine中找到 https://web.archive.org/web/20140414205924/http://michael.laffargue.fr/blog/2013/11/02/decompiling-groovy-made-classes/ - opticyclic

1

生成的存根对您来说是无用的。它们只是其名称所示的存根。

当进行联合Java / Groovy编译时,存根才有用。这是因为在Java / Groovy混合项目中涉及两个编译器。

  1. 解析Groovy
  2. 创建存根
  3. 编译Java和存根(使用javac)
  4. 继续Groovy编译(使用groovyc)

Groovy代码将使用groovyc编译器编译,结果是字节码。

这是一个生成的存根示例:

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;}
}

正如您所见,这里没有任何有用的东西。而且您仍然需要依赖一些 Groovy 库。


嗨maba,也许我的问题没有表达清楚,对此我很抱歉,但我可以获得存根,是的,我的问题在于无法获取已实现的Java源文件。:-)。谢谢你的回答!干杯 - jhack

1

这个问题在邮件列表上已经讨论过一段时间了[0]。总结一下:由于Java中没有可用的语言结构和API(如果您确实想完全删除Groovy依赖),因此将Groovy转换为Java很难实现。

特别是随着调用站点缓存和其他性能优化技术的引入,生成的Java代码看起来会像这样(为了简单起见,我只是将一些脚本扔进了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


Andre,谢谢,它看起来很复杂...现在我明白了为什么它只是从Groovy转换为Java字节码...会尝试使用反编译器获取一些东西... 非常感谢您精确的答案。 最好的问候 Javier - jhack

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接