I have a problem deploying compiled classes in a Tomcat web application: I'm deploying a class which is to be called from a servlet, but when I run the application it fails telling me of a ServletException: Error allocating the servlet instance due to an UnsupportedClassVersionError: Bad version number in .class file.
Tomcat is using Java 1.5.0_06 as reported by the manager. My class was compiled using Java 1.6.0_14. Running javap on any of the classes already present tells me "Major version 46, minor version 0" which should be 1.2.0 initial and which isn't available anymore for download. The oldest I can find is 1.2.1_004 which doesn't even compile.
Do i need to match my Java version to the Tomcat environment or to the classes already there? Re-compiling the whole project using more modern Java is not feasible for me at the moment, although I'd love to do so.
That's easy: You compiled your application with a later version Java compiler than the Java runtime underneath Tomcat.
Update
The java compiler, javac, supports the options
-source release
Specifies the version of source code accepted. The following values for release are allowed:
1.3 the compiler does not support assertions, generics, or other language features introduced after JDK 1.3.
1.4 the compiler accepts code containing assertions, which were introduced in JDK 1.4.
1.5 the compiler accepts code containing generics and other language features introduced in JDK 5. The compiler defaults to the version 5 behavior if the -source flag is not used.
5 Synonym for 1.5
...and even more importantly,
-target version
Generate class files that will work on VMs with the specified version. The default is to generate class files to be compatible with the JDK 5 VM. When the -source 1.4 or lower option is used, the default target is 1.4. The versions supported by javac are:
1.1 Generate class files that will run on VMs in JDK 1.1 and later.
1.2 Generate class files that will run on VMs in JDK 1.2 and later, but will not run on 1.1 VMs.
1.3 Generate class files that will run on VMs in JDK 1.3 and later, but will not run on 1.1 or 1.2 VMs.
1.4 Generate class files that will run on VMs in JDK 1.4 and later, but will not run on 1.1, 1.2 or 1.3 VMs.
1.5 Generate class files that are compatible only with JDK 5 VMs.
5 Synonym for 1.5
... which will allow you to compile code for a certain version of the JVM.
In other words, you can continue to use your 1.6 compiler, just throw these options at it and you can make it generate 1.5 code which Tomcat will be able to handle.
Do i need to match my Java version to the Tomcat environment or to the classes already there?
You need to ensure that your code is compiled with a version (less than or equals) supported by the JVM you are using; but no, this doesn't need to be the same version that the Tomcat code base was built from - the two code bases can be jvm version independent of each other, as long as they are both supported by the jvm you are using.
Instead of recompiling your source to be 1.5 compatible you could update the JDK that Tomcat is using to 1.6.
You should be able to change this by setting the JAVA_HOME environment variable to point to a Java 1.6 install.
I got the same UnsupportedClassVersionError issue a while ago. The root cause there was not my own compiled code, but some libraries that were needed, which were compiled with a newer JDK.
Related
Can I use higher java version (17) on my machine than mentioned in existing (11) spring boot project's pom.xml ?
will it create any problem ?
Backward Compatibility
Java versions are expected to be binary backwards-compatible. For example, JDK 8 can run code compiled by JDK 7 or JDK 6. It is common to see applications leverage this backwards compatibility by using components built by different Java version.
The compiler is not backwards compatible because bytecode generated with Java5 JDK won’t run in Java 1.4 jvm (unless compiled with the -target 1.4 flag). But the JVM is backwards compatible, as it can run older bytecodes. JDK’s are (usually) forward compatible.
See: https://alanxelsys.com/php/what-is-meant-by-backward-compatible-in-java.html
Fast-ClassPath-Scanner
https://github.com/lukehutch/fast-classpath-scanner using latest version.
On executing(get names of all classes in war which includes all jars and classes)
new FastClasspathScanner(basePackage).scan().getNamesOfAllClasses()
getting:
unsupportedclassversion error with jre 6
Please provide a solution to it or alternative to perform same.
FastClasspathScanner is compiled for java 1.7
When you try to load it in a 1.6 (JRE6) environment it fails with an UnsupportedClassVersionError. This error indicates that the class version (here 1.7) is not compatible with the JVM version (here 1.6).
Java 7 is not backwards compatible with Java 6. You could try to build the FastClasspathScanner library yourself unter 1.6 (not sure if that's possible). Or upgrade your project to Java 7.
Correct, I am the author of FastClasspathScanner, and it's not a goal to get this working with JRE6. However, patches for supporting 1.6 are welcome.
I was wondering if there is any difference running/building a software under JDK 8 and using compiler compliance level 1.7 vs JDK 7 as system default? I am more interested in reference to Android building, building apps, Eclipse, Android Studio, etc.
Yes, there are loads of new classes in the JDK 1.8, for example, the java.time classes. You won't get those if you build in JDK 1.7; but you will be able to use them if you build in JDK 1.8 with compiler compliance level 1.7.
Yes there is a difference between running/building a software under JDK 8 and using compiler compliance level 1.7 vs JDK 7 as system default.
running a software under JDK 8 and using compiler compliance level : You compile in jdk 1.7 but run on 1.8. No problem, your programm will work as needed.
JDK 7 as system default : You compile in 1.7 version and run on the same version.
I am wondering in waht case you would like to use the first case ?
truck load of difference actually. With JDKs the the compliance level is a directive to the compiler to specifically use the optimizations and linking features for the version you specified. It has a lot more going under the hood but I don't think you want to know that. New JDK versions bring new features and the compilers in those version are able to understand and link those features when building class files or assembled code of your source Java files. Consequently the JVM runtime in those JDKS is also equipped to handle such optimizations and cases and process them. So without compliance levels the class file that you build with JDK8 would only run correctly with JDK8 based runtimes. They may not do so with JDK7 or 6. To counter this problem and thus allow your JDK8 compiled code to run on JDK8,7 and maybe even on 6, hyou need to add compliance level to compiler directives accordingly. Downside is that you may not be able to use some latest features which the compiler offers but such cases are far few and outweigh the need for interoperability and potability.
I would like to know if it is possible to launch a war which have to run with the JDK 1.5 (not compliant with JDK 1.6) under Webpshere 7.
It is not possible/supported to run WebSphere Application Server 7.0 process with any other JDK than the one that is bundled with the product.
I guess I'm confused by your question. JRE's are to be backwards compatible. So the 1.6 JRE within IBM WebSphere Application Server V 7.x.x.x will run Java EE code as far back as Java EE 1 (which I think might be Java 1.2 compliant) and should support Java SE code as far back as 1.1. (Why you'd want to go that far back, I'm not sure....).
There really is no trouble to it. Just compile your code with a 1.5 JDK (that's what we do), or if you want you could compile it with a 1.6 compiler and flag the compiler to use 1.5.
Your code doesn't have to be 1.6 compliant. It just has to be 1.5 compliant and it will run fine. That is the whole point of abstracting and backwards compatibility with the JDK and JRE.
As an example for you, we have an enterprise application that we compile with Maven 2 using Sun/Oracle's 1.5 JDK. We package in several open source project jars, some of which are even as old as 1.3 compliant and/or compiled.
We package all of this up as an EAR using Maven 2 and we deploy it to IBM's WebSphere Application Server (and we run 7.0.0.9). Our code runs just fine. We even have some modules that we do compile with JDK 1.6 to leverage certain functions in 6, but most of the code is compiled as 1.5. And it runs fine.
So I guess I'm confused what you are asking. Could you provide a more concrete example of what you are trying to do? Because from what you have told me, you should be able to run just fine in WAS 7 without compiling at JDK 6.
Does the bytecode depend on the version of Java it was created with?
If I compiled a java file in the newest JDK, would an older JVM be able to run the .class files?
That depends on three things:
The actual Java versions you are talking about. For instance, a 1.4.0 JVM can run code compiled by a 1.4.2 compiler, but a 1.3.x JVM cannot1.
The compilation flags used. There is a -target compiler flag that tells it to generate code that will run on an older (target) JVM. And the -source compiler flag tells it to only accept the older JVM's language features. (This approach won't always work, depending on the Java language features used by your code. But if the code compiles it should work.)
The library classes that the class file uses. If it uses library classes that don't exist in the older class libraries, then it won't run ... unless you can include a JAR that back-ports the classes2. You can avoid this problem by using the -bootclasspath option to compile your code against the APIs of the older version of Java.
Does the bytecode depend on the version of the java it was created with?
Yes, modulo the points above.
1 - The Java 8 JVMS states this: "Oracle's Java Virtual Machine implementation in JDK release 1.0.2 supports class file format versions 45.0 through 45.3 inclusive. JDK releases 1.1.* support class file format versions in the range 45.0 through 45.65535 inclusive. For k ≥ 2, JDK release 1.k supports class file format versions in the range 45.0 through 44+k.0 inclusive."
2 - A backport could be problematic too. For example: 1) Things which depend on native code support would most likely require you to implement that native code support. 2) You would most likely need to put any back-port JAR file onto the bootclasspath when you run the code on the older JVM.
Does the bytecode depend on the version of the java it was created with?
Normally yes. But by using the -source, -target and -bootclasspath options, a 1.7+ compiler can be used to create binaries that are compatible with Java 1.1
First and foremost all java files have a version byte in the class header. Older jvms won't load classes with newer versions, regardless of what features they have.
JVM bytecode is forward compatible between major JVM version, but not backward compatible. However, for the best information you will have to read the JVM release notes because they typically indicate how backward compatible the bytecode is.
Edit clarification since this caused discussion in the comments
JVM bytecode is forward compatible, such that bytecode from one JVM is compatible with with later JVM releases. For example, you can take bytecode from the 1.4 JVM and run it in Java 5 or Java 6 JVM (aside from any sort of regression issues as pointed out by Andrew).
JVM bytecode is not backward compatible between JVMs, such that bytecode from a JVM is not guaranteed to work in a previous release of the JVM, as would be the case if you were attempting to run code compiled for Java 6 in a 1.4.2 JVM.
Does the bytecode depend on the version of the java it was created with?
Yes.
If I compiled a java file in the newest JDK, would an older JVM be able to run the .class files?
No. But the opposite will work, most likely. You might like see this interesting thread, it talks about backporting Java.
No, unless you specify as target the old JVM.
Eg.with Java 6 you can compile and run in Java 1.4 using:
javac -target 1.4 SomeClass.java
Obviously the source code should be 1.4 compatible.
You can compile classes that are older-version JVMs compatible if you don't use features available in higher JVMs.
javac -target 1.5 MyJava.java
javac -target 1.4 MyJava.java