有没有办法让 maven 和 eclipse 生成相同的 class 文件
Is there a way to get maven and eclipse to generate identical class files
我有一个使用 maven 的 java 项目。我还使用 M2Eclipse 插件,因此我可以在项目中使用 eclipse。我还使用 JRebel,以便 class 更改会自动反映在 运行 服务器中。
问题是我有时在 maven 中编译项目,有时在 eclipse 中编译它(更准确地说,eclipse 会在我保存 java 文件时自动编译 class 文件)。 eclipse 和 maven 编译器最终会为相同的 java 源文件生成不同的 class 文件,因此 JRebel 经常不必要地重新加载 classes。有时数百个 class 文件会被重新加载,即使它们的代码实际上并没有改变。它只是被一个系统或另一个系统重新编译。
比如这个空class:
public class Stack {
}
使用 maven 编译时,生成以下结构:
$ javap -verbose Stack.class
Classfile /tmp/Stack.class
Last modified Apr 21, 2016; size 240 bytes
MD5 checksum faf24015026a9cc09caa2c7388930d9a
Compiled from "Stack.java"
public class Stack
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #3.#13 // java/lang/Object."<init>":()V
#2 = Class #14 // Stack
#3 = Class #15 // java/lang/Object
#4 = Utf8 <init>
#5 = Utf8 ()V
#6 = Utf8 Code
#7 = Utf8 LineNumberTable
#8 = Utf8 LocalVariableTable
#9 = Utf8 this
#10 = Utf8 LStack;
#11 = Utf8 SourceFile
#12 = Utf8 Stack.java
#13 = NameAndType #4:#5 // "<init>":()V
#14 = Utf8 Stack
#15 = Utf8 java/lang/Object
{
public Stack();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 2: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this LStack;
}
SourceFile: "Stack.java"
并且当用 eclipse 编译时,产生:
$ javap -verbose Stack.class
Classfile /tmp/Stack.class
Last modified Apr 21, 2016; size 240 bytes
MD5 checksum 0d578ab592aebbb947fa85de391019e5
Compiled from "Stack.java"
public class Stack
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Class #2 // Stack
#2 = Utf8 Stack
#3 = Class #4 // java/lang/Object
#4 = Utf8 java/lang/Object
#5 = Utf8 <init>
#6 = Utf8 ()V
#7 = Utf8 Code
#8 = Methodref #3.#9 // java/lang/Object."<init>":()V
#9 = NameAndType #5:#6 // "<init>":()V
#10 = Utf8 LineNumberTable
#11 = Utf8 LocalVariableTable
#12 = Utf8 this
#13 = Utf8 LStack;
#14 = Utf8 SourceFile
#15 = Utf8 Stack.java
{
public Stack();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #8 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 2: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this LStack;
}
SourceFile: "Stack.java"
有没有办法让这两个系统从同一个源文件编译到同一个 class 文件,这样 JRebel 就不会不必要地重新加载 classes?
关于可能重复的编辑:
我不认为这与 this question 完全相同。这个问题是出于调试原因,使用 maven 的 ecj 编译器是否是正确的方法?如何配置它以使用配置文件;甚至可以做到吗?我的问题只是如何让 JRebel 不重新加载 classes 只是因为它们在没有代码更改的情况下被 javac/ecj 重新编译。
我的问题的解决方案最终可能与另一个问题的答案相似(例如:配置 maven 以使用 ecj),或者可能不同(例如配置 eclipse 以使用 javac;或其他完全不同的东西)。
这不仅仅是因为它们不同,还因为它们不同。问题是 class 文件将被保存、编译,然后在您在 Eclipse 中编辑它时重新加载(毕竟,这就是它的重点)。所以即使 class 文件的内容在语义上没有改变,它仍然会被重新加载。
直接回答问题:不,javac 和 ecj 是不同的编译器,因此不会产生相同的输出。当然,除了错误,它们会产生 compatible 输出。但是这个问题不是关于兼容性的,它实际上是一个关于与不同的构建触发器和 JRebel 打得很好的问题。我不了解 JRebel,所以我无法建议如何让它在这种情况下发挥得更好。
正如@gregg-449 所建议的,一种解决方法是将 Maven 配置为使用 ecj,如 中所述。
我有一个使用 maven 的 java 项目。我还使用 M2Eclipse 插件,因此我可以在项目中使用 eclipse。我还使用 JRebel,以便 class 更改会自动反映在 运行 服务器中。
问题是我有时在 maven 中编译项目,有时在 eclipse 中编译它(更准确地说,eclipse 会在我保存 java 文件时自动编译 class 文件)。 eclipse 和 maven 编译器最终会为相同的 java 源文件生成不同的 class 文件,因此 JRebel 经常不必要地重新加载 classes。有时数百个 class 文件会被重新加载,即使它们的代码实际上并没有改变。它只是被一个系统或另一个系统重新编译。
比如这个空class:
public class Stack {
}
使用 maven 编译时,生成以下结构:
$ javap -verbose Stack.class
Classfile /tmp/Stack.class
Last modified Apr 21, 2016; size 240 bytes
MD5 checksum faf24015026a9cc09caa2c7388930d9a
Compiled from "Stack.java"
public class Stack
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #3.#13 // java/lang/Object."<init>":()V
#2 = Class #14 // Stack
#3 = Class #15 // java/lang/Object
#4 = Utf8 <init>
#5 = Utf8 ()V
#6 = Utf8 Code
#7 = Utf8 LineNumberTable
#8 = Utf8 LocalVariableTable
#9 = Utf8 this
#10 = Utf8 LStack;
#11 = Utf8 SourceFile
#12 = Utf8 Stack.java
#13 = NameAndType #4:#5 // "<init>":()V
#14 = Utf8 Stack
#15 = Utf8 java/lang/Object
{
public Stack();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 2: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this LStack;
}
SourceFile: "Stack.java"
并且当用 eclipse 编译时,产生:
$ javap -verbose Stack.class
Classfile /tmp/Stack.class
Last modified Apr 21, 2016; size 240 bytes
MD5 checksum 0d578ab592aebbb947fa85de391019e5
Compiled from "Stack.java"
public class Stack
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Class #2 // Stack
#2 = Utf8 Stack
#3 = Class #4 // java/lang/Object
#4 = Utf8 java/lang/Object
#5 = Utf8 <init>
#6 = Utf8 ()V
#7 = Utf8 Code
#8 = Methodref #3.#9 // java/lang/Object."<init>":()V
#9 = NameAndType #5:#6 // "<init>":()V
#10 = Utf8 LineNumberTable
#11 = Utf8 LocalVariableTable
#12 = Utf8 this
#13 = Utf8 LStack;
#14 = Utf8 SourceFile
#15 = Utf8 Stack.java
{
public Stack();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #8 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 2: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this LStack;
}
SourceFile: "Stack.java"
有没有办法让这两个系统从同一个源文件编译到同一个 class 文件,这样 JRebel 就不会不必要地重新加载 classes?
关于可能重复的编辑:
我不认为这与 this question 完全相同。这个问题是出于调试原因,使用 maven 的 ecj 编译器是否是正确的方法?如何配置它以使用配置文件;甚至可以做到吗?我的问题只是如何让 JRebel 不重新加载 classes 只是因为它们在没有代码更改的情况下被 javac/ecj 重新编译。
我的问题的解决方案最终可能与另一个问题的答案相似(例如:配置 maven 以使用 ecj),或者可能不同(例如配置 eclipse 以使用 javac;或其他完全不同的东西)。
这不仅仅是因为它们不同,还因为它们不同。问题是 class 文件将被保存、编译,然后在您在 Eclipse 中编辑它时重新加载(毕竟,这就是它的重点)。所以即使 class 文件的内容在语义上没有改变,它仍然会被重新加载。
直接回答问题:不,javac 和 ecj 是不同的编译器,因此不会产生相同的输出。当然,除了错误,它们会产生 compatible 输出。但是这个问题不是关于兼容性的,它实际上是一个关于与不同的构建触发器和 JRebel 打得很好的问题。我不了解 JRebel,所以我无法建议如何让它在这种情况下发挥得更好。
正如@gregg-449 所建议的,一种解决方法是将 Maven 配置为使用 ecj,如