1

The question first, the story will follow:

Is it safe to mix different bytecode version in a class hierarchy? What are the risks?

For a case, Class C extends B, Class B extends Class A. Class A implements Interface I. My question would involve following example scenarios:

  • Class A compiled to Java 1.6 bytecode, and have 1.6 features such as generics, etc. The heirs, which are B and C was compiled to 1.4 bytecode.
  • Interface I compiled to 1.6, while the implementor compiled to 1.4.
  • Other exotic inheritance scenario involving different version of bytecode.

I have tried as many scenarios I could imagine and it seems to run just fine. However I still feel the urge to ask here as I only know Java at the surface; i know how to code and tweak Java but don't really know what happen under the hood.

Now for those minds who can't help themselves to ask "why would you need to do that???".

I'm in a project to assess the migration of legacy Java 1.4 Swing app, connected to EJB 2 via RMI, to Java 1.6 Swing connected to newer version of App Server running on top of 1.6 also. The J2EE platform will still be 1.4 (EJB 2).

The migration will not be "recompile everything to 1.6", but it will be "code and compile new features to 1.6". The way they do things is like this: They only have one path in the CVS, everyone commits there. No tags/branches whatsoever to get the production code. Whenever a new feature need to be added, they get the JARs from production server, explode them, replace or add new classes as needed, repackage the jars, put them back to server. Therefore, if they will use Java 6 to compile and using the above method for deployment, there will be a lot of exotic mixes of 1.4 and 1.6 bytecodes.

bungrudi
  • 1,417
  • 1
  • 17
  • 24
  • The development procedure you explain in the last paragraph sounds like the real problem here. You *might* be able to get that 1.4/1.6 mix to work, but with that process you're going to end in artifact-hell. – Joachim Sauer Apr 19 '12 at 08:56
  • It sounds like your company fails (at least) items 2 and 3 from [the Joel Test](http://www.joelonsoftware.com/articles/fog0000000043.html). – Joachim Sauer Apr 19 '12 at 09:01
  • We're an ISV, handed a project in a bank in here. The app was originally developed inhouse. You're right though, the bank (not our company :) failed those points from the Joel Test. – bungrudi Apr 19 '12 at 09:13

5 Answers5

3

You can compile with Java 6 but target 1.4 with a compiler setting. We did this for a migration project once. If/when 1.4 disappears, you then change your compiler settings again and target 1.6.

Keeping the target version explicit also means that you can upgrade your SDK without fear of your JAR files becoming unusable to an older JVM.

Rory Hunter
  • 3,425
  • 1
  • 14
  • 16
  • compiling using JDK 6 with 1.4 code level will result in 1.4 compliant bytecode. this i'm sure will not cause any trouble since all the bytecode are 1.4. the issue is that our client's old (proprietary) development toolset is nearing EOL and they want to use the fancy feature of the new toolset (which require annotations etc, thus will be compiled to 1.6 bytecode). – bungrudi Apr 23 '12 at 02:33
3

The JVM byte code is not siginificantly different between Java 1.0 and Java 6. In Java 7 they add one new instruction. Woohoo.

There are so little changes in how the byte code works that

  • The JVM doesn't support nested classes accessing private members of outer classes, this works through generated code.
  • The JVM doesn't support runtime checks for generics e.g you cannot new T() where T is a generic.

Basically, they make the JVM smarter and faster but until recently changing the model of how the byte code works has been avoided at all costs.

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • 1
    I translated "until recently changing the model of how the byte code works has been avoided at all costs" as an 'OK' to mix 1.4 and 1.6 bytecode, even in the exotic case of class hierarchies. Backed by my own small POC projects and a bit of crossing my fingers, I pronounce this answer as accepted. Thanks Peter and all.. – bungrudi Apr 23 '12 at 02:37
  • Technically, there was another change that breaks class hierachies - the addition of the ACC_SUPER flag. But this happened well before Java 1.4, so this shouldn't be a problem. – Antimony May 27 '13 at 18:10
2

I am maintaining an environment with mix of 1.4 (old library jars) and 1.5 (my fixes and stuff) classes on Tomcat using Sun JVM 1.5 and it runs fine.

However, for RMI you may be in trouble if client and server has different class version because the server might check the class version (I ran into this problem).

The best way to find out is to do a proof of concept type of project on small scale.

A friendly reminder though, you are digging a pretty big hole for yourself here :-)

Alvin
  • 10,308
  • 8
  • 37
  • 49
1

These links seem relevant. They document the few edge cases that could break compatibility between 1.4 and 1.5 and between 1.5 and 1.6.

The biggest differences that could cause problems that I can think of is that enum became a keyword, but that would only effect a 1.5+ JVMs when loading an older class file (which doesn't seem to be what you will be doing). The other thing is annotations. The above links seem to suggest everything would be fine, but I would be wary about what would happen if an older JVM loaded up a class with runtime annotations.

Other than that I don't think there have been any bytecode changes between the first version of java and java 6. Meaning the only problems you should encounter are changes to functionality the API or deprecations (listed in the links above).

Dunes
  • 37,291
  • 7
  • 81
  • 97
1

As long as you aren't using reflection, the only major problem you could have from differing bytecode versions is the ACC_SUPER flag.

In very early versions, invocation of superclass methods was not handled correctly. When they fixed it, they added a new flag to the classfile format, ACC_SUPER to enable it, so that applications relying on the old, broken, behavior were not affected. Naturally, using a class that doesn't contain this flag could cause problems.

However, this is ancient history. Every class compiled in 1.4 and later will have the flag, so this isn't a problem. Bytecode wise, the only major differences between 1.4 and 1.6 are the addition of optional attributes used to store metadata about inner classes, generics, annotations, etc.

However, these don't directly affect the bytecode execution. The only way these have an affect is if you access them through reflection. For instance, java.lang.Class.getDeclaredClasses() will return information from the optional attribute InnerClasses.

Antimony
  • 37,781
  • 10
  • 100
  • 107