Printing a JAXB generated bean - java

I have a JAXB data class which is generated from wsimport and I'd like to print it to the console and/or log. Unfortunately a toString is not generated.
What's the easiest way to print the data object? It doesn't matter whether the output is the original XML or something else, as long as it's readable.
It looks like the class is a valid bean (properly named getters and setters) so anything that works with beans is probably fine too.

For printing to the console, try this:
jaxbContext.createMarshaller().marshal(jaxbObject, System.out);
To get it into a String, use a StringWriter:
StringWriter writer = new StringWriter();
jaxbContext.createMarshaller().marshal(jaxbObject, writer);
String xmlString = writer.toString();
To get the JAXBContext object you need to do the following:
JAXBContext jaxbContext = JAXBContext.newInstance(<WhateverClass>.class);
Where <WhateverClass> is the class literal for the type that jaxbObject is. You should also be able to do:
JAXBContext jaxbContext = JAXBContext.newInstance(jaxbObject.getClass());
Depending on where you are defining the context and your stylistic preference. JAXBContext is thread-safe so it is good to define one instance and share it. Marshaller and Unmarshaller make no such guarantees though. So they need to be created on demand.

Related

Java: Populating .xsd-generated class from .xml file

I have a class that was generated from an .xsd file, and I have an .xml file that contains data that adheres to the schema in the .xsd. Something like:
XML schema file: MyObject.xsd
Java class generated from schema: MyObject.java
XML that matches the schema: MyObject.xml
Is there an easy way for me to deserialize MyObject.xml into an instance of MyObject.java? I'm hoping for something easier than hand-walking through the DOM elements and setting all the properties on the object.
Basically, I'm looking for the functionality in java.beans.XMLDecoder, but since my .xml file was not created from the XMLEncoder, I do not believe that I can use the decoder.
First you need to create a JAXBContext instance using the static newInstance method. Then create an Unmarshaller instance using the createMarshaller method and call the appropriate unmarshal method on that instance:
InputStream is = new FileInputStream("MyObject.xml");
JAXBContext jc = JAXBContext.newInstance(MyObject.class);
Unmarshaller u = jc.createUnmarshaller();
MyObject o = (MyObject)u.unmarshal(is);

JAXB marshall ignore interfaces

I'm trying to marshall a class with an interface in it. I got an error saying "JAXB can't handle interfaces.". I've seen several solutions for handling the interfaces, but I think my case is slightly different, because I'm not going to use the data in that interface in the xml. So is there any way to ignore the interface or something like that?
Also, the class (Comment) is got from a library, I don't think I can change the annotation.
Comment newComment = event.getComment();
// Marshalling
JAXBContext context = JAXBContext.newInstance(newComment.getClass());// error occurs
Marshaller marshaller = context.createMarshaller();
StringWriter writer = new StringWriter();
marshaller.marshal(newComment, writer);

JAXB holding on to objects passed to Marshaller

JAXB works fine for marshalling and unmarshalling. Because it can be slow to create marshallers and unmarshallers, using pools for them (based on contextPath) seems a reasonable approach. However, it appears that Unmarshaller holds onto objects after it is done. If it was passed a very large document, then it may hold onto a lot of memory if that particular Unmarshaller isn't reused for a while. Is there a way to cause JAXB to release the objects it processed?
JAXBContext jaxBContext = JAXBContext.newInstance(contextPath, loader);
Unmarshaller unMarshaller = jaxBContext.createUnmarshaller();
...
responseObject = unmarshaller.unmarshal( new StreamSource( new StringReader( xml ) ) );
There are examples online of pooling approaches like this (e.g. one at apache: JAXBUtils.java). Most don't seem to do anything special when they put an Unmarshaller back in the pool.
Update: This appears to be a bug in JAXB: Post-Unmarshall Object Retention. The similar bug in Marshall was fixed earlier so it's in recent versions of JAXB. So now I'm wondering (a) if there's a workaround for this issue with Unmarshaller (b) which version of Java6 this fix is/will be included in.
One workaround that occurs to me is to pool the JAXBContext rather than the Un/Marshaller. Doing some quick timings, it seems that the time taken for creating a Un/Marshaller is negligible compared to the time taken to create a JAXBContext from a contextPath. And by holding only a reference to the JAXBContext in the pool, then the Unmarshaller should be freed up, which hopefully allows the GC to reclaim its memory along with that of the doc that the Unmarshaller was holding onto due to the jaxb bug.
Another possible workaround would seem to be to immediately reuse the UnMarshaller so that it will release the objects from the previous unmarshal. Perhaps pass it a valid but essentially empty XML doc, a string that just has the outermost tags needed. Unfortunately, initial results from this don't seem promising.
String xmlStr = "<ns0:SvcData xmlns:ns0=\"http://Company.com/Schemas/Svc/Base\"></ns0:SvcData>";
Object o = unMarshaller.unmarshal( new StreamSource( new StringReader( xmlStr ) ) );
http://java.net/jira/browse/JAXB-843
I faced with the same with marshaller. I reported the issue with a test program. If you try to marshal something stupid, you catch and consume the exception like in the attached file in the issue report, then your marshaller releases the previously used resources.
I think it would worth trying the same with unmarshallers :)

