-
Bug
-
Resolution: Duplicate
-
P4
-
None
-
6u21
-
x86
-
windows_vista
FULL PRODUCT VERSION :
java version "1.6.0_20"
Java(TM) SE Runtime Environment (build 1.6.0_20-b02-279-10M3065)
Java HotSpot(TM) 64-Bit Server VM (build 16.3-b01-279, mixed mode)
And other versions too
ADDITIONAL OS VERSION INFORMATION :
All operating systems
A DESCRIPTION OF THE PROBLEM :
I think there is a bug in the DefaultPersistenceDelegate class in the method:
private static boolean definesEquals(Class type) {
try {
return type == type.getMethod("equals", Object.class).getDeclaringClass();
}
catch(NoSuchMethodException e) {
return false;
}
}
When used on a class like Rectangle2D.Double it returns false (because the equals() method is defined in the enclosing class).
This means that DefaultPersistenceDelegates may NOT get called if a bean property has been initialised to anything other than null and where the property equals method is not declared directly in the class.
Without documentation I cannot determine the intent of the existing code for definesEquals() , but if it is to return true if a class has
a suitable equals() method then this would seem to work:
private static boolean definesEquals(Class type) {
try {
// return true if type defines a method with signature: boolean equals(Object o)
return boolean.class == type.getMethod("equals", Object.class).getReturnType();
} catch (NoSuchMethodException e) {
return false;
}
}
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the test application twice setting THIS_WORKS to true ad then false.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
THIS_WORKS=true
bean as XML is :
<?xml version="1.0" encoding="UTF-8"?>
<java version="1.6.0_20" class="java.beans.XMLDecoder">
<object class="TestBean">
<void property="bounds">
<object class="java.awt.geom.Rectangle2D$Double">
<double>1.0</double>
<double>2.0</double>
<double>3.0</double>
<double>5.0</double>
</object>
</void>
</object>
</java>
bean.getBounds() as XML is :
<?xml version="1.0" encoding="UTF-8"?>
<java version="1.6.0_20" class="java.beans.XMLDecoder">
<object class="java.awt.geom.Rectangle2D$Double">
<double>1.0</double>
<double>2.0</double>
<double>3.0</double>
<double>5.0</double>
</object>
</java>
ACTUAL -
THIS_WORKS=false
bean as XML is :
<?xml version="1.0" encoding="UTF-8"?>
<java version="1.6.0_20" class="java.beans.XMLDecoder">
<object class="TestBean"/>
</java>
bean.getBounds() as XML is :
<?xml version="1.0" encoding="UTF-8"?>
<java version="1.6.0_20" class="java.beans.XMLDecoder">
<object class="java.awt.geom.Rectangle2D$Double">
<double>1.0</double>
<double>2.0</double>
<double>3.0</double>
<double>5.0</double>
</object>
</java>
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
import java.awt.geom.Rectangle2D;
import java.beans.DefaultPersistenceDelegate;
import java.beans.XMLEncoder;
import java.io.ByteArrayOutputStream;
/**
*
* Bug with XMLEncoder and DefaultPersistenceDelegate
*
* DefaultPersistenceDelegate is not called when a bean property has been
* initialised to non null?
*
* This TestBean has a bounds property of type Rectangle2D.Double. The
* XMLEncoder requires a persistenceDelegate in order to encode
* Rectangle2D.Double.
* <p>
* However, if TestBean is initialised with its bounds property set to anything
* other than null, the persistenceDelegate is not invoked for the bounds
* property when writeObject is used on the TestBean. The persistenceDelegate
* still gets called if you call writeObject on the bounds property rather than
* the TestBean.
* <p>
*
* Try running this program changing THIS_WORKS between true and false.
*
*
* @author Michael Ellis.
*/
public class TestBean {
private static boolean THIS_WORKS = false;
Rectangle2D.Double bounds;
/**
*
*/
public TestBean() {
if (THIS_WORKS) {
bounds = null; // THIS WORKS
} else {
bounds = new Rectangle2D.Double(1, 2, 3, 4); // THIS DOESN'T WORK
}
}
public Rectangle2D.Double getBounds() {
return bounds;
}
public void setBounds(Rectangle2D.Double bounds) {
this.bounds = bounds;
}
public static void main(String[] args) {
TestBean bean = new TestBean();
bean.setBounds(new Rectangle2D.Double(1, 2, 3, 5));
System.out.printf("THIS_WORKS=%b\n", THIS_WORKS);
System.out.printf("bean as XML is :\n%s\n", objectToXML(bean));
System.out.printf("bean.getBounds() as XML is :\n%s\n", objectToXML(bean.getBounds()));
}
static String objectToXML(Object o) {
final ByteArrayOutputStream bos = new ByteArrayOutputStream();
final XMLEncoder encoder = new XMLEncoder(bos);
encoder.setPersistenceDelegate(Rectangle2D.Double.class, new DefaultPersistenceDelegate(
new String[] { "x", "y", "width", "height" }));
encoder.writeObject(o);
encoder.close();
return bos.toString();
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Override the mutatesTo() method when using DefaultPersistenceDelegate, for example:
encoder.setPersistenceDelegate(Rectangle2D.Double.class, new DefaultPersistenceDelegate(
new String[] { "x", "y", "width", "height" }) {
@Override
protected boolean mutatesTo(Object oldInstance, Object newInstance) {
return (super.mutatesTo(oldInstance, newInstance) && oldInstance.equals(newInstance));
}
});
java version "1.6.0_20"
Java(TM) SE Runtime Environment (build 1.6.0_20-b02-279-10M3065)
Java HotSpot(TM) 64-Bit Server VM (build 16.3-b01-279, mixed mode)
And other versions too
ADDITIONAL OS VERSION INFORMATION :
All operating systems
A DESCRIPTION OF THE PROBLEM :
I think there is a bug in the DefaultPersistenceDelegate class in the method:
private static boolean definesEquals(Class type) {
try {
return type == type.getMethod("equals", Object.class).getDeclaringClass();
}
catch(NoSuchMethodException e) {
return false;
}
}
When used on a class like Rectangle2D.Double it returns false (because the equals() method is defined in the enclosing class).
This means that DefaultPersistenceDelegates may NOT get called if a bean property has been initialised to anything other than null and where the property equals method is not declared directly in the class.
Without documentation I cannot determine the intent of the existing code for definesEquals() , but if it is to return true if a class has
a suitable equals() method then this would seem to work:
private static boolean definesEquals(Class type) {
try {
// return true if type defines a method with signature: boolean equals(Object o)
return boolean.class == type.getMethod("equals", Object.class).getReturnType();
} catch (NoSuchMethodException e) {
return false;
}
}
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the test application twice setting THIS_WORKS to true ad then false.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
THIS_WORKS=true
bean as XML is :
<?xml version="1.0" encoding="UTF-8"?>
<java version="1.6.0_20" class="java.beans.XMLDecoder">
<object class="TestBean">
<void property="bounds">
<object class="java.awt.geom.Rectangle2D$Double">
<double>1.0</double>
<double>2.0</double>
<double>3.0</double>
<double>5.0</double>
</object>
</void>
</object>
</java>
bean.getBounds() as XML is :
<?xml version="1.0" encoding="UTF-8"?>
<java version="1.6.0_20" class="java.beans.XMLDecoder">
<object class="java.awt.geom.Rectangle2D$Double">
<double>1.0</double>
<double>2.0</double>
<double>3.0</double>
<double>5.0</double>
</object>
</java>
ACTUAL -
THIS_WORKS=false
bean as XML is :
<?xml version="1.0" encoding="UTF-8"?>
<java version="1.6.0_20" class="java.beans.XMLDecoder">
<object class="TestBean"/>
</java>
bean.getBounds() as XML is :
<?xml version="1.0" encoding="UTF-8"?>
<java version="1.6.0_20" class="java.beans.XMLDecoder">
<object class="java.awt.geom.Rectangle2D$Double">
<double>1.0</double>
<double>2.0</double>
<double>3.0</double>
<double>5.0</double>
</object>
</java>
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
import java.awt.geom.Rectangle2D;
import java.beans.DefaultPersistenceDelegate;
import java.beans.XMLEncoder;
import java.io.ByteArrayOutputStream;
/**
*
* Bug with XMLEncoder and DefaultPersistenceDelegate
*
* DefaultPersistenceDelegate is not called when a bean property has been
* initialised to non null?
*
* This TestBean has a bounds property of type Rectangle2D.Double. The
* XMLEncoder requires a persistenceDelegate in order to encode
* Rectangle2D.Double.
* <p>
* However, if TestBean is initialised with its bounds property set to anything
* other than null, the persistenceDelegate is not invoked for the bounds
* property when writeObject is used on the TestBean. The persistenceDelegate
* still gets called if you call writeObject on the bounds property rather than
* the TestBean.
* <p>
*
* Try running this program changing THIS_WORKS between true and false.
*
*
* @author Michael Ellis.
*/
public class TestBean {
private static boolean THIS_WORKS = false;
Rectangle2D.Double bounds;
/**
*
*/
public TestBean() {
if (THIS_WORKS) {
bounds = null; // THIS WORKS
} else {
bounds = new Rectangle2D.Double(1, 2, 3, 4); // THIS DOESN'T WORK
}
}
public Rectangle2D.Double getBounds() {
return bounds;
}
public void setBounds(Rectangle2D.Double bounds) {
this.bounds = bounds;
}
public static void main(String[] args) {
TestBean bean = new TestBean();
bean.setBounds(new Rectangle2D.Double(1, 2, 3, 5));
System.out.printf("THIS_WORKS=%b\n", THIS_WORKS);
System.out.printf("bean as XML is :\n%s\n", objectToXML(bean));
System.out.printf("bean.getBounds() as XML is :\n%s\n", objectToXML(bean.getBounds()));
}
static String objectToXML(Object o) {
final ByteArrayOutputStream bos = new ByteArrayOutputStream();
final XMLEncoder encoder = new XMLEncoder(bos);
encoder.setPersistenceDelegate(Rectangle2D.Double.class, new DefaultPersistenceDelegate(
new String[] { "x", "y", "width", "height" }));
encoder.writeObject(o);
encoder.close();
return bos.toString();
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Override the mutatesTo() method when using DefaultPersistenceDelegate, for example:
encoder.setPersistenceDelegate(Rectangle2D.Double.class, new DefaultPersistenceDelegate(
new String[] { "x", "y", "width", "height" }) {
@Override
protected boolean mutatesTo(Object oldInstance, Object newInstance) {
return (super.mutatesTo(oldInstance, newInstance) && oldInstance.equals(newInstance));
}
});
- duplicates
-
JDK-7169395 Exception throws due to the changes in JDK 7 object tranversal and break backward compatibility
- Resolved
- relates to
-
JDK-7169395 Exception throws due to the changes in JDK 7 object tranversal and break backward compatibility
- Resolved
-
JDK-7080156 LTP: Sometimes XMLEncoder does not encode public array fields
- Closed