How to marshall JAXB object to a different schema? - java

I unmarshall an XML that comes in a specific format e.g.
<root>
<a/>
<b/>
<c>
<x/>
</c>
<d/>
</root>
After playing around with the Java object, I want to send it to another service that uses a different schema, e.g.
<anotherRoot>
<a/>
<x/>
<something>
<d/>
</something>
</anotherRoot>
Can this be done "easily" w/ JAXB?

Using any JAXB (JSR-222) implementation you could use XSLT on a JAXBSource and the javax.xml.transform APIs to produce a secondary XML structure:
JAXBContext jc = JAXBContext.newInstance(Foo.class);
// Output XML conforming to first XML Schema
Marshaller marshaller = jc.createMarshaller();
marshaller.marshal(foo, System.out);
// Create Transformer on Style Sheet that converts XML to
// conform the second XML Schema
TransformerFactory tf = TransformerFactory.newInstance();
StreamSource xslt = new StreamSource(
"src/example/stylesheet.xsl");
Transformer transformer = tf.newTransformer(xslt);
// Source
JAXBSource source = new JAXBSource(jc, foo);
// Result
StreamResult result = new StreamResult(System.out);
// Transform
transformer.transform(source, result);
Full Example
http://blog.bdoughan.com/2012/11/using-jaxb-with-xslt-to-produce-html.html

You can create create a proxy for the other service and regard its beans as simple data transfer objects.
So when you wish to call the service, you manually fill the beans based on the values of your proper model objects (the one you play around with, the ones that contain business logic) and call the service using the beans.
If changes happen to the service's interface, you can recreate the proxy and the compiler will help you fix the transformation.

Related

Transforming Java object to JSON via XSLT

I already have
a working JAXB setup for Schema A
a working JAXB setup for Schema B
an XSLT transformation from instances of A to instances of B (and vice versa)
If I have an XML instance of type A, I can use XSLT and Jettsion to produce a reasonable JSON representation of B. But what I really want to do is take a Java object of type A, a JAXB marshaller, my existing A->B XSLT, and a Jettsion XMLStreamWriter to produce JSON of type B, without having to produce an instance of B (XML or Java) in between.
Java Object A --> JAXB Marshaller --> ? --> XSLT A to B transfrom --> JSON B
I have an idea that I should be able to this by marshalling to a SAXResult that in turn act as an XMLReader that can feed the XSLT translation. I need a kind of ContentHandlerAdapter that can coordinate the marshalling with the transformation.
But here my head starts spinning.
Has anybody seen or written a setup like this, and hopefully point me to an example?
You can wrap the object and an instance of Marshaller (or JAXBContext) in JAXBSource and pass that to the Transformer.
http://blog.bdoughan.com/2012/11/using-jaxb-with-xslt-to-produce-html.html
That is the purpose of the trax TransformerHandler interface.
TransformerFactory tf = TransformerFactory.newInstance();
// or just use new net.sf.saxon.TransformerFactoryImpl() for Saxon (XSLT 2.0)
Source xslt = new StreamSource(....);
TransformerHandler handler =
((SAXTransformerFactory)tf).newTransformerHandler(xslt);
Result result = new StAXResult(theJettisonStreamWriter);
handler.setResult(result);
SAXResult marshallerResult = new SAXResult(handler);
// marshal to the marshallerResult as normal

Jaxb : Append field of Request XML without modfying JAXB java class

