简体   繁体   中英

NoSuchFieldError Java

I am getting a NoSuchFieldError in my code, now oracle isn't very clear about why this error is thrown only saying: this error can only occur at run time if the definition of a class has incompatibly changed.

Can someone explain to me how one could 'incompatibly change' a class? The class I am talking about extends quite allot of classes so I suspect it might have to do with that but I don't know where to start looking or what I'm looking for.

This error is typically thrown if you only partially recompile your code. You've got old code that is referencing a field that no longer exists in the recompiled class files.

The solution is to clean out all the class files and compile everything from fresh.

Update: If you still get the same error after recompiling everything, then you're probably compiling against one version of an external library and using another at runtime.

What you need to do now is first identify the class that is causing the problem (it looks like you have done this already) and then run your application with the -verbose:class command line option. It will dump a lot of class loading information on your standard out and you'll be able to find out where the problematic class is exactly loaded from.

When the compiler compiled the code that is throwing the error, there was some other class with a field, and your class could access this field (either reading or changing the value).

On runtime, the other class somehow has no field with this name, which results in the mentioned error.

One reason might be that the second class changed without the first one being recompiled. Recompile all your classes, and you should either get a compiler error (which will give you more information on how to solve this), or the class will reference the right class.

Another reason could be that you have some class in more than one jar file (or directory) in the class path (in different versions), resulting in some other class using the wrong one. Check all your jars on duplicate classes.

Something to be careful of when tracing these errors in an IDE (Eclipse in my case) is to watch the dependencies of projects your project may depend on. If you use different versions of a library in different dependent projects, the classpath loader may pick up the wrong one. This includes having a project dependent on a jar created from an Eclipse project, and having another project dependent on that project and the project which the jar was generated from. The outdated classes in the jar could potentially be loaded instead of the the classes from the project.

Example:

project1 depends on project2 and project3

project3 depends on project2.jar , a jar generated from the class files in project2

A final static field is added to a class in project2 , which is recompiled, while project2.jar is not rebuilt

Running project1 may cause the exception, as the classes from project2 may be loaded from the project directly OR the jar, which doesn't have the field

It means that you have probably recompiled a class that was depended upon by another already-compiled class - and not recompiled the depending class.

For example:

public class MyClass {
    public int num;
    public MyClass() { num = 1; }
}

public class MyDependingClass {
    private int foo;
    public MyDependingClass(MyClass init) {
        foo = init.num;
    }
}

So you recompile the two classes, presumably by hand (an IDE would normally update the project workspace for you so handle depending classes).

And it worked.

Later you decide to refactor MyClass:

public class MyClass {
    private int innernum;
    public int getNum() {
        return innernum;
    }
    public MyClass() { innernum = 1; }
}

If you compile MyClass and not MyDependingClass, when you run your program and create an instance of MyDependingClass then you will get your NoSuchFieldError .

The short term fix is probably to recompile all classes in your workspace, which should show up the error.

The long term fix is to use Eclipse or NetBeans or another IDE that handles this for you.

Although the underlying cause is the same as described in the top answers, my problem was a bit different than the other answers that I've found here so I thought I'd share.

I'm working on a large project that has several maven poms spread out throughout the project. A colleague updated the version number of one of the dependencies without updating every single place where that dependency appeared, resulting in mismatched libraries on the classpath.

The solution was to update each occurrence of this dependency to have to same version number. As a side note, to prevent this from happening again we added a variable there and now we control the version number of those dependencies from one spot.

It was quite tricky for me, so I am writing my solution.

I was working in IntelliJ with Boot everything was fine, all Java 8 versions were set up appropriately.

After some hours I somehow checked on terminal the javac -version and guess what, it was set to version 9. So make sure to look for javac, I know its counterintuitive but supposedly, since I had set the jdk on bash profile, on IntelliJ etc, I shouldn't have to bother of it.

Hope it helps!

Understand this error:

This is a java.lang.LinkageError error which happens when jvm tries to link the loaded classes. Note that the code is firstly compiled(with the dependent classes), then all involved classes are loaded by the jvm, and then these classes are linked together.

Think about the error: NoSuchField , it means when linking the target class, the field is not there. But when compiling, the class should have that field, otherwise the code cann't compile. When linked, the jvm finds that that field is not there. So the only reason is that we are compiling with a class with that field, and another version of that class(which doesnot have that field) is loaded and linked.


Decide your situation between two common reasons for this error

Usually the wrongly loaded class is either a source code you have modified, or a class in one of your dependent jar package. We can decide this by finding the wrongly loaded class by adding -verbose:class argument to the jvm which is trying to run your application, in your ide. This argument print all the loaded classes in the console. In eclipse we place it in: right click on your project-> run as-> run configurations->the arguments tag-> VM argument field.

After you find the wrongly loaded class, usually it is either a class that you have the source code in your project, or it is in a jar package that your project is depending on. Different situation leads to different solutions.


Solution for the source code case:

Chances are that you changed that class(adding the field in the source code), but did not recompile it. It may due to different reasons, but you should delete the old version compiled .class file of that class, and recompile it to let the new version .class file contain that field.


Solution for the jar package case:

You should try to let the project load the correct jar package. But why a different version is envolved is usually because that they are both depended(by different parts of your project). The situation is much simple(and may not exists in the real world project ), if you write codes taht directly depend on both of them, just choose one and drop another.

But chances are that your code indirectly depend on them. And you don't want to change your code(or change as less as possible).

One solution is that you write your own ClassLoader to paly with both: Possible to use two java classes with same name and same package? (I didn't try it)

If you choose to load the correct version(that containing such field ), and your code that indirectly depending on the wrong version still can work(hopingfully), then we have a much simpl solution: let your project choose the right version.

Take eclipse for example, you can use the Order and Export tag in your Java Build Path property, just adjust the order to let the correct version be ahead of the wrong version, since the fucntion of Order part is:

On one hand, it functions as the order of resolution for resources used in the building of the project in question (the "Order" part).

If the correct version or the wrong version does not show up there, you should determine what package is depending on it and adjust its order, due to the function of Export part. Read The "Order and Export" tab in "Java Build Path" for details.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM