5

我们有一些使用 Groovy 的遗留代码,我们想从应用程序中删除 Groovy,因此,我们需要获取使用 gmaven 插件后生成的 java 源代码。

基本上,换句话说,我正在动态生成新类(使用 gmaven Groovy maven 插件),并且我希望能够获得此类生成的类的 java 源代码。

我研究了一下,可以看到这个插件的唯一目标是

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

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

4

4 回答 4

4

我对 gmaven 插件不是很熟悉,但我认为它会将 groovy 代码编译成字节码。在这种情况下,您可以使用字节码反编译器,这里有一个不错的列表。过去我使用过 JAD,它非常好。最好的也会尝试根据类名创建有意义的变量名。

不过有一个警告——Groovy 对象是从 GObject 派生的,而不是 java.lang.Object,因此您可能需要保留 groovy jar 直到 groovy->java 移植完成。另外,请准备好它不会是一个非常容易阅读的java ...

于 2012-10-31T07:35:43.853 回答
2

它可能超出了您的范围(1 岁),但我与同样的问题作斗争并找到了一种从反编译的 groovy 类中检索算法(而不是 java 源代码)的方法。

你可能想看看: http: //michael.laffargue.fr/blog/2013/11/02/decompiling-groovy-made-classes/

于 2013-11-19T08:33:05.480 回答
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 库。

于 2012-10-31T07:47:49.197 回答
1

这个问题前段时间已经在邮件列表中[0]。总而言之:从 Groovy 到 Java 很难实现,因为 Java 中不存在语言结构和 API(如果您确实想完全删除 Groovy 依赖项)。

尤其是在引入调用站点缓存和其他性能优化技术后,生成的 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

于 2012-10-31T09:26:28.413 回答