JDK-4741757 : LTP: XMLEncoder ignores persistence delegates when used with java web start
  • Type: Bug
  • Component: client-libs
  • Sub-Component: java.beans
  • Affected Version: 1.2.0,1.4.2,6
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • OS: generic,linux
  • CPU: generic,x86
  • Submitted: 2002-09-04
  • Updated: 2006-04-13
  • Resolved: 2006-03-16
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 6
6 b76Fixed
Related Reports
Duplicate :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Description
Name: nt126004			Date: 09/04/2002


FULL PRODUCT VERSION :
java version "1.4.0_01"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.0_01-b03)
Java HotSpot(TM) Client VM (build 1.4.0_01-b03, mixed mode)


FULL OPERATING SYSTEM VERSION :
Linux 2.4.18-5
glibc-2.2.5-36
red hat 7.3

A DESCRIPTION OF THE PROBLEM :
When using java.beans.XMLEncoder in a java web start
application, persistence delegates are ignored. The attached
code is a short (25 line) program that creates an object,
creates an XMLEncoder writing to System.out, adds a
persistence delegate, and writes the object. When run as an
application, this works perfectly. When run with java web
start, the exact same jar file emits an error because the
persistence delegate is ignored.

I have the application set up as a java web start program at
http://www.igoweb.org/~wms/comp/xetest/ to make it easier to
see this behavior.


STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Start up java web start; enable logging or enable java
console (directions to do this in the web page mentioned below)
2. Visit http://www.igoweb.org/~wms/comp/xetest/
3. Download the jar file
4. Run jar file locally with "java -jar xetest.jar"; observe
output.
5. Run same jar file by java web start from same web page as
above
6. Note the output of the java web start program

EXPECTED VERSUS ACTUAL BEHAVIOR :
Expected: The two should produce exactly the same output.
There is no code in the application that should be different
under java web start and a normal application.

Actual: When run with "java -jar xetest.jar", the object is
properly encoded and sent to System.out. When run with java
web start, as error is printed and the object is not
properly encoded. My tests have shown that the problem is
that the reason for the error is that the persistence
delegate is ignored.


ERROR MESSAGES/STACK TRACES THAT OCCUR :
Output of application (correct):

<?xml version="1.0" encoding="UTF-8"?>
<java version="1.4.0_01" class="java.beans.XMLDecoder">
 <object class="XETest">
  <int>5</int>
 </object>

Output of java web start (incorrect):

Java Web Start Console, started Fri Aug 09 09:33:00 PDT 2002
Java 2 Runtime Environment: Version 1.4.0 by Sun Microsystems Inc.
java.lang.Exception: discarding statement XMLEncoder0.writeObject(XETest0);
Continuing ...
<?xml version="1.0" encoding="UTF-8"?>
<java version="1.4.0" class="java.beans.XMLDecoder">

Note that the error appears above, and the object is not emitted. Unfortunately
the full exception trace is not given by the XMLEncoder.


REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import java.beans.*;wabi333


public class XETest {

  private int value;

  public XETest(int value) {
    this.value = value;
  }

  public int getValue() {
    return(value);
  }

  public static void main(String args[]) {
    Object testObj = new XETest(5);
    XMLEncoder e = new XMLEncoder(System.out);
    e.setPersistenceDelegate(
      XETest.class,
      new DefaultPersistenceDelegate(new String[] {"value"}));
    e.writeObject(testObj);
    e.flush();
  }
}

---------- END SOURCE ----------

CUSTOMER WORKAROUND :
None known.
(Review ID: 160587) 
======================================================================

