Index: /home/ralf/Workspace/castor-2/src/bugs/xml/c1342/Proxy.java =================================================================== --- /home/ralf/Workspace/castor-2/src/bugs/xml/c1342/Proxy.java (Revision 0) +++ /home/ralf/Workspace/castor-2/src/bugs/xml/c1342/Proxy.java (Revision 0) @@ -0,0 +1,29 @@ +package xml.c1342; + +import java.lang.reflect.Method; + +import net.sf.cglib.proxy.Enhancer; +import net.sf.cglib.proxy.MethodInterceptor; +import net.sf.cglib.proxy.MethodProxy; + +public class Proxy implements MethodInterceptor { + public static Object newInstance(final Object object){ + try{ + Proxy proxy = new Proxy(object); + return Enhancer.create(object.getClass(), new Class[] {}, proxy); + } catch (Throwable e){ + e.printStackTrace(); + throw new Error(e.getMessage()); + } + } + + private final Object _object; + + private Proxy(final Object object) { + _object = object; + } + + public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { + return method.invoke(_object, args); + } +} Index: /home/ralf/Workspace/castor-2/src/bugs/xml/c1342/Bean.java =================================================================== --- /home/ralf/Workspace/castor-2/src/bugs/xml/c1342/Bean.java (Revision 0) +++ /home/ralf/Workspace/castor-2/src/bugs/xml/c1342/Bean.java (Revision 0) @@ -0,0 +1,40 @@ +package xml.c1342; + +public class Bean { + private Integer _attribute; + private String _element; + private String _text; + private Bean _reference; + + public Integer getAttribute() { + return _attribute; + } + + public void setAttribute(final Integer attribute) { + _attribute = attribute; + } + + public String getElement() { + return _element; + } + + public void setElement(final String element) { + _element = element; + } + + public String getText() { + return _text; + } + + public void setText(final String text) { + _text = text; + } + + public Bean getReference() { + return _reference; + } + + public void setReference(final Bean reference) { + _reference = reference; + } +} Index: /home/ralf/Workspace/castor-2/src/bugs/xml/c1342/Test1342.java =================================================================== --- /home/ralf/Workspace/castor-2/src/bugs/xml/c1342/Test1342.java (Revision 0) +++ /home/ralf/Workspace/castor-2/src/bugs/xml/c1342/Test1342.java (Revision 0) @@ -0,0 +1,262 @@ +package xml.c1342; + +import java.io.StringReader; +import java.io.StringWriter; + +import junit.framework.TestCase; + +import net.sf.cglib.proxy.Factory; + +import org.exolab.castor.mapping.Mapping; +import org.exolab.castor.util.Configuration; +import org.exolab.castor.util.LocalConfiguration; +import org.exolab.castor.xml.Marshaller; +import org.exolab.castor.xml.Unmarshaller; + +public final class Test1342 extends TestCase { + private static final String MAPPING_FILE = "mapping.xml"; + + public Test1342() { + super(); + } + + /** + * Test unmarshalling of simple bean without proxy. + * + * @throws Exception For any exception thrown. + */ + public void testUnmarshalSimpleBean() throws Exception { + Mapping mapping = new Mapping(); + mapping.loadMapping(getClass().getResource(MAPPING_FILE).toExternalForm()); + + Unmarshaller unmarshaller = new Unmarshaller(Bean.class); + unmarshaller.setMapping(mapping); + + String input + = "\n" + + "" + + "element of 999" + + ""; + + Bean bean = (Bean) unmarshaller.unmarshal(new StringReader(input)); + assertNotNull(bean); + assertEquals(999, bean.getAttribute().intValue()); + assertEquals("element of 999", bean.getElement()); + assertNull(bean.getReference()); + } + + /** + * Test unmarshalling of bean refering to another one without proxy. + * + * @throws Exception For any exception thrown. + */ + public void testUnmarshalReferingBean() throws Exception { + Mapping mapping = new Mapping(); + mapping.loadMapping(getClass().getResource(MAPPING_FILE).toExternalForm()); + + Unmarshaller unmarshaller = new Unmarshaller(Bean.class); + unmarshaller.setMapping(mapping); + + String input + = "\n" + + "" + + "element of 100" + + "" + + "element of 999" + + "" + + ""; + + Bean referer = (Bean) unmarshaller.unmarshal(new StringReader(input)); + assertNotNull(referer); + assertEquals(100, referer.getAttribute().intValue()); + assertEquals("element of 100", referer.getElement()); + assertNotNull(referer.getReference()); + + Bean refered = referer.getReference(); + assertNotNull(refered); + assertEquals(999, refered.getAttribute().intValue()); + assertEquals("element of 999", refered.getElement()); + assertNull(refered.getReference()); + } + + /** + * Test marshalling of simple bean without proxy. + * + * @throws Exception For any exception thrown. + */ + public void testMarshalSimpleBean() throws Exception { + Mapping mapping = new Mapping(); + mapping.loadMapping(getClass().getResource(MAPPING_FILE).toExternalForm()); + + StringWriter out = new StringWriter(); + Marshaller marshaller = new Marshaller(out); + marshaller.setMapping(mapping); + + Bean bean = new Bean(); + bean.setAttribute(new Integer(999)); + bean.setElement("element of 999"); + bean.setReference(null); + + marshaller.marshal(bean); + + String output = out.toString(); + + String expected + = "\n" + + "" + + "element of 999" + + ""; + + assertEquals(expected, output); + } + + /** + * Test marshalling of bean refering to another one without proxy. + * + * @throws Exception For any exception thrown. + */ + public void testMarshalReferingBean() throws Exception { + Mapping mapping = new Mapping(); + mapping.loadMapping(getClass().getResource(MAPPING_FILE).toExternalForm()); + + StringWriter out = new StringWriter(); + Marshaller marshaller = new Marshaller(out); + marshaller.setMapping(mapping); + + Bean refered = new Bean(); + refered.setAttribute(new Integer(999)); + refered.setElement("element of 999"); + refered.setReference(null); + + Bean referer = new Bean(); + referer.setAttribute(new Integer(100)); + referer.setElement("element of 100"); + referer.setReference(refered); + + marshaller.marshal(referer); + + String output = out.toString(); + + String expected + = "\n" + + "" + + "element of 100" + + "" + + "element of 999" + + "" + + ""; + + assertEquals(expected, output); + } + + /** + * Test marshalling of simple bean with proxy. + * + * @throws Exception For any exception thrown. + */ + public void testMarshalSimpleBeanProxy() throws Exception { + Configuration config = LocalConfiguration.getInstance(); + config.getProperties().setProperty( + Configuration.Property.ProxyInterface, "net.sf.cglib.proxy.Factory"); + + Mapping mapping = new Mapping(); + mapping.loadMapping(getClass().getResource(MAPPING_FILE).toExternalForm()); + + StringWriter out = new StringWriter(); + Marshaller marshaller = new Marshaller(out); + marshaller.setMapping(mapping); + + Bean bean = new Bean(); + bean.setAttribute(new Integer(999)); + bean.setElement("element of 999"); + bean.setReference(null); + + Bean proxy = (Bean) Proxy.newInstance(bean); + + assertNotNull(proxy); + assertEquals(Bean.class, proxy.getClass().getSuperclass()); + assertEquals(1, proxy.getClass().getInterfaces().length); + assertEquals(Factory.class, proxy.getClass().getInterfaces()[0]); + + assertEquals(999, proxy.getAttribute().intValue()); + assertEquals("element of 999", proxy.getElement()); + assertNull(proxy.getReference()); + + marshaller.marshal(proxy); + + String output = out.toString(); + + String expected + = "\n" + + "" + + "element of 999" + + ""; + + assertEquals(expected, output); + } + + /** + * Test marshalling of bean refering to another one with proxy. + * + * @throws Exception For any exception thrown. + */ + public void testMarshalReferingBeanProxy() throws Exception { + Configuration config = LocalConfiguration.getInstance(); + config.getProperties().setProperty( + Configuration.Property.ProxyInterface, "net.sf.cglib.proxy.Factory"); + + Mapping mapping = new Mapping(); + mapping.loadMapping(getClass().getResource(MAPPING_FILE).toExternalForm()); + + StringWriter out = new StringWriter(); + Marshaller marshaller = new Marshaller(out); + marshaller.setMapping(mapping); + + Bean refered = new Bean(); + refered.setAttribute(new Integer(999)); + refered.setElement("element of 999"); + refered.setReference(null); + + Bean referedProxy = (Bean) Proxy.newInstance(refered); + + assertNotNull(referedProxy); + assertEquals(Bean.class, referedProxy.getClass().getSuperclass()); + assertEquals(1, referedProxy.getClass().getInterfaces().length); + assertEquals(Factory.class, referedProxy.getClass().getInterfaces()[0]); + + assertEquals(999, referedProxy.getAttribute().intValue()); + assertEquals("element of 999", referedProxy.getElement()); + assertNull(referedProxy.getReference()); + + Bean referer = new Bean(); + referer.setAttribute(new Integer(100)); + referer.setElement("element of 100"); + referer.setReference(referedProxy); + + Bean refererProxy = (Bean) Proxy.newInstance(referer); + + assertNotNull(refererProxy); + assertEquals(Bean.class, refererProxy.getClass().getSuperclass()); + assertEquals(1, refererProxy.getClass().getInterfaces().length); + assertEquals(Factory.class, refererProxy.getClass().getInterfaces()[0]); + + assertEquals(100, refererProxy.getAttribute().intValue()); + assertEquals("element of 100", refererProxy.getElement()); + assertNotNull(refererProxy.getReference()); + + marshaller.marshal(refererProxy); + + String output = out.toString(); + + String expected + = "\n" + + "" + + "element of 100" + + "" + + "element of 999" + + "" + + ""; + + assertEquals(expected, output); + } +} Index: /home/ralf/Workspace/castor-2/src/bugs/xml/c1342/mapping.xml =================================================================== --- /home/ralf/Workspace/castor-2/src/bugs/xml/c1342/mapping.xml (Revision 0) +++ /home/ralf/Workspace/castor-2/src/bugs/xml/c1342/mapping.xml (Revision 0) @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + Index: /home/ralf/Workspace/castor-2/src/main/java/org/exolab/castor/xml/Marshaller.java =================================================================== --- /home/ralf/Workspace/castor-2/src/main/java/org/exolab/castor/xml/Marshaller.java (Revision 7075) +++ /home/ralf/Workspace/castor-2/src/main/java/org/exolab/castor/xml/Marshaller.java (Arbeitskopie) @@ -95,7 +95,6 @@ import java.util.List; import java.util.Stack; - /** * A Marshaller that serializes Java Object's to XML * @@ -281,10 +280,15 @@ /** * The validation flag - **/ + */ private boolean _validate = false; + /** Shell the objects to be marshalled be searched if they implement a proxy interface? */ + private boolean _proxySearch = false; + /** Full classname of the proxy interface to search for. */ + private String _proxyInterface = null; + /** * Creates a new Marshaller with the given DocumentHandler. * @@ -408,7 +412,10 @@ if ("false".equalsIgnoreCase(val) || "off".equalsIgnoreCase(val)) { _saveMapKeys = false; } - + + //-- proxy interface to search for if defined + _proxyInterface = _config.getProperty(Configuration.Property.ProxyInterface, null); + _proxySearch = (_proxyInterface != null) && !"".equals(_proxyInterface.trim()); } //-- initialize(); /** @@ -912,10 +919,20 @@ if (!isNil) { _class = object.getClass(); + + if (_proxySearch) { + boolean isProxy = false; + + Class[] interfaces = _class.getInterfaces(); + for (int i = 0; i < interfaces.length; i++) { + if (_proxyInterface.equals(interfaces[i].getName())) { isProxy = true; } + } + + if (isProxy) { _class = _class.getSuperclass(); } + } + } else { + _class = ((NilObject) object).getClassDescriptor().getJavaClass(); } - else { - _class = ((NilObject)object).getClassDescriptor().getJavaClass(); - } boolean byteArray = false; if (_class.isArray()) @@ -952,8 +969,7 @@ if (object instanceof NilObject) { classDesc = ((NilObject)object).getClassDescriptor(); - } - else if (_class == descriptor.getFieldType()) { + } else if (_class == descriptor.getFieldType()) { classDesc = (XMLClassDescriptor)descriptor.getClassDescriptor(); } Index: /home/ralf/Workspace/castor-2/src/main/java/org/exolab/castor/util/Configuration.java =================================================================== --- /home/ralf/Workspace/castor-2/src/main/java/org/exolab/castor/util/Configuration.java (Revision 7075) +++ /home/ralf/Workspace/castor-2/src/main/java/org/exolab/castor/util/Configuration.java (Arbeitskopie) @@ -298,6 +298,17 @@ */ public static final String LenientIdValidation = "org.exolab.castor.xml.lenient.id.validation"; + /** + * Property specifying whether or not to search for an proxy interface at marshalling. + * If property is not empty it the objects to be marshalled will be searched if they + * implement the given interface name. If the interface is implemented the marshaller + * will search for a descriptor of the superclass instead of the class itself. + *
+         * org.exolab.castor.xml.proxyInterface
+         * 
+ * @since 1.2.2 + */ + public static final String ProxyInterface = "org.exolab.castor.xml.proxyInterface"; } //-- class: Property Index: /home/ralf/Workspace/castor-2/src/main/resources/org/exolab/castor/castor.properties =================================================================== --- /home/ralf/Workspace/castor-2/src/main/resources/org/exolab/castor/castor.properties (Revision 7075) +++ /home/ralf/Workspace/castor-2/src/main/resources/org/exolab/castor/castor.properties (Arbeitskopie) @@ -106,6 +106,13 @@ # org.exolab.castor.debug=false +# Property specifying whether or not to search for an proxy interface at marshalling. +# If property is not empty it the objects to be marshalled will be searched if they +# implement the given interface name. If the interface is implemented the marshaller +# will search for a descriptor of the superclass instead of the class itself. +# +#org.exolab.castor.xml.proxyInterface=net.sf.cglib.proxy.Factory + # List of collection handlers for Java 1.1 and Java 1.2 run-times: # org.exolab.castor.mapping.collections=\