1

For given structure of classes (skipped annotations and so on):

class A {
 public B getObjectB {}
}

class B {
 public String getHello { return " world"; }
}

I have no problems with generating correct XSD and XML output:

<A>
 <B>
  <hello>world</hello>
 </B>
</A>

The thing is, I need to break it a little: first of all, XSD should remain as is - full. But while marshalling of A, I need to get somtething like this:

<A>
 someStringForA
</A>

(so B is rendered as some calculated String). At the same time, while marshalling B (as a root), I still need to get "normal" output.

I tried with XmlAdapters, but using @XmlJavaTypeAdapter change the XSD too. Setting adapters through Marshaller.setAdapter(...) apparently (http://stackoverflow.com/questions/6110757/jaxb-xml-adapters-work-via-annotations-but-not-via-setadapter/6112149#6112149) will not work.

Some kind of solution would be, if there were possibility to "turn off" the @XmlJavaTypeAdapter (XSD is generated "manually" by JUnit, some switch or even hack is allowed)

Thanks for any help!

Tomasz
  • 988
  • 1
  • 9
  • 23

1 Answers1

1

Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB (JSR-222) expert group.

Alternate Mapping - oxm.xml

If you are using MOXy as your JAXB provider you could use an external mapping file to provide an alternate mapping for your domain model (see: http://blog.bdoughan.com/2010/12/extending-jaxb-representing-annotations.html).

<?xml version="1.0"?>
<xml-bindings
    xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
    package-name="forum13843624">
    <java-types>
        <java-type name="A">
            <java-attributes>
                <xml-value java-attribute="objectB"/>
            </java-attributes>
        </java-type>
        <java-type name="B">
            <java-attributes>
                <xml-value java-attribute="hello"/>
            </java-attributes>
        </java-type>
    </java-types>
</xml-bindings>

Java Model

A

import javax.xml.bind.annotation.*;

@XmlRootElement(name="A")
class A {

    private B b;

    @XmlElement(name="B")
    public B getObjectB() {
        return b;
    }
    public void setObjectB(B b) {
        this.b = b;
    }

}

B

import javax.xml.bind.annotation.XmlElement;

class B {

    @XmlElement
    public String getHello() {
        return " world";
    }

}

jaxb.properties

To specify MOXy as your JAXB provider you need to include a file named jaxb.properties in the same package as your domain model with the following entry (see: http://blog.bdoughan.com/2011/05/specifying-eclipselink-moxy-as-your.html).

javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory

Demo Code

import java.util.*;
import javax.xml.bind.*;
import org.eclipse.persistence.jaxb.JAXBContextProperties;

public class Demo {

    public static void main(String[] args) throws Exception {
        B b = new B();
        A a = new A();
        a.setObjectB(b);

        JAXBContext jc = JAXBContext.newInstance(A.class);
        marshal(jc, a);

        Map<String, Object> properties = new HashMap<String, Object>();
        properties.put(JAXBContextProperties.OXM_METADATA_SOURCE, "forum13843624/oxm.xml");
        JAXBContext jc2 = JAXBContext.newInstance(new Class[] {A.class}, properties);
        marshal(jc2, a);
    }

    private static void marshal(JAXBContext jc, A a) throws Exception {
        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(a, System.out);
    }

}

Output

Below is the output from running the demo code. Note how the same object graph is marshalled two different ways.

<?xml version="1.0" encoding="UTF-8"?>
<A>
   <B>
      <hello> world</hello>
   </B>
</A>
<?xml version="1.0" encoding="UTF-8"?>
<A> world</A>
bdoughan
  • 147,609
  • 23
  • 300
  • 400
  • Thank you Blaise for your excellent answer - I hope someone pays you for this effort ;) I saw your previous answers and posts, and was considering switching to MOXy, but was hoping it won't be necessary... I will check the consequences of that – Tomasz Dec 12 '12 at 20:41
  • @Tomasz - I'm not sure I have your use case 100% straight. Do you really want to marshal A to multiple XML representations as I have in my answer? – bdoughan Dec 12 '12 at 20:43
  • Yes. Or more exactly - I need to marshall some of its child elements (B) to some String (URL in fact). At the same time, while marshalling B as root, it shall not be turned into that String (URL) - it should then be "normal" XML output (unless there is some C nested, and configured to behave analog to B). Its all about the "Edge Side Includes", if you want to know the reasons ;) – Tomasz Dec 13 '12 at 07:45