0

I am totally a newbie to to JAXB architecture. But here is what i am trying to do do and where is am stuck in a nutshell.

I am creating a web application where the client will first register his xsd and then subsequently send his xml/json data as per the xsd.

For the registration of the xsd, i am using XJC (not as a maven plugin, but instead from java code itself :

 SchemaCompiler sc = XJC.createSchemaCompiler();
    File schemaFile = new File(schemaPath);
    InputSource is = new InputSource(new FileInputStream(schemaFile));
    is.setSystemId(schemaFile.getAbsolutePath());
    sc.parseSchema(is);
    S2JJAXBModel model = sc.bind();
    JCodeModel jCodeModel = model.generateCode(null, null);
    jCodeModel.build(new File(outputDirectory));

By XSD looks like:

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">

    <xsd:element name="Metadata" type="Metadata" />

    <xsd:complexType name="Metadata">
        <xsd:sequence>

            <xsd:element name="MicroscopeStagePosition"
                type="MicroscopeStagePosition" maxOccurs="1" minOccurs="1">
            </xsd:element>

        </xsd:sequence>
    </xsd:complexType>


    <xsd:complexType name="MicroscopeStagePosition">
        <xsd:sequence>
            <xsd:element name="Start" type="xsd:string"/>
            <xsd:element name="End" type="xsd:string"/>
        </xsd:sequence>
   </xsd:complexType> 
   </xsd:schema>

I am creating the JAXB annoted POJO classes from the above and the 2 classes created are :

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "Metadata", propOrder = {
    "microscopeStagePosition"
})
public class Metadata {

    @XmlElement(name = "MicroscopeStagePosition", required = true)
    protected MicroscopeStagePosition microscopeStagePosition;

    public MicroscopeStagePosition getMicroscopeStagePosition() {
        return microscopeStagePosition;
    }
    public void setMicroscopeStagePosition(MicroscopeStagePosition value) {
        this.microscopeStagePosition = value;
    }

}

And

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "MicroscopeStagePosition", propOrder = {
    "start",
    "end"
})
public class MicroscopeStagePosition {

    @XmlElement(name = "Start", required = true)
    protected String start;
    @XmlElement(name = "End", required = true)
    protected String end;

    public String getStart() {
        return start;
    }

    public void setStart(String value) {
        this.start = value;
    }

    public String getEnd() {
        return end;
    }

    public void setEnd(String value) {
        this.end = value;
    }

}

Now my idea to have a generic annotated class that will wrapper around this above classes that will be created in real time (this class is created in real and hence can have anything that needs to be).

The problem is that i do not which xsd will come and hence the rootelement is not going to help. So i thought creating a wrapper around the created JAXB class and then only deal with this one wrapper class in all API.

i have created the below class in real time :

public class MyModel {
@XmlElement(required = true)
protected Metadata Metadata;
@XmlElement(required = true)
protected MicroscopeStagePosition MicroscopeStagePosition;
}

Is it possible to Unmarshell a incoming XML based on this wrapper class . Note the incoming XML cannot be forced to have the root element of MyModel in it. So i try to create root JAXBElement and then assign it to the wrapper class:

  MyModel je = new MyModel();

JAXBContext jaxbContext = JAXBContextFactory.createContext(new Class[] {MyModel.class}, null);

         Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();

         InputStream is = new ByteArrayInputStream(sIncomingMetadataXML.getBytes());

        JAXBElement<MyModel> root = jaxbUnmarshaller.unmarshal(new StreamSource(
                is), MyModel.class);
        je = root.getValue();

if i annotate MyModel with @XmlRootElement @XmlAccessorType(XmlAccessType.FIELD) and return je from my api its a null child object xml :

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<MyModel/>

and if not there is an error :

A message body writer for Java class aand MIME media type application/xml was not found.

So can i create a wrapper class like above and if so how?, or have i missed totally something here

anil keshav
  • 479
  • 1
  • 5
  • 18
  • Note the incoming XML cannot be forced to have the root element of MyModel in it. Why not?, seems the most simple way.... Store the incomming xml (add what you need) and then unmarshal, this you can do in runtime (without saving to file).... – Petter Friberg Jan 05 '16 at 20:26
  • Hmm, well thought it would be clean code , but can you elloborate how do I add an parent tag to an incoming XML without saving to file ? – anil keshav Jan 05 '16 at 21:04
  • I have posted an answer, I do this often since when I interact with different service (msxml ecc ) from java I need to handle different BOM headers ecc. Maybe it take a little bit more memory, but you have much more control of the incoming data... – Petter Friberg Jan 05 '16 at 21:19
  • The other solution is to override the unmarshal behavior, but this I will leave to you.... – Petter Friberg Jan 05 '16 at 21:24

1 Answers1

0

Not considering "Note the incoming XML cannot be forced to have the root element of MyModel in it" as user approved in comment.

Instead of passing stream directly to Jaxb you read into a StringBuffer, This I do often to handle different UTF header's, log as I like ecc.

In your case to add the desperately needed tag.

  1. Read the stream into a StringBuffer sb (see as example Read/convert an InputStream to a String)

  2. Insert the tags as need in StringBuffer

  3. Unmarshaller the StringBuffer

    StringReader reader = new StringReader(sb.toString());
    JAXBElement<MyModel> root = getUnmarshaller().unmarshal(reader)
    
Community
  • 1
  • 1
Petter Friberg
  • 21,252
  • 9
  • 60
  • 109