Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

JVM Languages

Java Q&A

Kenneth Hittleman and Ted Leung

, January 01, 1999


Jan99: Java Q&A

The authors are software engineers at the IBM Center for Java Technology in Cupertino, California. They can be reached at ken_hittleman@ us.ibm.com and ted_leung@ us.ibm.com, respectively.


Version 1.2 of the Java Development Kit (JDK) is a major upgrade from JDK 1.1, with changes that could impact developers working on JDK 1.1 applications. In this article, we'll discuss what you need to know when migrating applications from JDK 1.1 to JDK 1.2. The information we present is based on our experiences in porting large Java applications such as SanFrancisco Business Process Components and the VisualAge WebRunner Toolkit technology from JDK 1.1 to JDK 1.2.

The SanFrancisco Business Process Components comprise a framework containing over 750,000 lines of code and 7500 classes. We ported Version 1.2.0 of the SanFrancisco frameworks from JDK 1.1.2 and Swing 1.0.1 to JDK 1.2 Beta 3. The VisualAge for Java Toolkit is a collection of Java Beans and wizards containing over 500 classes. We ported the VisualAge for Java Toolkit from JDK 1.1.5 to both JDK 1.2 Beta 3 and JDK 1.2 Beta 4.

In addition to SanFrancisco and VisualAge for Java Toolkit, we also used Sun's Java Certification Kit (JCK) to help find porting problems. The JCK contains thousands of method-level tests for the classes in the JDK. While no test suite can be exhaustive, the JCK provides good coverage of the JDK APIs. We compiled and ran the JCK tests for JDK 1.1.6 using both the JDK 1.2 Beta 3 and JDK 1.2 Beta 4 run times.

A number of issues surfaced repeatedly during our porting efforts, specifically:

  • Inheriting from JDK classes or implementing JDK interfaces was repeatedly a source of migration problems. Some classes and interfaces have new abstract methods which must be provided by a subclasser or implementor, while other new concrete methods introduce signature conflicts with methods of classes that inherit from them. Most errors of this kind (signature clashes and unimplemented methods) will be signaled by the compiler. It is good to be aware that methods were added to some classes.
  • Use of collection classes can be problematic. The severity of the problem can range from slight changes in the semantics of existing collections to full-scale clashes with the new collection-class functionality.
  • Improved error checking in JDK 1.2 can cause applications that worked under JDK 1.1 to fail.

Deprecated API

As in JDK 1.1, a number of interfaces, classes, and methods have been deprecated in JDK 1.2. A full list of the deprecated API is at http://java.sun.com/products/jdk/1.2/docs/api/deprecated-list.html. Examine this list to see if you are using deprecated APIs.

General Subclassing andImplementing Issues

JDK 1.2 adds many new methods to existing classes. While at first glance this should not create compatibility issues, signature conflicts may arise in classes that inherit from them if the new methods have similar signatures to the existing methods of the subclass. For example, we found that a specialized class loader that inherits from java.lang.ClassLoader developed a signature conflict with java.lang.ClassLoader.getLocalResource(String), which was introduced in JDK 1.2 Beta 3 (and removed in JDK 1.2 Beta 4), since java .lang.ClassLoader had already used that method name (with a similar yet incompatible signature) for a slightly different purpose. If you get a signature conflict where none previously existed, a newly inherited method is probably the cause. The easiest remedy is probably to rename your own methods. (Don't forget to also update all the old references to your old method so they don't call the newly inherited method by mistake.)

Some of the AWT classes (Font, Window, Component, and so on) have new methods with signatures that conflict (different argument types) with methods in SanFrancisco classes which inherit from them. Suppose that, as in Listing One, you had a subclass of java.awt.Window with a method that you added called getOwnedWindows. MyWindow will fail to compile under JDK 1.2 because a getOwnedWindows method has been added to java.awt.Window; the signature of the new method is public Window[] getOwnedWindows(), which conflicts with the method that you have already defined.

Another situation to be aware of is when the two signatures match instead of conflict. When this happens, it is possible that the subclass may silently override the new method it inherited, and the new callers under JDK 1.2 may invoke your subclass's method instead of the intended method from the JDK. This case will not be flagged by the compiler and should be considered when tracking down unexpected results in migrated code.

This would occur for Listing One if the subclass of java.awt.Window had added a getOwnedWindows that looked like Listing Two. In this situation, the subclassed getOwnedWindows method will be called instead of the superclass's version. This could be especially dangerous if the overridden method was for a set instead of a get.

Some new abstract methods have been added to existing classes. Since they are abstract, this forces all classes that subclass them to provide implementations for them. Any class that implements an interface that now has a new method (such as java.sql.Connection) will need to be updated to provide an implementation for it.

