2

Using Eclipselink/MOXy 2.3 i have following usecase in marshalling to XML:

abstract class MyAbstract {
}

class MyImpl extends MyAbstract {
}

class A {

    private MyAbstract myAbstract;

    // MyImpl is behind this
    public MyAbstract getMyAbstract() {
        return myAbstract;
    }

}

I have following mapping defined in oxm.xml:

<java-type name="foo.MyAbstract" xml-accessor-type="NONE">
    <xml-see-also>
        foo.MyImpl
    </xml-see-also>
</java-type>

<java-type name="foo.MyImpl">
    <xml-root-element name="MyImpl" />
</java-type>

<java-type name="bar.A" xml-accessor-type="NONE">
    <xml-root-element name="A" />
    <java-attributes>
        <xml-element java-attribute="myAbstract" type="foo.MyAbstract" />
    </java-attributes>
</java-type>

Now this results in:

<A>
    <myAbstract xsi:type="myImpl">
        <!-- Mapped members of MyImpl + MyAbstract -->
    </myAbstract>
</A>

Since i didnt want the property-name in the exported xml I changed:

<java-type name="bar.A" xml-accessor-type="NONE">
    <xml-root-element name="A" />
    <java-attributes>
        <xml-element java-attribute="myAbstract" type="foo.MyAbstract" xml-path="."/>
    </java-attributes>
</java-type>

which resulted in:

<A>
    <!-- Members of MyImpl + MyAbstract marshalled without any wrapping element-->
</A>

What i want is:

 <A>
    <MyImpl>
        <!-- Members of MyImpl + MyAbstract -->
    </MyImpl>
 </A>

The question is: how do i achieve this? MOXy is just ignoring my XmlRootElement on MyImpl...

EDIT:

Trying what Blaise suggested gives me following exception:

Exception [EclipseLink-60] (Eclipse Persistence Services - 2.3.2.v20111125-r10461):   
org.eclipse.persistence.exceptions.DescriptorException
The method [] or [getMyAbstract] is not defined in the object [bar.A].

Now this needs further information which i had left out before because i thought it was not relevant:

Class A is an interface which defines: public X getMyAbstract(); MyAbstract implements X (this is why i added the type-attribute in the mapping for interface A).

So, using xml-element-ref MOXy does not "see" the getter anymore, using xml-element it does.

quaylar
  • 2,617
  • 1
  • 17
  • 31
  • Class A is an interface? What is the concrete implementation of A that you are mapping to XML? – bdoughan Jan 16 '12 at 13:18
  • @BlaiseDoughan: I have no mapping for the concrete class - just the one for the interface bar.A. Since i am passing in just the interface, i figured it would be sufficient to just have a mapping for the interface? I followed the first example in http://blog.bdoughan.com/2011/05/jaxb-and-interface-fronted-models.html. – quaylar Jan 16 '12 at 13:33
  • In that example assuming the interface `A` corresponds to the `Customer` interface in my example, you will need to still bootstrap and map the JAXBContext on the impl class, `CustomerImpl` in my example. – bdoughan Jan 16 '12 at 13:46
  • @BlaiseDoughan - Is it sufficient to add an entry to oxm.xml for my Impl class and bootstrap JAXBContext with a Map containing package-name -> oxm.xml entries? This is how i am bootstrapping it now - i am just missing an entry for the Impl class. And what should this entry look like? I already mapped everything for the interface..? – quaylar Jan 16 '12 at 14:02
  • Just replace the mapping for the interface with the mapping for the impl class. – bdoughan Jan 16 '12 at 14:04
  • @BlaiseDoughan - dont i still need a mapping for the interface as well containing an xml-see-also tag? How would MOXy otherwise know how to marshal the Impl class if i pass the interface to the marshal method? – quaylar Jan 16 '12 at 14:09
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/6758/discussion-between-quaylar-and-blaise-doughan) – quaylar Jan 16 '12 at 14:10
  • @BlaiseDoughan - is obviously the right way to go, i discovered other problems which now led me to directly marshal MyAbstract ("getting" it and marshal() it), instead of marshalling Class A. Nevertheless your solution would have worked and will come in handy next time i need it.. – quaylar Jan 16 '12 at 15:27
  • 1
    I opened and fixed the following bug based on our "chat": http://bugs.eclipse.org/368746. You can try out the fix by downloading a 2.3.3 nightly build from the following location: http://www.eclipse.org/eclipselink/downloads/nightly.php – bdoughan Jan 16 '12 at 20:14

1 Answers1

2

The mapping that you are looking for is @XmlElementRef. This corresponds to the concept of substitution groups in XML schema.

bar/oxm.xml

Below is the external mapping document for the bar package. Note how the myAbstract property is mapped with xml-element-ref which is the XML representation of @XmlElementRef

<?xml version="1.0" encoding="UTF-8"?>
<xml-bindings
    xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
    package-name="bar">
    <java-types>
        <java-type name="A" xml-accessor-type="NONE">
            <xml-root-element name="A" />
            <java-attributes>
                <xml-element-ref java-attribute="myAbstract"/>
            </java-attributes>
        </java-type>
    </java-types>
</xml-bindings>

foo/oxm.xml

Below is the external metadata file for the foo package:

<?xml version="1.0" encoding="UTF-8"?>
<xml-bindings
    xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
    package-name="foo">
    <java-types>
        <java-type name="MyAbstract" xml-accessor-type="NONE">
            <xml-see-also>
                foo.MyImpl
            </xml-see-also>
        </java-type>
        <java-type name="MyImpl">
            <xml-root-element name="MyImpl" />
        </java-type>
    </java-types>
</xml-bindings>

Demo

Below is demo code for this example:

package forum8853855;

import java.util.*;
import javax.xml.bind.*;    
import org.eclipse.persistence.jaxb.JAXBContextFactory;
import bar.A;
import foo.MyImpl;

public class Demo {

    public static void main(String[] args) throws Exception {
        List<String> oxm = new ArrayList<String>(2);
        oxm.add("foo/oxm.xml");
        oxm.add("bar/oxm.xml");

        Map<String, Object> properties = new HashMap<String, Object>(1);
        properties.put(JAXBContextFactory.ECLIPSELINK_OXM_XML_KEY, oxm);

        JAXBContext jc = JAXBContext.newInstance(new Class[] {A.class}, properties);
        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

        A a = new A();
        a.setMyAbstract(new MyImpl());
        marshaller.marshal(a, System.out);
    }

}

Output

<?xml version="1.0" encoding="UTF-8"?>
<A>
   <MyImpl/>
</A>

For More Information

bdoughan
  • 147,609
  • 23
  • 300
  • 400
  • 1
    Thanks for supporting MOXy tag ;) – dma_k Jan 14 '12 at 00:06
  • Thanks Blaise for the tip, i had actually already tried this before i posted (acc. to your blog-post on this topic) but an exception occurred during marshalling. I will edit my post above with some additional information. – quaylar Jan 16 '12 at 12:04
  • @quaylar - In your update can you include the exception you are seeing? – bdoughan Jan 16 '12 at 12:06