3

Whats the easiest way to determine which Java class is compiled with the "wrong" version number?

I've a project with a large number of dependencies and somewhere I've a class compiled using Java 1.6, where Java 1.5 is required. At runtime I get the uninformative exception:

[WARN] StandardWrapperValve[shell]: Servlet.service() for servlet shell threw exception
java.lang.UnsupportedClassVersionError: Bad version number in .class file
    at java.lang.ClassLoader.defineClass1(Native Method)
    at java.lang.ClassLoader.defineClass(ClassLoader.java:675)
    at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:124)
    at java.net.URLClassLoader.defineClass(URLClassLoader.java:260)
    at java.net.URLClassLoader.access$100(URLClassLoader.java:56)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:195)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:188)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:316)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:280)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:251)
    at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:374)
    at foo.Listener.(Listener.java:30)
    at foo.rpc.service.MapServiceImpl.(MapServiceImpl.java:58)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:494)
    at java.lang.Class.newInstance0(Class.java:350)
    at java.lang.Class.newInstance(Class.java:303)
    at com.google.gwt.dev.shell.GWTShellServlet.tryGetOrLoadServlet(GWTShellServlet.java:934)
    at com.google.gwt.dev.shell.GWTShellServlet.service(GWTShellServlet.java:276)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:237)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:157)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:214)
    at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValveContext.java:104)
    at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:520)
    at org.apache.catalina.core.StandardContextValve.invokeInternal(StandardContextValve.java:198)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:152)
    at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValveContext.java:104)
    at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:520)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:137)
    at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValveContext.java:104)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:118)
    at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValveContext.java:102)
    at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:520)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
    at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValveContext.java:104)
    at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:520)
    at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:929)
    at org.apache.coyote.tomcat5.CoyoteAdapter.service(CoyoteAdapter.java:160)
    at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:799)
    at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.processConnection(Http11Protocol.java:705)
    at org.apache.tomcat.util.net.TcpWorkerThread.runIt(PoolTcpEndpoint.java:577)
    at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:683)
    at java.lang.Thread.run(Thread.java:613)

The only thing I spot is the class foo.Listener at which all my dependencies (Camel, ActiveMQ, various in house libraries) are required.

The best thing I've thought of so far is too use opensnoop and manually dig through the jars and classes using the ideas from "how-can-i-find-the-target-java-version-for-a-compiled-class". Is there a better way?

Community
  • 1
  • 1
eaubin
  • 658
  • 9
  • 14

4 Answers4

4

You might try attaching a debugger with a breakpoint set on UnsupportedClassVersionError. (Run -> Add Java Exception Breakpoint in Eclipse)

You could then examine the class name passed into the defineClass or loadClass frame when the breakpoint halts the VM.

gibbss
  • 2,013
  • 1
  • 15
  • 22
1

Try running with the -verbose flag on the command line.

Kieveli
  • 10,944
  • 6
  • 56
  • 81
0

In addition to what @gibbss said, you can use this command on the command line.

javap -v path-to-your-class-file > output.txt

After this, open the output.txt file with any editor. In the beginning of the file, there will be information about the java version used for compiling this class. The information that you should look for is the "java major version".
Use the below information to know the java version once you know the major information.

Java 1.2 uses major version 46
Java 1.3 uses major version 47
Java 1.4 uses major version 48
Java 5 uses major version 49
Java 6 uses major version 50
Java 7 uses major version 51
Java 8 uses major version 52
RITZ XAVI
  • 3,633
  • 1
  • 25
  • 35
0

If you want to detect all files (in a .jar or a directory) that have a bad version you can load each of the files via a bytecode library (BCEL or ASM) and examine their version number

Itay Maman
  • 30,277
  • 10
  • 88
  • 118