So, I'm working in eclipse were everything compiles and runs correctly. However, when compiling under ant for the build server, A large number of tests fail with a NoSuchMethodError saying:
class A implements B
interface B extends C
C requires method getSyncID() // standard getter for an int field.
A.java contains getSyncID()
A.class contains getSyncID()
and yet the Error is still thrown.
Does anyone know how the hell this could happen? how to fix it.
This happens when class files get out of sync with each other; in other words, one was compiled to a new version while another one wasn't. Try cleaning and rebuilding from scratch.
The problem occurs when the class loader discovers that a method in one class (A) calls a method in another class (B) that does not exist. The root cause is that the class B that the class loader sees is different to the class B that the compiler saw when it compiled A.
The most common cause of this problem is as #MarkPeters says - that your ".class" files have gotten out of sync with the ".java" files and need to be recompiled from scratch.
Another possibility is that you have an old copy of some of the ".class" files on the classpath when you try to run the application.
But either way, you have to believe the classloader. If it says that the method is not there, then it is not there ... in the particular ".class" file that it is loading. If the method appears to be there in the ".class" file, then that is evidence that you are loading a different version of the file earlier in the classpath!
Related
I am studying the jvm class loading process,and got know the following fact:
the Class Loader Subsystem uses a delegation hierarchy algorithm
It will search in order from BootStrap path --> extension path-->Application path.
Then I want to "try" this in real code as below :
create a class A, and Class B; Class A with the main() method and a type B variable.
after compiling , I used jar command to get jar file of Class B from B.class, then delete the B.class file, put the B.jar file to jdk/jre/lib/ext
(Since the oracle doc says the extClassLoader will not search any loose classfile in jdk/jre/lib/ext).
The result is ClassNotFoundException .so My question is :
1) Does jvm not allow loading of user's clasfile from BootStrap and Extension classpath ?
2) if so , why its loading using a delegation hierarchy algorithm which seems to result in low efficiency ?
tks ....
Things seem bit strange.
After several times of ClassNotFoundException , I got java.lang.IllegalAccessError which at least indicates the extclassloader is trying to access my class B.jar
since I did not declare a package for Class A and B, This might be the reason, so I just added a public modifier before my Class B and did the same as above , finally the ExtClassLoader works withs my B.jar.
though still no idea why first times the jvm ignores my jar file and later on read it ....seems jvm keeps a catche of directory list(of BootStrap and Ext class path)which does not update just-in-time like my computer system
It sounds like you are doing something wrong in your deployment.
I have used lib/endorsedin the past without problem even for internal java.lang* classes.
The JVM doesn't cache anything from one run to the next.
I have a project I am working on in WebSphere Integration Developer 7.0 where I am trying to reference a public method I just wrote from a different package. I have an import statement included for the class my new method is in.
When I create an instance of my class and try to call my new method, I get a standard "method 'x' is undefined for the type 'y'" compiler error, indicating my new method isn't being recognized.
What's really peculiar to me is that when I press F3 to open the declaration of my class instance, I'm taken to the class declaration in the .class file rather than the .java file. I tried calling several other non-static methods from my class instance, which were recognized and also took me to the .class file when I opened their declarations. I have my .class and .java files for this class in the same directory.
I have cleaned and rebuilt the project to see if that would have any affect, but still see the same behavior.
So my question is, why would my IDE open the class and method declarations in the .class file rather than the .java file? I've never seen that before - could that be expected behavior within WID in this case, or does that suggest a problem with my environment?
Why the IDE opens the .class file
Because, that is what the IDE finds listed in the build path.
It is very common behaviour.
For example, lets say we have 2 projects - project F and project B.
Project `F` - front end
Project `B` - back end
Now, F depends on B for its compilation but B can be compiled independently.
So, in order to build F, we first build B and then copy the artifacts generated as part of the build in the build path of F or if we don't want to do copy/ paste, we just make F's build path point to the artifact generated by B's build.
Now, we can build F. Here, what F actually points to are a bunch of class files not the source.
And, now if we try to access any files of B from F - IDE will intelligently open the .class file(s) for us.
created a "java" class in eclipse, when try to use same class name in same package again it showing error "type already defined". when write program in notepad and running in command prompt it overwriting class and not showing error, why not overwriting when using eclipse, to overwrite what need to do.
EDIT: Okay, through comments I think we've actually got to the bottom of the problem. The situation is:
Compiling under Windows
There are two classes in the same file, with the same name except for case
The command-line compiler doesn't noticed that the two class files will become one due to Windows file system case-insensitivity, but Eclipse does
So as an example:
class Foo {}
class foo {}
The Eclipse error message also makes this pretty clear, by mentioning case:
Class file collision: A resource exists with a different case: '/Sandbox/bin/Foo.class'.
As with my earlier answer, my advice is still the same don't do this.
Earlier answer...
I suspect that when you used the same name in a different file and compiled from the command line, you only specified one of them to compile - whereas Eclipse will try to compile all the classes present. If you specified both of the files, you would have got an error:
For example:
X.java
class Foo {}
Y.java
class Foo {}
> javac X.java Y.java
Y.java:1: error: duplicate class: Foo
class Foo {}
^
1 error
Basically, don't do this. Either rename one of the classes, or delete one of the files.
If Eclipse would let you create a class with the same name in the same package, it would override the existing file containing the original class.
Eclipse assumes that such an attempt is an error on your part.
You have no reason to do that, since you can simply edit the existing class.
Recently have been touched Java classloaders and suddenly recognized that do not fully understand what happens step-by-step when someone calls
java -jar App.jar
Well I guess
a new instance of JVM is created
it uses ClassLoader to load main class and other classes
byte-code is started to execute from main() method
But still I suppose there are many things I need to know more about it.
Who and how decides which classes should be loaded at startup and which once needed?
I have found two related questions but there it is not explained how to apply that to Java realities.
What happens when a computer program runs?
What happens when you run a program?
•Who and how decides which classes should be loaded at startup and which once needed?
we need to understand the fundamentals of java class loading. Initially bootstrap classloader (it is implemented natively as part of the VM itself) is responsible for loading core system classes. Then there are other class loaders as well like Extension, system, user-defined(optional) class loaders which decide when and how classes should be loaded.
Fundamentals of class loading
The decision is made by the classloader. There are different implementations, some of which pre-load all classes they can and some only loading classes as they are needed.
A class only needs to be loaded when it is accessed from the program code for the first time; this access may be the instantiation of an object from that class or access to one of its static members. Usually, the default classloader will lazily load classes when they are needed.
Some classes cannot be relied on to be pre-loaded in any case however: Classes accessed via Class.forName(...) may not be determined until this code is actually exectued.
Among other options, for simple experiments, you can use static initializer code to have a look at the actual time and order in which classes are actually loaded; this code will be executed when the class is loaded for the first time; example:
class SomeClass {
static {
System.out.println("Class SomeClass was initialized.");
}
public SomeClass() {
...
}
...
}
Your example shows an executable jar, which is simply a normal java archive (jar) with an extra key/value pair in it's manifest file (located in folder "META_INF"). The key is "Main-Class" and the value the fully qualified classname of that class whose "main" method will be executed, if you "run" the jar just like in your example.
A jar is a zip file and you can have a look inside with every zip archive tool.
Whenever you compile a Java program the following steps takes place
First the Class Loader loads the class into the JVM.
After giving the command javac filename.java the compiler checks for compile time errors and if everything is fine then it will generate the .Class files(byte code).
This will be the first phase.
Later the interpreter checks for the runtime errors and if everything is fine without exceptions then the interpreter converts the byte code to executable code.
First phase in java is done by the JIT compiler(Just In Time).
Java class files inside jars can be easily replaced and modified. For instance, the following command can be used to replace a compiled class file within a jar:
jar uf JarFile.jar com\something\Class.class
If the class file was replaced with a file such that no dependencies were broken, then the code is still able to execute. The same happens with class files that are not inside jars.
Is there any way to validate a set of class files (whether inside a jar or not) to see if all their dependencies are present and not broken?
I do not want to prevent class files from being modified but rather to be able to verify that changes are valid (with respect to dependencies). The compiler does this check (dependency-check) at compile time, but once the classes are compiled, how can one verify the class files themselves?
You might have sealing and signing JARs in mind.
Update:
Apparently I've missed the mark with my first guess.
What do you plan to do if they're not? If they're a 3rd party, I'd say that you've got little choice besides reporting to the bug database that the download is bad.
If you mean "I want to make sure that all their 3rd party JAR dependencies are correct", you've got a much bigger problem. Most downloads that I know of (e.g. Spring) make dependencies available using Maven. That's the best you can do.
If you mean you want to check your own dependencies, I'd say that testing would reveal any errors you've made.
Just loading the class will ensure that.
no, you cannot.
at least: not really.
the problem is that java loads classes at runtime only when needed. so eventually it might be alright to remove a class from the jar file and as long as no code referencing that class is executed things run very smoothly.
consider this example:
class A{ public static void main( String args[] ){ out.println( "hello" ); } }
class B{}
compile this, put it in a jar, remove the B.class from it, no problem there :)
now you might think you can go through each .class file, check what classes it references and see if the files are all there. not only is this painful, it is also incomplete. you will never quite catch files loaded with reflection because their class names might be constructed just at runtime.
my advice: don't go there. if someone removes a class file it's their own fault.
the best thing you can do is (but only if this really really worries you) try to catch ClassNotFoundExceptions at runtime (look into thread.setUncaughtExceptionHandler)