I have a tool we wrote internal to create patches for our application.
It checks in scm what classes were changed and compile them using javac
.
Then we add the created jar to the classpath.
In the past we discovered that there is a problem with that:
If I changed method return type in class A, and class B uses that method then the class A signature changed and we get NoSuchMethodError
when class B call that method.
However, now I have a different case that class static variables were changed and I get:
java.lang.NoClassDefFoundError: Could not initialize class
.
Do you know what is causing this?
Is there any way to tell which classes I need to compile when a class was changed?

- 14,865
- 26
- 84
- 140
-
1I'm wondering if it wouldn't be easier to recompile everything and use a diff tool to find the binary files that actually changed. – Jens Schauder Dec 25 '11 at 11:25
-
I've read several detailed discussions of this problem. The short answer is that it's not straightforward to know what needs recompiling, and there are no standalone tools that do it. The Eclipse incremental compiler can do it, but only as part of doing compilation. @JensSchauder's suggestion seems like a good one. – Tom Anderson Dec 25 '11 at 15:07
3 Answers
It sounds like a lot of effort to develop a solution I suspect is unreliable.
I would build the whole application, for every release. To create a patch, I would compare the class or file produced against that in the original distribution. Any files which have changed would be included.
This is better because
- you don't have to understand all the consequences of changing a constant, method or class.
- if you change something incidental like formatting or comments, there is no need to update the file.
- you can have confidence that applying the patch is exactly the same and giving a full distribution.

- 525,659
- 79
- 751
- 1,130
Also, inlining of public
constants may be a source of problems that are hard to target, since they don't cause exceptions or errors, but cause silent wrong behaviour.
Lets say you have a class A with some public static final
fields that are of a primitive type or a String
and whose values can be determined at compile time.
public class A {
public static final String GREETING = "Hello";
...
}
Then if another class B accesses this field, the compiler inlines the constant - i.e. replaces the A.GREETING
reference with its value "Hello"
. No information of where the constant value comes from is kept.
Now comes the trouble - if you change the value of GREETING
to lets say "Hi"
and recompile only the class A, the inlined value in class B will remain unchanged until you recompile it too. Therefore, it is usually a better idea to rebuild the entire application from scratch, as others have already pointed out.
A nice article discussing this problem: http://marxsoftware.blogspot.com/2009/09/inconstant-constants-in-java.html
Some related SO questions:
Is Java guaranteed to inline string constants if they can be determined at compile time
If you change signature of class A you do not just have to recompile all classes that call this class. You have to change the implementation of these classes.
For example if you class A had method foo()
that was called by class B and now you change its name to bar()
you have to change the source code of class B. Otherwise you will get NoSuchMethodError
.
If however you do not change interfaces but just modify the internal implementation of class A you do not have to recompile anything except this class itself. You just have to create appropriate classpath when compiling. The class path must include direct dependencies of class A and dependencies of dependencies. It must not contain 3rd level dependencies (i.e. dependencies of dependencies of dependencies). But IMHO the easiest way to deal with class path when compiling the patch is just provide the full classpath of existing application.

- 114,158
- 16
- 130
- 208
-
1There are some signature changes where (at least some) usages can simply be recompiled, without any source changes - For example, if the return type is still assignable to the same type used before, or if argument types are now more wide. Similar for changes of constants. – Paŭlo Ebermann Dec 25 '11 at 11:34