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 :)
Related
Please shed some light on JAXBContext configutation.
Given:
customer library com.mycompany.user01234 with several
JAXB-annotated classes
all classes are simple POJOs located in the same package
classes are annotated by #XmlType
Customer marshals instance of com.mycompany.user01234.UserClass1.class to the server via web service endpoint. On the server side I do the following:
JAXBContext jbc = JAXBContext.newInstance("com.mycompany.user01234")
Unmarshaller um = jbc.createUnmarshaller();
JAXBElement<Object> element = um.unmarshal(source, Object.class);
Object customerInput = element.getValue();
And it works fine ONLY if I patch customer library with following package-info.java:
#XmlSchema(elementFormDefault = XmlNsForm.QUALIFIED)
package com.mycompany.user01234;
To my shame I havent found any clear explanation of what this #XmlNsForm annotation is and how it affects unmarshalling process. This is the first question.
The second question is whether it is possible (in the given layout) to put that QUALIFIED value into some properties or defaults for JAXBContext or use other non-declarative means allowing to get rid of package-info.java.
Many thanks in advance!
It corresponds exactly to the elementFormDefault attribute of an <xs:schema> element (i.e., the top-level element of an XML Schema document). What it does (with that constant) is state that elements from the namespace defined by the schema should be rendered with a qualifier (i.e., as <foo:bar> instead of <bar>); the exact way that the namespace is declared will also vary between the two styles. In terms of the XML infoset, the two styles are completely equivalent; if namespaces are declared correctly in the XML, JAXB should be equally happy (I believe it should only use the value when serializing).
You might want to try making your JAXBContext by passing in the class that you are expecting so that you are a little less reliant on discovery code (assuming it's a FooBar class that's really being produced):
JAXBContext jbc = JAXBContext.newInstance(FooBar.class);
FooBar customerInput = (FooBar) jbc.createUnmarshaller().unmarshal(source);
(The above code is abstracted from things that I do in my code's test suite that definitely already work.)
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.
It seems the standard approach for deserializing JAXB XML is to specify the package name when creating the context. Then, JAXB looks up the class based on the root element:
JAXBContext jc = JAXBContext.newInstance("com.foo");
Unmarshaller u = jc.createUnmarshaller();
Object o = u.unmarshal(new StringReader("<?xml version="1.0" encoding="UTF-8" standalone="yes"?><MyJaxb>..."));
I'm looking for a more flexible approach where I don't have to specify the package name and could still deserialize any object. This would be as simple as JAXB storing the package in the XML, but I can't seem to find out how to do this. I can write the code to do it myself but that would be unpleasant. It would like JAXB to do it, if possible. BTW, I am not using schemas, just Annotations and marshal/unmarshal. Any ideas?
Actually you can not deserialize "any" object with pure JAXB. You have to specify either packages (where ObjectFactory.class will be sought) or list of classes like JAXBContext.newInstance(Class1.class, Class2.class, Class3.class); That's how jaxb works, it's a part of agreement.
If your tasks are wider that that, e.g. building java classes from arbitrary xml data structure - it's also possible, but you have to be a bit more concrete - what do you mean under "more flexible approach".
You should be able to add more than one package when you get the instance of the jaxbcontext object. You can add as many packages as you want like below.
JAXBContext jc = JAXBContext.newInstance("com.foo.package1:com.foo.package2" );
however, I am not sure how you are gonna use it if you deserialize it into an Object instance?
Are you not gonna use what you have just deserialized?
Also Unmarshaller is not a thread safe class if your application is a multithreaded one.
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.
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.