Comments
EVALUATION There are two secured methods in DefaultPersistenceDelegate that should be refactored. 1. private static boolean definesEquals(Class type) <code> type.getDeclaredMethod("equals", new Class[]{Object.class}); return true; </code> We can rewrite it: <code> return type == type.getMethod("equals", Object.class).getDeclaringClass(); </code> This code part is allowed by SecurityManager. 2. protected Expression instantiate(Object oldInstance, Encoder out) There hack that contradicts the JavaBeans specification: <code> Field f = null; try { // System.out.println("Trying field " + name + " in " + type); f = type.getDeclaredField(name); f.setAccessible(true); } catch (NoSuchFieldException e) {} </code> It accesses to the properties by field name instead getter method. We should remove this hack!
20-02-2006

PUBLIC COMMENTS .
02-10-2004

WORK AROUND Rewrite the class so that it has a no arg constructor. Sign the JWS deployed jar file. ###@###.### 2002-12-09
09-12-2002

EVALUATION The problem is the XMLEncoder requires ( at least in XMLDecoder.writeStatement) the permission: (java.lang.RuntimePermission accessDeclaredMembers), and when running in an unsigned application under java web start, it dosn't have this permmision. The coder in writeStatement: try { super.writeStatement(oldStm); ... } catch (Exception e) { getExceptionListener().exceptionThrown(new Exception("discarding statement " + oldStm)); } compounds the problem by masking out the: java.security.AccessControlException: access denied (java.lang.RuntimePermission accessDeclaredMembers) and shows a "discarding statement" instead. writeStatement should at least be: try { ... } catch (Exception e) { getExceptionListener().exceptionThrown(e); getExceptionListener().exceptionThrown(new Exception("discarding statement " + oldStm)); } to show the user what the real cause of the problem is. ###@###.### 2002-09-06 ---- The exception handling in XMLEncoder.writeStatement has been changed to include the original exception for 1.4.2. catch (Exception e) { getExceptionListener().exceptionThrown(new Exception("discarding statement " + oldStm, e)); } Not sure about the extent of the problem. It may be a requirement that priviledged access must be for the XMLEncoder to work correctly in a network context. ###@###.### 2002-09-06 I tried out the developer's site with both 1.4.1 and 1.4.2 (nov 02) and I found that it still didn't fix the problem. This is a security issue which will have to be resolved in 1.5. ###@###.### 2002-12-09 I added an exception listener to the encoder to get a better stack trace: Java Web Start 1.2 Console, started Mon Dec 09 15:39:56 PST 2002 Java 2 Runtime Environment: Version 1.4.2-internal by Sun Microsystems Inc. Exception thrown during serialization: java.lang.Exception: discarding statement XMLEncoder0.writeObject(XETest0); at java.beans.XMLEncoder.writeStatement(XMLEncoder.java:339) at java.beans.XMLEncoder.writeObject(XMLEncoder.java:253) at XETest.main(XETest.java:27) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:324) at com.sun.javaws.Launcher.executeApplication(Launcher.java:778) at com.sun.javaws.Launcher.executeMainClass(Launcher.java:740) at com.sun.javaws.Launcher.continueLaunch(Launcher.java:625) at com.sun.javaws.Launcher.handleApplicationDesc(Launcher.java:352) at com.sun.javaws.Launcher.handleLaunchFile(Launcher.java:177) at com.sun.javaws.Launcher.run(Launcher.java:145) at java.lang.Thread.run(Thread.java:536) Caused by: java.security.AccessControlException: access denied (java.lang.RuntimePermission accessDeclaredMembers) at java.security.AccessControlContext.checkPermission(AccessControlContext.java:270) at java.security.AccessController.checkPermission(AccessController.java:401) at java.lang.SecurityManager.checkPermission(SecurityManager.java:542) at java.lang.SecurityManager.checkMemberAccess(SecurityManager.java:1662) at java.lang.Class.checkMemberAccess(Class.java:1438) at java.lang.Class.getDeclaredMethod(Class.java:1251) at java.beans.DefaultPersistenceDelegate.definesEquals(DefaultPersistenceDelegate.java:83) at java.beans.DefaultPersistenceDelegate.definesEquals(DefaultPersistenceDelegate.java:96) at java.beans.DefaultPersistenceDelegate.mutatesTo(DefaultPersistenceDelegate.java:119) at java.beans.PersistenceDelegate.writeObject(PersistenceDelegate.java:98) at java.beans.Encoder.writeObject(Encoder.java:55) at java.beans.XMLEncoder.writeObject(XMLEncoder.java:250) at java.beans.Encoder.writeObject1(Encoder.java:192) at java.beans.Encoder.cloneStatement(Encoder.java:205) at java.beans.Encoder.writeStatement(Encoder.java:236) at java.beans.XMLEncoder.writeStatement(XMLEncoder.java:326) ... 13 more <?xml version="1.0" encoding="UTF-8"?> <java version="1.4.2-internal" class="java.beans.XMLDecoder"> ###@###.### 2002-12-09
09-12-2002