Hi again,
Imagine my horror this morning when I tried to run the code from last nights newsletter and discovered that it generated an exception! On frantic searching I figured that the JBuilder 3.0 compiler produces a different result to the SUN JDK 1.3 compiler. I had only run the program from within JBuilder, so I got quite a surprise that it did not work in SUN. The reason I'm blaming the compiler is because when I ran the class files generated by JBuilder 3.0 with the JDK 1.3 VM it works perfectly.
The problem is that if you call out.defaultWriteObject()
, the two compilers have different ideas of which object you are calling this from, because you are inside an inner class. The SUN compiler thinks you are calling it from ComponentSerializer and that is not serializable.
The solution is quite simple, just move the ComponentEncapsulator class out of the ComponentSerializer class and it should work with the JDK 1.3 compiler.
We thus end up with ComponentSerializer:
//: ComponentSerializer.java import java.io.*; import java.awt.*; public class ComponentSerializer { public void write(Component comp, OutputStream out) throws IOException { System.out.println("writing " + comp); ObjectOutputStream oout = new ObjectOutputStream(out); oout.writeObject(new ComponentEncapsulator(comp)); oout.reset(); oout.flush(); } public Component read(InputStream in) throws IOException, ClassNotFoundException { System.out.println("reading component"); ObjectInputStream oin = new ObjectInputStream(in); ComponentEncapsulator enc = (ComponentEncapsulator)oin.readObject(); return enc.getComponent(); } }and ComponentEncapsulator:
//: ComponentEncapsulator.java import java.io.*; import java.awt.*; import javax.swing.*; import java.lang.reflect.*; // wouldn't be right for me to send // you a newsletter that doesn't use reflection :) class ComponentEncapsulator implements Serializable { private final Component comp; private IOException defaultWriteException; public ComponentEncapsulator(Component comp) { this.comp = comp; } public Component getComponent() { return comp; } private void writeObject(final ObjectOutputStream out) throws IOException { if (SwingUtilities.isEventDispatchThread()) { // This is all that is necessary if we are already in // the event dispatch thread, e.g. a user clicked a // button which caused the object to be written out.defaultWriteObject(); } else { try { // we want to wait until the object has been written // before continuing. If we called this from the // event dispatch thread we would get an exception SwingUtilities.invokeAndWait(new Runnable() { public void run() { try { // easiest way to indicate to the enclosing class // that an exception occurred is to have a member // which keeps the IOException defaultWriteException = null; // we call the actual write object method out.defaultWriteObject(); } catch(IOException ex) { // oops, an exception occurred, remember the // exception object defaultWriteException = ex; } } }); if (defaultWriteException != null) { // an exception occurred in the code above, throw it! throw defaultWriteException; } } catch(InterruptedException ex) { // I'm not quite sure what do here, perhaps: Thread.currentThread().interrupt(); return; } catch(InvocationTargetException ex) { // This can actually only be a RuntimeException or an // Error - in either case we want to rethrow them Throwable target = ex.getTargetException(); if (target instanceof RuntimeException) { throw (RuntimeException)target; } else if (target instanceof Error) { throw (Error)target; } ex.printStackTrace(); // this should not happen! throw new RuntimeException(ex.toString()); } } } }This highlights again that we have to be quite careful with Java. In the big project that we work on, we have standardized on the JDK 1.3 compiler and ALL our classes have to be compiled with that. This happened only after much nailbiting because of slight compiler differences of various IDEs.
created by Dr. Heinz M. Kabutz
0 komentar:
Posting Komentar