For example, the getTypeMap method on interface java.sql.Connection is new in JDK 1.2. Suppose you had the class in Listing Three. Since a getTypeMap method has been added to JDK 1.2, you would need to add a getTypeMap method to MyJDBCConnection for your class to compile -- you must implement all of the methods on an interface. The new MyJDBCConnection would look like Listing Four. Table 1 lists the JDK 1.1 interfaces with new methods, and Table 2 lists the JDK 1.1 classes that contain new abstract methods.

The JDK 1.2 java.util.Calendar class has three methods that are abstract in JDK 1.1 -- after, before, and equals. If you used these classes and had to implement these methods, you can probably remove these overrides now as they are likely to be redundant to the newly supplied ones. Leaving the old ones in is not likely to cause problems, but it makes the code and executables slightly larger. You should check to make sure your implementation functions similarly to the new ones, in either case.

General Language-Related Issues

Casts of char literals to byte or short can no longer be implicit. Fortunately, the compiler is good at pointing out cases of this and forces you to add explicit casts. So byte b = 'c'; must become byte b = (byte) 'c';.

Another interesting discovery (that is probably true for earlier JDKs as well) is that references to final static strings from other classes get compiled directly into each .class file. Consequently, if a final static field of another class changes, all .java files that import that class and reference it must be recompiled to update their copies of the value.

The String class hashcode algorithm was corrected in JDK 1.2. Any string hashcode values persisted under JDK 1.1 will no longer match new results generated under JDK 1.2. Also the hashcode values returned from File objects have changed in JDK 1.2 Beta 4. These changes are not a problem for serialization in general, as hashcode values are not serialized by default.

Collection Class Issues

Under 1.2, Vector.indexOf() allows passing null for the target object. JDK 1.1 would throw a NullPointerException for this situation. Situations that previously threw the exception will now perform differently. This can change the behavior of classes that use Vectors, such as the Menu class. So Listing Five, which was illegal in JDK 1.1, is legal in JDK 1.2.

JDK 1.2 introduces new collection classes that have the usual names, including Map, Set, and Iterator. If your code has taken these names, you will have naming conflicts with the new JDK classes. These conflicts will result in compile-time errors if you import all of java.util by writing import java.util.*;. This can also be an issue if your code uses a third-party class library that provides collection-class functionality (such as SanFrancisco). To prevent this conflict, there are a number of alternatives:

1. Avoid importing the new collection classes by enumerating each desired class import from java.util rather than by using the wildcard ("*") import. So if you need Vector, write import java.util.Vector; not import java.util.*;

2. Add specific import statements for the conflicted classes you actually wish to use, in addition to using the wildcard imports. For example, if you use java.util.Vector and com.mycorp.Map, write import java.util; import java.util.Vector; import com.mycorp.Map;, but don't write import java.util.Map;.

3. Fully qualify the class for each usage. Suppose you have com.mycorp.Map, and you want to use both java.util.Map and com.mycorp.Map. Write import java.util.Map;, and every time you want to use the name Map and have it mean com.mycorp.Map, write com.mycorp.Map in your program. If you want to be even handed, you can skip importing java.util.Map and do the same thing you do for com.mycorp.Map.

Which alternative is best depends upon the situation. It may be easiest to use approach #2 with the existing code, since the import statements for Map, Set, and Iterator can be added to all files without bothering to see if they are actually needed for that file. Approach #1 seems to be the cleanest solution, and may lead to faster compiles because unneeded imports are eliminated. Approach #3 is the only solution that allows simultaneous use of both an existing collection class and the JDK 1.2 Collection class of the same name.

Inheriting from a JDK 1.1 collection class (Hashtable, Vector) as a way of getting an implementation is a good way to incur problems due to the new collection classes. If your code does this, be sure to inspect it and the new collections to make sure that there will be no problems, since the APIs for Hashtable and Vector have changed with the introduction of the new collection classes.

Suppose, as in Listing Six, WidgetManager has subclassed java.util.Vector to support maintaining a list of widgets. Under JDK 1.1, WidgetManager is fine. Under JDK 1.2 it will compile, but the add method silently overrides the new add(Object o) method on Vector that was inherited from java.util.AbstractCollection, and will probably cause Vector to stop behaving like an AbstractCollection.

The AWT

If a requested Font is unavailable, JDK 1.2 Beta 3 returns (for the font name) the name of the font used instead of the original font requested. This affects the string representation of Font.toString, as well as the other methods that return the names of a font. Listing Seven returns BogusFontName under JDK 1.1 and JDK 1.2 Beta 4, but returns "Arial" under JDK 1.2 Beta 3.

If a requested Font is unavailable, JDK 1.2 Beta 4 returns (for the font family) the name of the font family used instead of the original font name requested. This affects the string representation of Font .toString, as well as the other methods that return the family name of a font. Listing Eight returns BogusFontName under JDK 1.1 and JDK 1.2 Beta 3, but returns "Courier New" under JDK 1.2 Beta 4.

