Getting class to compile under JDK 1.5 AND 1.6

C

Chris

I've got a puzzling problem. Our code runs fine under JDK 1.5. I
downloaded JDK 1.6 today, recompiled, and got errors.

The trouble is that one of our classes implements the java.sql.ResultSet
interface, and they changed the interface to include more methods. For
example:

public RowId getRowId(int columnIndex);

Ok, no problem, I just went ahead and implemented that method in our
code (and just threw an UnsupportedOperationException in the method body).

The trouble is that now the code won't compile under JDK 1.5 because
RowId is a new class in 1.6 and doesn't exist in 1.5.

So I appear to have an impossible situation: no way to make the code
compilable under 1.5 and 1.6 at the same time.

What's the way out?
 
A

Andrew Thompson

Chris said:
...Our code runs fine under JDK 1.5. I
downloaded JDK 1.6 today, recompiled, and got errors. ....
The trouble is that now the code won't compile under JDK 1.5 because
RowId is a new class in 1.6 and doesn't exist in 1.5.

So I appear to have an impossible situation: no way to make the code
compilable under 1.5 and 1.6 at the same time.

What's the way out?

I have ebeen thinking on similar problems related
to cross-compilation. Although I have not actually
tested it yet, I figure it *might* be possible to get a
clean compile by specifying a -bootclasspath
pointing to the 1.5 rt.jar, with the 1.6 rt.jar added
to the standard classpath.

Andrew T.
 
C

Chris

Andrew said:
I have ebeen thinking on similar problems related
to cross-compilation. Although I have not actually
tested it yet, I figure it *might* be possible to get a
clean compile by specifying a -bootclasspath
pointing to the 1.5 rt.jar, with the 1.6 rt.jar added
to the standard classpath.

What would that mean at runtime, though?

Maybe I should just test this, but what if I leave the extra methods off
my class, compile it under 1.5, and then run it under 1.6? Does it blow
up when my class is loaded?
 
A

Andrew Thompson

Chris said:
What would that mean at runtime, though?

Maybe I should just test this,

Maybe you should.
..but what if I leave the extra methods off
my class, compile it under 1.5, and then run it under 1.6?

Any code that can run successfully in 1.5, should work in
1.6 (1.7, 1.8) - barring a JVM bug of some sort(, or reliance
on bugs that happen in 1.5).
...Does it blow
up when my class is loaded?

No. Whay would you think that might pose a problem,
as opposed to the other way around (running 1.6 code,
written in the 1.6 class format - in 1.5)?

Andrew T.
 
D

Daniel Dyer

What would that mean at runtime, though?

Maybe I should just test this, but what if I leave the extra methods off
my class, compile it under 1.5, and then run it under 1.6? Does it blow
up when my class is loaded?

Should only be a problem if those methods are invoked (you get a
NoSuchMethodError). If you are running on 1.5, none of the other JDBC
classes will know about the 1.6 methods, so they won't call them.

I am surprised that Sun have chosen to add methods to an existing
interface. I thought they were stricter on backwards compatibility than
that. I was under the impression that the backwards compatibility
argument was the reason that the clone() method has never been added to
the Cloneable interface. This would potentially cause similar
incompatibilities to the one that you are seeing, but in the case of
Cloneable it would only affect classes that deserve to break.

Dan.
 
C

Chris

Andrew said:
Maybe you should.


Any code that can run successfully in 1.5, should work in
1.6 (1.7, 1.8) - barring a JVM bug of some sort(, or reliance
on bugs that happen in 1.5).


No. Whay would you think that might pose a problem,
as opposed to the other way around (running 1.6 code,
written in the 1.6 class format - in 1.5)?

I just tested it, and code that compiles under 1.5 runs fine in 1.6.

The reason I thought that there would be a problem is that at runtime,
the system is going to load the 1.6 interface when I reference it, and
then the 1.5 class that implements it. Clearly the 1.5 class will not
meet the requirements of the interface. It doesn't appear that the JVM
checks for this, though. The constraint that an interface imposes on an
implementing class must be a compile-time only constraint.

Nevertheless, that doesn't solve my problem, because the IDE (correctly)
forces a recompile of everything when I switch JVM versions. So it still
seems that it's impossible to write code that implements
java.sql.ResultSet and compiles under both 1.5 and 1.6. This will make
it hard to use 1.6 for testing or development.
 
T

Thomas Hawtin

Chris said:
The trouble is that one of our classes implements the java.sql.ResultSet
interface, and they changed the interface to include more methods. For
example:
The trouble is that now the code won't compile under JDK 1.5 because
RowId is a new class in 1.6 and doesn't exist in 1.5.

Welcome to JDBC interface changing hell.

The easiest solution: compile with 1.5 bootclasses (or java.sql
extracted from 1.5 and replacing 1.6 classes with -Xbootclasspath/p:).

If you want to compile on both platforms I suggest three source
directories: one directory containing common code (including an abstract
implementation of ResultSet), one directory containing the small amount
of 1.5 specific code and the last 1.6 code (using largely the same class
names as the 1.5 code). For 1.5 builds compile with the first two on the
sourcepath; for 1.6 use the first and last.


So:


In directory java:

package xx.example;

abstract class AbstractResultSet implements java.sql.ResultSet {
... constructors ...
... bulk of code ...
}
....
ResultSetImpl results = new ResultSetImpl(...);


In directory java15:

package xx.example;

class ResultSetImpl extends AbstractResultSet {
... constructors ...
}


In directory java16:

package xx.example;

class ResultSetImpl extends AbstractResultSet {
... constructors ...
public java.sql.RowId getRowId(int columnIndex) {
throw new UnsupportedOperationException();
}
... other JDBC 4.0 methods ...
}

Tom Hawtin
 
A

Andrew Thompson

Chris wrote:
.....
Nevertheless, that doesn't solve my problem, because the IDE (correctly)
forces a recompile of everything when I switch JVM versions.

Sounds like a problem with your IDE.
The -bootclasspath option of javac works
just fine from the command line.

Andrew T.
 
T

Thomas Hawtin

Chris said:
The reason I thought that there would be a problem is that at runtime,
the system is going to load the 1.6 interface when I reference it, and
then the 1.5 class that implements it. Clearly the 1.5 class will not
meet the requirements of the interface. It doesn't appear that the JVM
checks for this, though. The constraint that an interface imposes on an
implementing class must be a compile-time only constraint.

The original specifications did not specify a precise outcome in this
case (compiling and running a program does not mean it is correct, even
in Java). IIRC, it was to allow the java.sql interfaces to evolve the
led to the specs being tightened up. Previously, I believe, you could
get a linkage error earlier, at the JVM's discretion.

If you run 1.6 client on 1.6 with a 1.5 JDBC driver, you will get an
AbstractMethodError for the new methods.

If you somehow run a 1.6 client on 1.5, you will get a NoSuchMethodError
for the new methods (because of improvements in javac defaults, you
would need to have used -source and -target without -bootclasspath,
which is daft).

Tom Hawtin
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top