Do you always need an ObjectFactory class when using JAXB? - java

Do you always need an ObjectFactory class when using JAXB?
Without it I get this exception:
javax.xml.bind.JAXBException:
"com.a.b.c"
doesnt contain ObjectFactory.class or
jaxb.index
I gather the ObjectFactory can be overkill. But given this exception I'm guessing you need it.. but not sure why?

You get that exception when you use the JAXBContext.newInstance(String) factory method, where you pass in the package name as the argument. This does require the ObjectFactory to be there, otherwise, JAXB doesn't know which classes to process.
If you don't have an ObjectFactory, you need to JAXBContext.newInstance(Class...) instead, passing in the explicit list of annotated classes to add to the context.

Instead of the ObjectFactory you can include a jaxb.index file which is a text file that contains a new line seperated list of Java classes.
For an example of using a jaxb.index file see:
http://bdoughan.blogspot.com/2010/08/using-xmlanyelement-to-build-generic.html

I was using Spring and I just had to change
Jaxb2Marshaller mlr = new Jaxb2Marshaller();
mlr.setContextPaths("","");
to
Jaxb2Marshaller mlr = new Jaxb2Marshaller();
mlr.setPackagesToScan("","");

Related

JAXB is confused about root elements?

I'm trying to marshal a file using the Visio XML Schema, which consists of 3 schema files and produces three packages when java source is generated with XJC:
com.microsoft.schemas.visio._2003.core
com.microsoft.schemas.visio._2006.extension
com.microsoft.schemas.office.visio._2010.extension
The root element is VisioDocument, and all of the classes I'm using are in the 2003 package.
Here is my approach to marshalling my XML file:
VisioDocumentType visioDoc = new VisioDocumentType();
... manipulated here ...
JAXBContext jc = JAXBContext.newInstance("com.microsoft.schemas.visio._2003.core");
Marshaller m = jc.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
m.marshal(new JAXBElement<VisioDocumentType>(new QName("uri","local"), VisioDocumentType.class, visioDoc), bw);
When executed, I receive this error:
javax.xml.bind.MarshalException
- with linked exception:
[com.sun.istack.internal.SAXException2: unable to marshal type "com.microsoft.schemas.visio._2003.core.PagePropsType" as an element because it is missing an #XmlRootElement annotation]
I am using PagePropsType, but it is not a root element. Why does JAXB think it is?
The problem resides in the ... manipulated here ... part of your code.
Based on the assumption that you do the following (or something similar).
// you create a page prop
PagePropsType pageProps = ...
// then you feed it to a shape sheet
ShapeSheetType shapeSheet = ...
shapeSheet.getTextOrXFormOrLine().add(pageProps);
(ShapeSheetType is a superclass for StyleSheetType, et cetera.)
If this's the case, then your problem lies in adding the pageProps to the list directly.
If you take a look at the getTextOrXFormOrLine() method's documentation it lists what kind of types the list can hold. Every type is wrapped in a JAXBElement<...> so you have to wrap pageProps before adding it to the list.
You should do it like this:
ObjectFactory objectFactory = new ObjectFactory();
JAXBElement<PagePropsType> pagePropsElement = objectFactory.createShapeSheetTypePageProps(pageProps);
(Note that I've used XJC 2.2.4 to compile the schemas; for me every class' name is suffixed with Type. Maybe this is why I ended up with VisioDocumentType instead of VisioDocument like you, but it shouldn't matter.)
If you check your generated code, you will find a ObjectFactory class in there. This class should have a method that returns a VisioDocument wrapped in a JAXBElement, and that it the object that you want to pass to the marshaller.
Same applicable to all objects you set inside VisioDocument - don't create them with 'new' but use ObjectFactory.

JAXBContext and #XmlNsForm annotation

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.)

Printing a JAXB generated bean

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.

Can JAXB store the class name in the XML so that the the deserialize code doesn't need knowledge of the class?

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.

Generate Spring bean definition from a Java object

Let's suggest that I have a bean defined in Spring:
<bean id="neatBean" class="com..." abstract="true">...</bean>
Then we have many clients, each of which have slightly different configuration for their 'neatBean'. The old way we would do it was to have a new file for each client (e.g., clientX_NeatFeature.xml) that contained a bunch of beans for this client (these are hand-edited and part of the code base):
<bean id="clientXNeatBean" parent="neatBean">
<property id="whatever" value="something"/>
</bean>
Now, I want to have a UI where we can edit and redefine a client's neatBean on the fly.
My question is: given a neatBean, and a UI that can 'override' properties of this bean, what would be a straightforward way to serialize this to an XML file as we do [manually] today?
For example, if the user set property whatever to be "17" for client Y, I'd want to generate:
<bean id="clientYNeatBean" parent="neatBean">
<property id="whatever" value="17"/>
</bean>
Note that moving this configuration to a different format (e.g., database, other-schema'd-xml) is an option, but not really an answer to the question at hand.
You can download the Spring-beans 2.5 xsd from here and run xjc on it to generate the Java classes with JAXB bindings. Then you can create the Spring-beans object hierarchy on runtime (and manipulate it as you wish) and then serialize it to an XML string using the JAXB Marshaller as shown in Pablojim's answer.
I'd use Jax-b to do this. You'de create a bean object with a list of property objects inside.
#XmlRootElement(name = "bean")
#XmlAccessorType(XmlAccessType.FIELD)
public class Bean {
#XmlAttribute
private String id;
#XmlAttribute
private String parent;
#XmlElement(name="property")
private List<BeanProperty> properties
Then You'd need to also add annotations to BeanProperty. Then when you have a populated object simply marshal it to xml using jaxb:
Marshaller m = jc.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
m.marshal( myBean, System.out );
For full code examples see: http://java.sun.com/webservices/docs/2.0/tutorial/doc/JAXBUsing.html
Alternatively you could use Groovy - you can drop it in place and creating this xml would be very simple... : http://www.ibm.com/developerworks/java/library/j-pg05199/index.html
If you want a simple to implement, no work solution, you can look at the IDE support provided in IntelliJ and Eclipse (The Spring Tool Suite).
They parse all the bean files (you can configure which set) and inspect the java code so it knows which classes there are, which properties are in those classes. Everywhere you can use Ctrl-Space to help with the options, etc...
I imagine you could setup 'projects' w/o Java code and only the spring config files in order to reduce the learning curve of front line personnel who must make these changes.
What you need is obviously a factory for your neatBeans.
In Spring, instead of declaring a bean, you can declare a FactoryBean whose role is to actually create and configure your final bean.
The NeatBeanFactoryBean could read a property file (or xml configuration) to determine how to configure the produced neatBeans, depending on some runtime parameter (the current clientID for example) or compile-time parameter (environment variable).
To add to the other two questions, I believe Spring already has a working model for bean definitions (see org.springframework.beans.factory.config.BeanDefinition); you could base your work on that.
I'd suggest using
<context:property-placeholder location="classpath*:clientX.properties"/>
and then in your bean def:
<bean id="${clientYNeatBeanId}" parent="neatBean">
<property id="whatever" value="${whateverValue}"/>
</bean>
Then for each client you can have a clientX.properties containing
whateverValue=17
whateverAnotherValue=SomeText
.properties files are easier to edit both manually, and programaticalyl via java.util.Properties store(..) / save(..) methods

Categories