How to stream large Files using JAXB Marshaller?

The Problem I'm facing is how to marshall a large list of objects into a single XML File, so large I can not marshall the complete list in one step. I have a method that returns these objects in chunks, but then I marshall these using JAXB, the marshaller returns with an exception that these objects are no root elements. This is ok for the normal case there you want to marshall the complete document in one step, but it also happens if I set the JAXB_FRAGMENT Property to true.
This is the desired XML output:
<rootElem>
<startDescription></startDescription>
<repeatingElem></repeatingElem>
<repeatingElem></repeatingElem>...
</rootElem>
So I assume I need some kind of listener that dynamically loads the next chunk of repeatingElements to feed it to the marshaller before he would write the closing tag of the rootElement. But how to do that? Up until now I only used JAXB to marshall small files and the JAXB documentation does not give much hints for that use case.
I'm aware that this is an old question but I came across it while searching for duplicates of another similar question.
As #skaffman suggests, you want to Marshal with JAXB_FRAGMENT enabled and your objects wrapped in JAXBElement. You then repeatedly marshal each individual instance of the repeated element. Basically it sounds like you want something roughly like this:
public class StreamingMarshal<T>
{
private XMLStreamWriter xmlOut;
private Marshaller marshaller;
private final Class<T> type;
public StreamingMarshal(Class<T> type) throws JAXBException
{
this.type = type;
JAXBContext context = JAXBContext.newInstance(type);
this.marshaller = context.createMarshaller();
this.marshaller.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);
}
public void open(String filename) throws XMLStreamException, IOException
{
xmlOut = XMLOutputFactory.newFactory().createXMLStreamWriter(new FileOutputStream(filename));
xmlOut.writeStartDocument();
xmlOut.writeStartElement("rootElement");
}
public void write(T t) throws JAXBException
{
JAXBElement<T> element = new JAXBElement<T>(QName.valueOf(type.getSimpleName()), type, t);
marshaller.marshal(element, xmlOut);
}
public void close() throws XMLStreamException
{
xmlOut.writeEndDocument();
xmlOut.close();
}
}
As you've discovered, if a class does not have the #XmlRootElement annotation, then you can't pass an instance of that class to the marshaller. However, there is an easy way around this - wrap the object in a JAXBElement, and pass that to the marshaller instead.
Now JAXBElement is a rather clumsy beast, but what it does is contains the element name and namespace of the object that you want to marshal, information which would normally be contained in the #XmlRootElement annotation. As long as you have the name and namespace, you can construct a JAXBElement to wrap your POJO, and marshal that.
If your POJOs were generated by XJC, then it will also have generated an ObjectFactory class which contains factory methods for building JAXBElement wrappers for you, making things a bit easier.
You'll still have to use the JAXB_FRAGMENT property for the repeating inner elements, otherwise JAXB will generate stuff like the XML prolog each time, which you don't want.
I don't know much of JAXB, so I can't help. But if you don't mind, I have a suggestion.
Writing XML is a lot easier than reading it, so an solution for your problem might be to use a more "low level" approach. Just write your own marshaller using one of the available open source libraries for XML. I think you can easily do what you want using dom4j.

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