I have a class say ClassX with enum defined. like so
public class ClassX{
public enum XType {
E_1, E_2, E_3, E_TC, UN_KNOWN, N_ONE;
}
}
In method (methodx) in another class I am referring to the enum and assigning it to another variable like so:
public class AnotherClass{
public class NestedClass {
// some member variables
public NestedClass(String x, CustomClass y) {
this.m1 = x;
this.m2 = y;
this.b1 = false;
this.b2 = false;
}
}
public SomeType methodx() {
XType xt = null;
try {
// print log stmt1
xt = XType.E_TC;
// print log stmt2
}
catch(Exception e) {
// print log stmt3
}
}
}
The problem is that i get log stmt1 in log. But don't get anything after that from the methodx().
I spent hours trying to figure out what was wrong. The logs were not getting printed and nor was there any exception thrown/caught. Then, I attached debugger. Put breakpoints just before the assignment. When the breakpoint was hit, I added the XType.E_TC to the watch list.
To my surprise it said <Errors Evaluating>. I still went ahead with my stepping and the code jumped to constructor block of subclass block above the methodx()!
This doesn't make sense to me as the classes are correctly compiled and classes load correctly. I checked for XType by executing "javap" separately and there is no error.
Have you seen something like this before?
How to fix this?
Why does such a thing happen in the first place? I mean I can understand if the .class file of ClassX is partially built and doesn't have definition for XType, this is plausible. But the class definition and enum are correctly compiled into the .class. as mentioned above, I verified it using the javap command.
Any help and pointers are very much appreciated!
"It may be that you have one or more stale class files somewhere" does look like the most likely reason: your code was compiled but linked wrongly (probably, with some leftover object files) at runtime.
Explore the app's state at breakpoint hit in more details: if XType is loaded, from which location, how it looks, if the other entities from that compilation unit are present (add one for a test and see if it appears at runtime). Alternatively, you may do a clean build in another directory and look for differences in the runtime state.
The issue was that the dependent class was not available on classpath.
I would expect ClassNotFoundException in such a case. But for reasons known to JBoss EAP6 server, it was printing this in "TRACE" level.
When I provided the correct jar file on classpath, it did not give me any error.
Am still not able to reconcile the fact that when class is not found, JBoss EAP server chose to report it in TRACE!
Related
I would need help trying to understand why this is happening to me:
Using Java 1.8.0_131, I have a class such as this:
public class DynamicClassLoadingAppKO {
/*
* THIS VERSION DOES NOT WORK, A ClassNotFoundException IS THROWN BEFORE EVEN EXECUTING main()
*/
// If this method received ChildClassFromLibTwo, everything would work OK!
private static void showMessage(final ParentClassFromLibOne obj) {
System.out.println(obj.message());
}
public static void main(final String[] args) throws Throwable {
try {
final ChildClassFromLibTwo obj = new ChildClassFromLibTwo();
showMessage(obj);
} catch (final Throwable ignored) {
// ignored, we just wanted to use it if it was present
}
System.out.println("This should be displayed, but no :(");
}
}
Two other classes are being used up there: ParentClassFromLibOne and ChildClassFromLibTwo. The latter extends from the former.
There are two external libraries involved:
One library is called libone and contains the ParentClassFromLibOne class. The application includes this library in the classpath both for compiling and executing.
A second library is called libtwo and contains the ChildClassFromLibTwo class. The application includes this library in the classpath for compiling, but not for executing.
As far as I understand, the Java runtime should try to load the ChildClassFromLibTwo (which is not in the classpath at runtime) at this line:
final ChildClassFromLibTwo obj = new ChildClassFromLibTwo();
Given this class is not in the classpath, a ClassNotFoundException should be thrown, and given this line is inside a try...catch (Throwable), the System.out.println line at the end should be executed anyway.
However, what I get is the ClassNotFoundException thrown when the DynamicClassLoadingAppKO itself is loaded, apparently before the main() method is executed at all, and therefore not caught by the try...catch.
What seems more strange to me is that this behaviour disappears and everything works as I would expect if I change the signature of the showMessage() method so that instead of receiving an argument of the parent class, it is directly of the child class:
/*
* THIS VERSION WORKS OK, BECAUSE showMessage RECEIVES THE CHILD CLASS AS A PARAMETER
*/
private static void showMessage(final ChildClassFromLibTwo obj) {
System.out.println(obj.message());
}
How is this possible? What am I missing in the way class loading works?
For testing convenience, I have created a GitHub repository replicating this behaviour [1].
[1] https://github.com/danielfernandez/test-dynamic-class-loading/tree/20170504
OK, the details of why this happens are explained in this Spring Boot ticket [1] which I've been very lucky to be promptly pointed to by Andy Wilkinson. That was definitely a difficult one IMO.
Apparently, what happens in this case is that when the calling class itself is loaded, the verifier kicks in and sees that the showMessage() method receives an argument of type ParentClassFromLibOne. So far so good, and this would not provoke a ClassNotFoundException at this phase even if ParentClassFromLibOne was not in the classpath at runtime.
BUT apparently the verifier also scans method code and notes that there is a call in main() to that showMessage() method. A call that does not pass as an argument a ParentClassFromLibOne, but instead an object of a different class: ChildClassFromLibTwo.
So it is in this case that the verifier does try to load ChildClassFromLibTwo in order to be able to check if it really extends from ParentClassFromLibOne.
Interestingly this wouldn't happen if ParentClassFromLibOne was an interface, because interfaces are treated as Object for assignment.
Also, this does not happen if showMessage(...) directly asks for a ChildClassFromLibTwo as an argument because in such case the verifier does not need to load the child class to check it is compatible... with itself.
Daniel, I'm voting up your answer but I will not mark it as accepted because I consider it fails at explaining the real reason why this is happening at verify time (it's not the class in the signature of the method that's causing the ClassNotFoundException).
[1] https://github.com/spring-projects/spring-boot/issues/8181
This is a bit more complicated than you think. When a class is loaded, all functions are verified. During the verify phase also all referenced classes are loaded, because they are needed to calculated the exact types that are on the stack at any given location in the bytecode.
If you want that lazy behaviour, you have to pass the -noverify option to Java, which will delay the loading of classes until the functions that reference them are executed the first time. But don't use -noverify for security reasons when you don't have full control over the classes that will be loaded into the JVM.
I'm working in Java and have come across an incredibly odd error. I have a very basic class as follows:
public class ClassA{
private static Logger log = Logger.getLogger(ClassA.class.getName());
private boolean trace;
public ClassA(){
trace = log.isTraceEnabled();
}
public void doSomething(){
//does stuff
}
}
I can use this class just fine within my current project. However, when I build, package, and install to my local repo (using Maven, no remote artifact repo set up), other projects cannot properly use this class because they cannot instantiate it. When I try anything like:
ClassA classA = new ClassA();
I get the following compilation error:
ClassA() has private access in [package].ClassA
I've decompiled the .jar in my local repo to ensure the constructor is present and is public - it is. I've also used the -U flag to force updates and the compilation continues to fail. What could be causing this error?
Maybe you have some other ClassA.class file somewhere in the classpath. Check all the jars used by the project that cannot call the constructor: one of them should contain an old version of your class.
My only thought is that you have a problem with your package. Make sure to define the package at the top of the source file for classA using the package keyword. When you call it ensure that the file is in include list with the include keyword. You could be running into the error because ClassA exists in some default package and that is what you are actually calling instead of calling your locally made ClassA class. The code you posted looks fine and you have already double checked to ensure the changes have taken effect in your repository.
//for those with Kotlin-Java mixed projects:
If the said file (With constructor) is in Kotlin and is being used in Java:
Instead of A a = new A(); //which causes the said error
Use A.INSTANCE. …
I have this error, where write "private", instead "public" for class constructor;
Guys, can anyone explain the following scenario:
1) Web application has module1.jar in its lib directory. There is a class A in that module:
package module1;
import module2.B;
public interface IA {
void methodOk() {}
void methodWithB(B param) {}
}
package module1;
import module2.B;
public class A implements IA {
public A() {}
//...
void methodWithB(B param) {
//do job on B
}
}
2) module2.jar is absent - it is not in the classpath.
3) Application is able to create objects of class A though it's missing the dependency. In application a method A.methodOk() is called.
Would be cool if you could give a reference to any spec on this.
Thanks a lot.
Since the code is already compiled, it will not throw an error until you directly use class B. From the looks of your code, you don't actually use an instance of B for anything.
If B is not used by A anywhere, then the resulting bytecode will have no reference to module2.B, therefore it gets compiled away. No dependency exists, except at compilation in this case.
If the question is unclear and B is used in A somewhere, then I'd be interested in seeing more code to try to determine what's going on.
Look at it from the perspective of the classloader. If you never have to load the class, you don't care if the bytecode for that class is missing.
Your question is really, "What triggers classloading?"
Two reasons I can think of off the top of my head are:
- Construction
- Static access
I'm getting an anonymous class at compile-time that I'm not expecting. Relevant code follows, then a more detailed explanation:
Entirety of CircuitType.java:
public enum CircuitType { V110A20, V110A30, V208A20, V208A30 }
From Auditor.java, lines 3-9:
public class Auditor {
private String[] fileNames;
private int numV110A20;
private int numV110A30;
private int numV208A20;
private int numV208A30;
From Auditor.java, lines 104-121:
[...]
switch (newCircuit.getType()) {
case V110A20:
this.numV110A20++;
break;
case V110A30:
this.numV110A30++;
break;
case V208A20:
this.numV208A20++;
break;
case V208A30:
this.numV208A30++;
break;
default:
System.err.println("An Error Has Occured.");
System.exit(-1);
break;
}
[...]
From Circuit.java, lines 1-5:
public class Circuit {
private CircuitType myType;
public CircuitType getType() {
return this.myType;
}
[...]
When the command
javac *.java
is executed, an anonymous class Auditor$1.java is generated. The files, obviously, all sit next to each other in a file system directory that contains nothing else.
When lines 104-121 are commented out, no anonymous class is generated.
I at first thought it was a package issue, so put the three classes in a package, but I didn't know enough about packages to get it working. If it's truely a package issue, can someone step me through exactly how to label them? I'd rather not have to package them if I don't have to, though.
The reason the anonymous class is a problem, besides the fact that such classes usually signify a namespace issue, is that it breaks my Makefile I use for automatic compilation.
Update
Attached is a console session which I hope may shed light on this mystery:
% javap 'Auditor$1'
Compiled from "Auditor.java"
class Auditor$1 extends java.lang.Object{
static final int[] $SwitchMap$CircuitType;
static {};
}
I've gone ahead and built a little project containing the source you posted and just enough framework around it to make it compile. I got 3 class files: Circuit.class, CircuitType.class and Auditor.class - as expected.
All this under Java 1.6. But as others have indicated, I think your diagnosis of the problem is off.
Anonymous classes are easy to generate accidentally: Typically a construct like
Circuit myCircuit = new Circuit() {
public CircuitType getCircuitType() {
return XXX;
}
}
will create one, for example. Given more of your code, the good SO folks might be able to pinpoint your error.
It might be interesting and instructive to disassemble your class files with javap or better yet a "real" Java disassembler like JD.
Update
Added your new Auditor code to mine... no change. No anonymous classes.
Your code is of course correct (to the extent we can see it) but the design is not very OO. Some people would point out that you'll have to extend your counter declarations and your switch statement every time a new circuit type appears.
You're also not making much use of the "special features" of enums. I have a much simplified version of your Auditor method:
private int[] counters = new int[CircuitType.values().length];
public void tallySomething() {
Circuit newCircuit = new Circuit();
counters[newCircuit.getType().ordinal()]++;
}
Update 2
I found your javap output quite illuminating. See my comment below.
My conclusions:
Yes, apparently your Java impl is using an anon class for the switch. Lame, but legitimate.
You have the following options:
eliminate the switch
use a different Java implementation
live with the anonymous class; ditch make and use ant to embrace the anon classes and other strangenesses of Java.
Since you're only having problems because of your non-standard compilation setup, I'd go with the last solution and attack the problem there.
It indeed appears that (in certain cases at least) an inner class will be generated for the switch statement:
Java enum and additional class files
Today I spent my afternoon with analysing a NoClassDefFoundError. After verifying the classpath again and again, it turned out that there was a static member of a class that threw an Exception that was ignored the first time. After that every use of the class throw a NoClassDefFoundError without a meaningful stacktrace:
Exception in thread "main" java.lang.NoClassDefFoundError:
Could not initialize class InitializationProblem$A
at InitializationProblem.main(InitializationProblem.java:19)
That's all. No more lines.
Reduced to the point, this was the problem:
public class InitializationProblem {
public static class A {
static int foo = 1 / 0;
static String getId() {
return "42";
}
}
public static void main( String[] args ) {
try {
new A();
}
catch( Error e ) {
// ignore the initialization error
}
// here an Error is being thrown again,
// without any hint what is going wrong.
A.getId();
}
}
To make it not so easy, all but the last call of A.getId() was hidden somewhere in the initialization code of a very big project.
Question:
Now that I've found this error after hours of trial and error, I'm wondering if there is a straight forward way to find this bug starting from the thrown exception. Any ideas on how to do this?
I hope this question will be a hint for anyone else analysing an inexplicable NoClassDefFoundError.
Really, you shouldn't ever ever catch Error, but here's how you can find initializer problems wherever they might occur.
Here's an agent that will make all ExceptionInInitializerErrors print the stack trace when they are created:
import java.lang.instrument.*;
import javassist.*;
import java.io.*;
import java.security.*;
public class InitializerLoggingAgent implements ClassFileTransformer {
public static void premain(String agentArgs, Instrumentation inst) {
inst.addTransformer(new InitializerLoggingAgent(), true);
}
private final ClassPool pool = new ClassPool(true);
public byte[] transform(ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) {
try {
if (className.equals("java/lang/ExceptionInInitializerError")) {
CtClass klass = pool.makeClass(new ByteArrayInputStream(classfileBuffer));
CtConstructor[] ctors = klass.getConstructors();
for (int i = 0; i < ctors.length; i++) {
ctors[i].insertAfter("this.printStackTrace();");
}
return klass.toBytecode();
} else {
return null;
}
} catch (Throwable t) {
return null;
}
}
}
It uses javassist to modify the classes. Compile and put it in a jar file with javassist classes and the following MANIFEST.MF
Manifest-Version: 1.0
Premain-Class: InitializerLoggingAgent
Run your app with java -javaagent:agentjar.jar MainClass and every ExceptionInInitializerError will be printed even if it is caught.
My advice would be to avoid this problem by avoiding static initializers as much as you can. Because these initializers get executed during the classloading process, many frameworks don't handle them very well, and in fact older VMs don't handle them very well either.
Most (if not all) static initializers can be refactored into other forms, and in general it makes the problems easier to handle and diagnose. As you've discovered, static initializers are forbidden from throwing checked exceptions, so you've got to either log-and-ignore, or log-and-rethrow-as-unchecked, none of which make the job of diagnosis any easier.
Also, most classloaders make one-and-only-one attempt to load a given class, and if it fails the first time, and isn't handled properly, the problem gets effectively squashed, and you end up with generic Errors being thrown, with little or no context.
If you ever see code with this pattern:
} catch(...) {
// no code
}
Find out who wrote it and BEAT THE CRAP OUT OF THEM. I'm serious. Try to get them fired--they do not understand the debugging portion of programming in any way, shape or form.
I guess if they are an apprentice programmer you might just beat the crap out of them and then let them have ONE second chance.
Even for temporary code--it's never worth the possibility that it will somehow be brought forward into production code.
This kind of code is caused by checked exceptions, an otherwise reasonable idea made into a huge language pitfall by the fact that at some point we'll all see code like that above.
It can take DAYS if not WEEKS to solve this problem. So you've got to understand that by coding that, you are potentially costing the company tens of thousands of dollars. (There's another good solution, fine them for all the salary spent because of that stupidity--I bet they never do THAT again).
If you do expect (catch) a given error and handle it, make sure that:
You know that the error you handled is the ONLY POSSIBLE source of that exception.
Any other exceptions/causes incidentally caught are either rethrown or logged.
You aren't catching to broad an exception (Exception or Throwable)
If I sound aggressive and angry, it's because I've gotten screwed spending weeks finding hidden bugs like this and, as a consultant, haven't found anyone to take it out on. Sorry.
The only hints the error gives are the name of the class and that something went terribly wrong during initialization of that class. So either in one of those static initializers, field initialization or maybe in a called constructor.
The second error has been thrown because the class has not been initialized at the time A.getId() was called. The first initialization was aborted. Catching that error was a nice test for the engineering team ;-)
A promising approach to locate such an error is to initialize the class in a test environment and debug the initialization (single steps) code. Then one should be able to find the cause of the problem.
Today I spent my afternoon with analysing a NoClassDefFoundError. After verifying the classpath again and again, it turned out that there was a static member of a class that threw an Exception that was ignored the first time.
There is your problem! Don't ever catch and ignore Error (or Throwable). NOT EVER.
And if you've inherited some dodgy code that might do this, use your favourite code search tool / IDE to seek and destroy the offending catch clauses.
Now that I've found this error after hours of trial and error, I'm wondering if there is a straight forward way to find this bug starting from the thrown exception.
No there isn't. There are complicated/heroic ways ... like using doing clever things with a java agent to hack the runtime system on the fly ... but not the sort of thing that a typical Java developer is likely to have in their "toolbox".
Which is why the advice above is so important.
I really don't understand your reasoning. You ask about "find this bug starting from the thrown exception" and yet you catch that error and ignore it ...
If you can reproduce the problem (even occasionally), and it's possible to run the app under debug, then you may be able to set a break point in your debugger for (all 3 constructors of) ExceptionInInitializerError, and see when they git hit.