If null is passed for the font name to the Font constructor, JDK 1.2 Beta 4 creates a default font instead of throwing a NullPointerException. For example, the line Font testFont = new Font(null, Font.ITALIC, 9); throws a NullPointerException under JDK 1.1 and JDK 1.2 Beta 3, but returns a default font under JDK 1.2 Beta 4.

java.awt.peer.ActiveEvent moved up a level in the package hierarchy, to java.awt. This shouldn't affect you, unless you are porting Java Virtual Machines or writing your own GUI toolkits.

The Swing imports moved from com .sun.java.swing in Swing 1.0.1 (and Swing 1.0.2 as JFC 1.1) to java.awt.swing in JDK 1.2 Beta 3. They then moved back to com.sun.java.swing for JDK 1.2 Beta 4.

I/O

Some classes in JDK 1.1 did not complain if a null was passed as an OutputStream. JDK 1.2 now throws a NullPointerException. Null can no longer be used as a bit recycler (/dev/null for UNIX) kind of destination. Using null was probably never intended in the first place; this is most likely improved error checking in JDK 1.2. Listing Nine runs under JDK 1.1 but throws a NullPointerException under JDK 1.2.

Improved error checking also results in new and/or different exceptions being thrown for invalid buffer sizes (size< = 0). Listing Ten will run under JDK 1.1 and JDK 1.2 Beta 3, but throws IllegalArgumentException under JDK 1.2 Beta 4.

