我有一个内部编写的工具来为我们的应用程序创建补丁。
它检查scm中哪些类被更改并使用javac
编译它们
然后我们将创建的jar添加到类路径中。
在过去,我们发现存在以下问题:
如果我在类A中更改了方法返回类型,并且类B使用该方法,则类A签名发生更改,当类B调用该方法时,我们得到NoSuchMethodError
。
但是,现在我有一个不同的情况,类静态变量被更改,我得到:
java.lang.NoClassDefFoundError: Could not initialize class
。
你知道造成这种情况的原因吗?
有什么方法可以告诉我在更改类时需要编译哪些类?
答案 0 :(得分:4)
开发一个我怀疑不可靠的解决方案听起来很费劲。
我会为每个版本构建整个应用程序。要创建补丁,我会比较原始发行版中生成的类或文件。任何已更改的文件都将包含在内。
这更好,因为
答案 1 :(得分:3)
此外,public
常量的内联可能是难以定位的问题的根源,因为它们不会导致异常或错误,但会导致无声的错误行为。
假设您有一个 A 类,其中一些public static final
字段属于基本类型或String
,其值可在编译时确定。
public class A {
public static final String GREETING = "Hello";
...
}
然后,如果另一个类 B 访问此字段,则编译器会内联常量 - 即将A.GREETING
引用替换为其值"Hello"
。没有关于恒定值来自何处的信息。
现在出现问题 - 如果您将GREETING
的值更改为"Hi"
并仅重新编译 A 类,则类 B中的内联值将保持不变,直到您重新编译它为止。因此,正如其他人已经指出的那样,从头开始重建整个应用程序通常是一个更好的主意。
讨论此问题的好文章: http://marxsoftware.blogspot.com/2009/09/inconstant-constants-in-java.html
一些相关的SO问题:
Is Java guaranteed to inline string constants if they can be determined at compile time
答案 2 :(得分:1)
如果更改了A类的签名,则不必重新编译调用此类的所有类。您必须更改这些类的实现。
例如,如果您的类A具有由类B调用的方法foo()
,现在您将其名称更改为bar()
,则必须更改类B的源代码。否则您将获得{ {1}}。
但是,如果您不更改接口但只修改A类的内部实现,则除了此类本身之外,您不必重新编译任何内容。您只需在编译时创建适当的类路径。类路径必须包含类A的直接依赖关系和依赖关系的依赖关系。它必须不包含第3级依赖项(即依赖项依赖项的依赖项)。但是IMHO在编译补丁时处理类路径的最简单方法就是提供现有应用程序的完整类路径。