I am using JAXB 2.0 for the Application Deveopment which is using RestFul Webservices .
Now there is a modification in the request , that is i will be getting another filed/variable in the request XML .
<Root Id="567" att="758" />
Modified Request will be
<Root Id="567" att="758" anotherfiledadded ="kiran" />
My question is , is it possible to automatically append that field (anotherfiledadded)in the UserData class (Without modifying the UserData ??)
The below is my UserData class
#XmlRootElement(name = "Root")
#XmlAccessorType(XmlAccessType.FIELD)
public class UserData {
#XmlAttribute
private String Id;
#XmlAttribute
private String att;
// getters and setters
You can try adding the field at runtime with javassist. But... It looks like you would also require to add the Annotation #XmlAttribute and I don't know if javassist allows you to add annotations... Anyways give it a try.
See: Javassist Add
You could use XSLT to apply an attribute into your XML document. All of the classes below are available in the JDK/JRE since Java SE 6.
JAXBContext jc = JAXBContext.newInstance(UserData.class);
JAXBSource source = new JAXBSource(jc, myUserData);
StreamResult result = new StreamResult(System.out);
TransformerFactory tf = TransformerFactory.newInstance();
StreamSource xslt = new StreamSource("addMyAttribute.xslt");
Transformer t = tf.newTransformer(xslt);
t.transform(source, result);
If you are implementing your RESTful service using JAX-RS you could plug-in this logic via a MessageBodyWriter:

JAXB Fragmented Marshalling

I'm having some trouble successfully marshalling using the Marshaller.JAXB_FRAGMENT property. Here's a simple version of the XML i'm trying to output.
<Import>
<WorkSets>
<WorkSet>
<Work>
<Work>
...
..
...
</WorkSet>
<WorkSet>
<Work>
<Work>
...
</WorkSet>
<WorkSets>
<Import>
The <Import> and <WorkSets> elements are essentially just container elements that enclose a large number of <WorkSet> & <Work> elements. I'm currently trying to marshall at the <WorkSet>.
Is it possible to initially marshal the <Import> and <WorkSets> elements and then from then on marshal at the <WorkSet> element and have the output be enclosed in the <Import><WorkSets> tags?
When I'm marshaling at the WorkSet level it attaches the xmlns='http://namespace.com' attribute to the WorkSet tag, is there a way to marshal without the namespace attribute being attached to Workset?
Basically, it sounds like rather than constructing a full object tree with the container objects, you want to be able to stream a collection of WorkSet instances to marshal using JAXB.
The approach I would take is to use an XMLStreamWriter and marshal the WorkSet objects by wrapping them in a JAXBElement. I don't have tested sample code close at hand, so here's the rough code snippet that should put you on the write track:
FileOutputStream fos = new FileOutputStream("foo.xml");
XMLStreamWriter writer = XMLOutputFactory.newFactory().createXMLStreamWriter(fos);
writer.writeStartDocument();
writer.writeStartElement("Import");
writer.writeStartElement("WorkSets");
JAXBContext context = JAXBContext.newInstance(WorkSet.class);
Marshaller m = context.createMarshaller();
m.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);
for (WorkSet instance : instances)
{
JAXBElement<WorkSet> element = new JAXBElement<WorkSet>(QName.valueOf("WorkSet"), WorkSet.class, instance);
m.marshal(element, writer);
}
writer.writeEndDocument(); // this will close any open tags
writer.close();
Note: The above is completely untested and may be messing something up in the wrapping part to write each instance of WorkSet. You need to wrap the WorkSet instances because they will not be annotated with #XmlRootElement and JAXB will otherwise refuse to marshal the objects.

Java JAXB XJC code generation form XSD schema problem

I have my own domain model and corresponding XSD schema for it. It consists of data types and messages that are exchanged in my application. I use XJC tool from Java JRE 1.5 for generation of Java classes for the given XSD schema. The generated classes do not contain neither the serialization/deserialization method nor the validation code. How can I achieve this using JAXB?
Regards
Are you using JAXB 1.x or 2.x?
If 2.x then validation is built in. See this article.
Do you mean that you just want the code to marshall the Bean to XML and unmarshall the XML to a Bean?
There are many articles that show this. Here's an example of marshalling a bean into xml:
JAXBContext jaxb = JAXBContext.newInstance(MyBean.class);
Marshaller marshaller = jaxb.createMarshaller();
java.io.StringWriter sw = new StringWriter();
marshaller.marshal(myBean, sw);
System.out.println(sw.toString());

JAXB to unmarshall <string>foobar</string>

Greetings! I have a server returning XML content to my client that looks like this:
<string xmlns="...">foobar</string>
I'm new to JAXB and have gotten a lot of stuff working, except this. I thought it would be pretty easy to marshal and unmarshal this to and from a String. It took a while, but I finally figured out how to marshal this as
public static String ToXML(String s) throws Exception
{
JAXBContext context = JAXBContext.newInstance(String.class);
Marshaller marshaller = context.createMarshaller();
StringWriter sw = new StringWriter();
marshaller.marshal(new JAXBElement(new QName("", "String"), String.class, s), sw);
return sw.toString();
}
So my question is, how to I unmarshal this? It cannot be annotated as a root element. I cannot use java.lang as the package to create a new instance of a JAXBContext (I get an ObjectFactory missing exception).
Any wisdom to impart? This can't be that hard, right?
You need to write an object model that conforms to your XML structure, and tell JAXB to unmarshal on to that. Your example may look simple, but it's not what JAXB is for.
Try something like this:
#XmlRootElement(name="string", namespace="blah")
public class MyString {
#XmlValue
String value;
}
JAXBContext context = JAXBContext.newInstance(MyString.class);
MyString myString = (MyString) context.createUnmarshaller().unmarshal(...);
This will unmarshal the XML <string xmlns="blah">foobar</string>. Change the namespace accordingly. If you have many namespaces, then JAXB isn't really the tool for you.
I was surprised by this, but the following seems to work:
final String xmlString = "<string>value</string>";
final StringReader xmlReader = new StringReader(xmlString);
final StreamSource xmlSource = new StreamSource(xmlReader);
final JAXBContext jaxbContext = JAXBContext.newInstance(String.class);
final Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
final String stringValue = unmarshaller.unmarshal(xmlSource, String.class).getValue();
Is that what you were looking for?
When you're using JAXB, you need to build the code around an XML schema. That is, if you have a file, say foo.xsd, you need to run it through the xjc compiler (in JDK 6 by default, otherwise you can download JAXB 2 and use that). That will read through the schema and generate the Java bean and associated ObjectFactory classes with the elements in the schema. The Java bean classes will look like regular POJOs with annotations. The ObjectFactory classes are needed by the JAXB implementation to convert the XML into the corresponding Java bean. This explains your ObjectFactory missing exception.
So it's not hard, but there is some leg work involved. We use it for one of our production applications and it's great. I see myself using it more now that it's part of the JDK.

Categories