java.io.StringReader.ready can now throw an IOException in JDK 1.2. Listing Eleven is legal in 1.1, but becomes Listing Twelve for 1.2. Changes and/or bug fixes relating to use of the system-dependent default name-separator character ("/" on UNIX and "\" on Win32) result in different return values under JDK 1.2 Beta 4 for some Strings that contain paths. On Win32, Listing Thirteen returns "/" under JDK 1.1 and JDK 1.2 Beta 3, but returns "\" under JDK 1.2 Beta 4.

The hashcode values returned from File objects have changed in JDK 1.2 Beta 4.

Serialization has also changed. You should check the JDK 1.2 release notes for full details -- there are no breaking API changes in JDK 1.2 Beta 4, but there is new functionality. In particular, there is a new API for accessing persistent fields -- java.io.ObjectOutputStream.putField and java.io.ObjectInputStream.getField. Furthermore, serialization now uses the new JDK 1.2 security model.

Utilities

java.util.properties.put is stricter in JDK 1.2 and requires both the key and value arguments to be of type String. An IllegalArgumentException is now thrown if an object which is not a String is passed. This is probably just improved error checking in JDK 1.2, and shouldn't cause any migration difficulties. Listing Fourteen is allowed in JDK 1.1 but throws an IllegalArgumentException in 1.2.

Security

Code signed using JDK 1.2 will appear unsigned on JDK 1.1, and vice versa. If you used digital signatures to ensure the authenticity and integrity of code in JDK 1.1, such security measures will be ignored under JDK 1.2, and vice versa.

In JDK 1.2, security has changed drastically. Some of the JDK 1.1 API is still present but there are major changes. Most of the interfaces in java.security.acl have been superseded, and the interface java.security.acl.Permission has become the abstract class java.security.Permission. The following classes in java.security are deprecated in 1.2: Certificate, Identity, IdentityScope, Signer. The method java.lang.SecurityManager.Check has been added to java.lang.SecurityManager. If your application makes any significant use of the Java security features, you should examine the new security architecture very carefully.

Remote Method Invocation (RMI)

JDK 1.2 no longer uses the system properties java.rmi.loader.packagePrefix and java.rmi.server.packagePrefix to override the system default value (sun.rmi.server) for the public String data members java.rmi .server.LoaderHandler.packagePrefix and java.rmi.server.RemoteRef.packagePrefix. LoaderHandler uses its package prefix to locate the implementation of the LoaderHandler class and RemoteRef uses its package prefix to find the implementation of server ref classes (UnicastRef, UnicastServerRef, and so on). These changes should only impact implementors of specialized versions of RMI, such as SanFrancisco's Extended RMI (SF ERMI).

Tools

The Java tools have also changed substantially. A common debugging tactic is to insert specialized versions of JDK classes in a private directory hierarchy, which is then placed at the beginning of the CLASSPATH, so that the specialized classes are found before the regular versions. In JDK 1.2, inserting substitute classes earlier in the CLASSPATH no longer replaces system classes in the rt.jar and i18n.jar files (JDK 1.2 Beta 4) or the classes.zip file (JDK 1.2 Beta 3). You can use the new -Xbootclasspath in JDK 1.2 Beta 4 (-Xsysclasspath option in JDK 1.2 Beta 3), which is similar to -classpath but for the new separate boot/system path. Starting with JDK 1.2, -classpath is used for the application class loader that is now separate from the boot/system class loader.

There is also a new property in JDK 1.2 that parallels java.class.path but is for the boot/system classes. In JDK 1.2 Beta 4, this property is sun.boot.class.path, and in JDK 1.2 Beta 3, the property is java.sys.class.path. This property is combined with the user-class path (from the CLASSPATH environment variable) and placed in the system property java.class.path. If your program needs to find the bootstrap classes, you should probably use sun.boot.class.path.

Also, JDK 1.2 appears to use more memory than JDK 1.1. At times, memory needed to be increased when running javadoc, javac, and java on JDK 1.2 for tasks that, on JDK 1.1, succeeded in the default heap allocation.

We hope this will be unnecessary in the final release of JDK 1.2. The initial and maximum heap allocation sizes can be reset on JDK 1.2 using the -Xms and -Xmx flags (just like the -ms and -mx flags on JDK 1.1). These flags can be passed through javac and javadoc by prepending the -J flag; for example, javac -J-Xmx128m <java file>. Alternatively, the main programs for javadoc and javac can be run directly via a java command with the appropriate -Xmx flag (for example, java -Xmx128m sun.tools.javadoc.Main on JDK 1.2 Beta 3). This becomes more difficult starting with JDK 1.2 Beta 4, because these classes moved from sun.tools in the classes.zip file to com.sun.tools in the new tools.jar file, which must be added to either the classpath or bootclasspath to locate and load them (for instance, java -Xmx128m -classpath .;D:\ jdk1.2beta4\lib\tools.jarcom.sun.tools. javadoc.Main).

We also found that, although the -ms and -mx flags for JDK 1.1 are no longer listed in the options help list for java on JDK 1.2, they still seem to work. If you are currently using either the -ms or -mx flag, at some point in the future you may be forced to upgrade to the newer -Xms and -Xmx flags.

Conclusion

Due to the size of the original JDK 1.1 and the subsequent expansion of JDK 1.2, we probably haven't uncovered every porting issue related to moving to JDK 1.2. We do believe that we have found many of the common challenges that you will experience when the time comes to jump to 1.2. You can visit our web site at http://www. ibm.com/java/ for this and other IBM Java related activities.

Acknowledgment

We would like to thank Chih-Hsiang Chou and Jeff Ryan for their timely and valuable technical help with SF ERMI. We would also like to thank Richard Gillam and Rahul Jain for their helpful comments and review of this article. Finally, we would like to thank Rajiv Jain, Tom Watson, and Kathleen Wilson for their support and guidance.

DDJ

Listing One

public class MyWindow extends java.awt.Window {    public Vector getOwnedWindows() {
        // body of getOwnedWindows
    }
    // ... rest of MyWindow
}

Back to Article

Listing Two

public class MyWindow extends java.awt.Window {    public Window[] getOwnedWindows() {
        // body of getOwnedWindows
    }
    // ... rest of MyWindow
}

Back to Article

Listing Three

public class MyJDBCConnection implements java.sql.Connection {   // body of class ...
}

Back to Article

Listing Four

public class MyJDBCConnection implements java.sql.Connection {    // body of class from above ...
    public Map getTypeMap() throws SQLException {
        // new code
    }
}

Back to Article

Listing Five

public integer indexOfNull(Vector v) {    return v.indexOf(null);
}

Back to Article

Listing Six

class WidgetManager extends Vector {    public boolean add(Object o) {
        // body of add
    }
    // remainder of WidgetManager
}

Back to Article

Listing Seven

public String fontName() {    Font testFont = new Font("BogusFontName", Font.ITALIC, 9);
    return (testFont.getName());
}

Back to Article

Listing Eight

public String fontName() {    Font testFont = new Font("BogusFontName", Font.ITALIC, 9);
    return (testFont.getFamily());
}

Back to Article

Listing Nine

Properties p = new Properties();OutputStream out = null;
String header = null;
p.put("key", "value");
p.save(out, header);

Back to Article

Listing Ten

PipedOutputStream pipedStream = new PipedOutputStream(newPipedInputStream());BufferedOutputStream bufferedStream = new BufferedOutputStream(pipedStream,0);

Back to Article

Listing Eleven

public boolean readyTest {StringReader r) {   return  r.ready();
}

Back to Article

Listing Twelve

public boolean readyTest(StringReader r) {    try {
        return r.ready();
    } catch (IOException e) {
        System.out.println("StringReader not ready");
    }
}

Back to Article

Listing Thirteen

public String whatPath() {    File myFile=new File("/");
    return (myFile.getPath());
}

Back to Article

Listing Fourteen

public void putStuffOnProperties(Properties p) {    p.put("Number",1);
}

Back to Article


Copyright © 1999, Dr. Dobb's Journal

Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.