热代码替换应该适用于 Eclipse 中的 Groovy 吗?
Is hot code replace supposed to work for Groovy in Eclipse?
我想知道是否有人能够让 Groovy 热替换在 Eclipse 中可靠地工作。我找不到任何关于此的有用信息,所以我不确定它是否 b/c 它只适用于其他人?或者没有人使用 Eclipse 进行 Groovy 开发?
我已经尝试使用最新的 Eclipse (4.5 Mars) 和最新的 Groovy-Eclipse 插件(Groovy 来自 http://dist.springsource.org/snapshot/GRECLIPSE/e4.5/ 的 Eclipse 2.9.2),但我仍然不能获得可靠的热替换。
一些简单的热替换方案工作正常。然而,稍微复杂一点就会导致奇怪的 Groovy 异常。我在不同的情况下遇到不同的错误,但我能够在一个简单的 junit 中重现一个错误,所以我将用一些简化的域对象来演示那个错误。
HotSwapTests.groovy:
class HotSwapTests {
@Test
public void testHotReplace() {
DefaultTxView transactionGroup = new DefaultTxView();
List<Default> defaults = [];
Default d1 = new Default(ProducerAccountTransactionType.REPAID_AMOUNT, ParticipantAccountType.DEFAULT);
Default d2 = new Default(ProducerAccountTransactionType.REPAID_AMOUNT, ParticipantAccountType.DEFAULT);
d1.setCancelledDefault(d2);
defaults << d1;
transactionGroup.setDefaultTransactions(defaults);
while (true) {
Default result = transactionGroup.getRepaymentTransaction();
println result
}
}
}
DefaultTxView.groovy:
public class DefaultTxView {
def List<Default> defaultTransactions;
public Default getRepaymentTransaction() { return getTransactionOfType(REPAID_AMOUNT); }
public Default getTransactionOfType(ProducerAccountTransactionType type) {
return defaultTransactions.find { it.getType() == type };
}
Default.java:
The contents of this domain object are not really important - it's a simple POJO.
现在,为了测试热插拔,我在标记的行放置了一个断点:
while (true) {
Default result = transactionGroup.getRepaymentTransaction(); <<< break
println result
}
然后我转到 DefaultTxView.groovy
并修改传递给 find
方法的闭包内的代码:
public Default getTransactionOfType(ProducerAccountTransactionType type) {
return defaultTransactions.find { it.getType() == type && it.getCancelledDefault() == null};
}
保存文件时我没有收到任何警告或错误消息,但如果我现在尝试跨过修改后的行,我会收到以下异常:
java.lang.ArrayIndexOutOfBoundsException: 2
at ca.gc.agr.app.web.jsf.producer.DefaultTxView$_getTransactionOfType_closure1.doCall(DefaultTxView.groovy:15)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:90)
at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:324)
at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:278)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1016)
at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.call(PogoMetaClassSite.java:39)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:45)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:108)
at org.codehaus.groovy.runtime.callsite.BooleanReturningMethodInvoker.invoke(BooleanReturningMethodInvoker.java:48)
at org.codehaus.groovy.runtime.callsite.BooleanClosureWrapper.call(BooleanClosureWrapper.java:50)
at org.codehaus.groovy.runtime.DefaultGroovyMethods.find(DefaultGroovyMethods.java:3060)
at org.codehaus.groovy.runtime.dgm5.invoke(Unknown Source)
at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite$PojoMetaMethodSiteNoUnwrapNoCoerce.invoke(PojoMetaMethodSite.java:271)
at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite.call(PojoMetaMethodSite.java:53)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:116)
at ca.gc.agr.app.web.jsf.producer.DefaultTxView.getTransactionOfType(DefaultTxView.groovy:15)
at ca.gc.agr.app.web.jsf.producer.DefaultTxView$getTransactionOfType.callCurrent(Unknown Source)
at ca.gc.agr.app.web.jsf.producer.DefaultTxView.getRepaymentTransaction(DefaultTxView.groovy:11)
at ca.gc.agr.app.web.jsf.producer.DefaultTxView$getRepaymentTransaction[=16=].call(Unknown Source)
at ca.gc.agr.app.web.jsf.temp.HotSwapTests.testHotReplace(HotSwapTests.groovy:29)
当 运行 我的 webapp 在 TomCat 时,我得到非常相似的结果,但在修改该行后出现相同的异常。重新启动 junit,或 TomCat 使新线路正常工作,因此这绝对是一个热替换问题。
那我做错了什么?如有任何建议,我们将不胜感激。
我过去使用 eclipse 插件在 Web 开发环境中使用过热部署 with groovy successfully。
IIRC,我使用了groovyReset.jar、DCEVM和jdk1.7.
groovyReset.jar 应在 class 路径中并设置为 java agent。我使用了 groovy-eclipse 插件文件夹中的那个(比如 eclipse/plugins/org.codehaus.groovy_2.3.7.xx-201411061335-e44-RELEASE/extras/groovyReset.jar
)
-javaagent:/groovyReset.jar
无需重新部署即可立即看到新的闭包和方法。当然,在方法中包含一个简单的 LOC 也是可行的。有时我需要重新启动虚拟机,但仍然呼吸新鲜空气。
在你的情况下,我认为至少 groovyReset.jar 必须存在。它负责重置 metaclass。如果你反编译 groovy class,你可以使用 java.lang.Method
的数组检查通过反射调用的方法调用。热代码交换后,此数组出现故障,需要重置。
我想知道是否有人能够让 Groovy 热替换在 Eclipse 中可靠地工作。我找不到任何关于此的有用信息,所以我不确定它是否 b/c 它只适用于其他人?或者没有人使用 Eclipse 进行 Groovy 开发?
我已经尝试使用最新的 Eclipse (4.5 Mars) 和最新的 Groovy-Eclipse 插件(Groovy 来自 http://dist.springsource.org/snapshot/GRECLIPSE/e4.5/ 的 Eclipse 2.9.2),但我仍然不能获得可靠的热替换。
一些简单的热替换方案工作正常。然而,稍微复杂一点就会导致奇怪的 Groovy 异常。我在不同的情况下遇到不同的错误,但我能够在一个简单的 junit 中重现一个错误,所以我将用一些简化的域对象来演示那个错误。
HotSwapTests.groovy:
class HotSwapTests {
@Test
public void testHotReplace() {
DefaultTxView transactionGroup = new DefaultTxView();
List<Default> defaults = [];
Default d1 = new Default(ProducerAccountTransactionType.REPAID_AMOUNT, ParticipantAccountType.DEFAULT);
Default d2 = new Default(ProducerAccountTransactionType.REPAID_AMOUNT, ParticipantAccountType.DEFAULT);
d1.setCancelledDefault(d2);
defaults << d1;
transactionGroup.setDefaultTransactions(defaults);
while (true) {
Default result = transactionGroup.getRepaymentTransaction();
println result
}
}
}
DefaultTxView.groovy:
public class DefaultTxView {
def List<Default> defaultTransactions;
public Default getRepaymentTransaction() { return getTransactionOfType(REPAID_AMOUNT); }
public Default getTransactionOfType(ProducerAccountTransactionType type) {
return defaultTransactions.find { it.getType() == type };
}
Default.java:
The contents of this domain object are not really important - it's a simple POJO.
现在,为了测试热插拔,我在标记的行放置了一个断点:
while (true) {
Default result = transactionGroup.getRepaymentTransaction(); <<< break
println result
}
然后我转到 DefaultTxView.groovy
并修改传递给 find
方法的闭包内的代码:
public Default getTransactionOfType(ProducerAccountTransactionType type) {
return defaultTransactions.find { it.getType() == type && it.getCancelledDefault() == null};
}
保存文件时我没有收到任何警告或错误消息,但如果我现在尝试跨过修改后的行,我会收到以下异常:
java.lang.ArrayIndexOutOfBoundsException: 2
at ca.gc.agr.app.web.jsf.producer.DefaultTxView$_getTransactionOfType_closure1.doCall(DefaultTxView.groovy:15)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:90)
at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:324)
at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:278)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1016)
at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.call(PogoMetaClassSite.java:39)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:45)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:108)
at org.codehaus.groovy.runtime.callsite.BooleanReturningMethodInvoker.invoke(BooleanReturningMethodInvoker.java:48)
at org.codehaus.groovy.runtime.callsite.BooleanClosureWrapper.call(BooleanClosureWrapper.java:50)
at org.codehaus.groovy.runtime.DefaultGroovyMethods.find(DefaultGroovyMethods.java:3060)
at org.codehaus.groovy.runtime.dgm5.invoke(Unknown Source)
at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite$PojoMetaMethodSiteNoUnwrapNoCoerce.invoke(PojoMetaMethodSite.java:271)
at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite.call(PojoMetaMethodSite.java:53)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:116)
at ca.gc.agr.app.web.jsf.producer.DefaultTxView.getTransactionOfType(DefaultTxView.groovy:15)
at ca.gc.agr.app.web.jsf.producer.DefaultTxView$getTransactionOfType.callCurrent(Unknown Source)
at ca.gc.agr.app.web.jsf.producer.DefaultTxView.getRepaymentTransaction(DefaultTxView.groovy:11)
at ca.gc.agr.app.web.jsf.producer.DefaultTxView$getRepaymentTransaction[=16=].call(Unknown Source)
at ca.gc.agr.app.web.jsf.temp.HotSwapTests.testHotReplace(HotSwapTests.groovy:29)
当 运行 我的 webapp 在 TomCat 时,我得到非常相似的结果,但在修改该行后出现相同的异常。重新启动 junit,或 TomCat 使新线路正常工作,因此这绝对是一个热替换问题。
那我做错了什么?如有任何建议,我们将不胜感激。
我过去使用 eclipse 插件在 Web 开发环境中使用过热部署 with groovy successfully。
IIRC,我使用了groovyReset.jar、DCEVM和jdk1.7.
groovyReset.jar 应在 class 路径中并设置为 java agent。我使用了 groovy-eclipse 插件文件夹中的那个(比如 eclipse/plugins/org.codehaus.groovy_2.3.7.xx-201411061335-e44-RELEASE/extras/groovyReset.jar
)
-javaagent:/groovyReset.jar
无需重新部署即可立即看到新的闭包和方法。当然,在方法中包含一个简单的 LOC 也是可行的。有时我需要重新启动虚拟机,但仍然呼吸新鲜空气。
在你的情况下,我认为至少 groovyReset.jar 必须存在。它负责重置 metaclass。如果你反编译 groovy class,你可以使用 java.lang.Method
的数组检查通过反射调用的方法调用。热代码交换后,此数组出现故障,需要重置。