When using the ObjectFactory class generated by JAXB (from an XSD), I'd like to store it in a field or even constant, so I don't have to pass it around between private methods. As far as I can tell, the ObjectFactory does not have any state, at least for no schema I have used.
Are there cases, e.g. when using specific XSD constructs or JAXB properties, where the ObjectFactory is not stateless?
If there are, is it safe to use a static constant for storing the ObjectFactory or are there thread safety issues?
Related
Say I have a bean:
public class MyBean {
public String oneMississipi;
public int myBestFriend;
//Getters&Setters&Bears,Oh my.
}
And I am using com.fasterxml.Jackson DataBinding to transform instances of this pojo into json output... How do I customize the serialization of field names and can this be scoped to a global/class/field level?
e.g. I wish to dasherize my field names:
{
"one-mississipi": "two mississippi",
"my-best-friend": 42
}
I have already spent hours in Google and even trawling through the jackson code in order to find out where the field serialization occurs, but can't seem to see anywhere that it may delegate for custom field processing.
Does anyone have any ideas as to where this functionality lies if any? Much appreciated
Implement PropertyNamingStrategy and inside the resolving methods use AnnotatedMethod, AnnotatedField or AnnotatedParameter to get the declaring class. Then you can look for any custom annotation on that class and apply any custom naming depending on it.
The biggest problem with this approach is that it's not possible to get the actual concrete class being serialized or deserialized, it will always return the declaring class. So it won't be possible to override naming behavior in subtypes for the inherited members unless you bring them into the subtype.
Another solution would be using different mappers for classes that have different naming strategies. You can make it more or less transparent by creating a top-level "router" mapper that will decide which mapper instance to use (special care must be taken for configuration methods and other non ser/deser related methods). Assuming that you will have a finite number of the strategies this solution should be workable too.
The drawback of this solution is that you won't be able to mix different naming strategies during a single serialization / deserialization run.
I have a class that any I need to marshal to XML.
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class ClassToBeMarshalled {
public Interface object;
}
The Interface is implemented by a lot of concrete classes and most of them are vendor specific whose source code I don't have access to.
So my problem is:
If I try to marshal that class, JAX-B will complain that the current concrete implementation of Interface is not known in the context - In another words, the concrete class was not loaded into the context by calling JAXBContext.newInstance providing the current implementation.
The most common ways to sort out that problem are:
1) Use XMLSeeAlso - not a viable option as there are a lot of concrete classes
2) Annotate each class with #XmlRootElement - not a viable option as I don't have access to all the classes
Does anyone know a way to make JAX-B load the concrete class into its context as the need arises?
Thanks.
P.S.: I'm using JAX-B RI
You could mark your object as #XmlAnyElement(InterfaceHandler.class) where InterfaceHandler is a DomHandler capable of translating between a DOM representation and the actual implementing classes. That handler should probably store the class name when marshalling, and use that class name to create the instance when unmarshalling. It might either configure the instance manually, perhaps using some helper classes designed to work with beans, or it might use another jaxb context which includes that specifically named class and will handle that object with all its nested children.
Also have a look at the #XmlElementRef annotation. I fear that in order to make this work properly, you'd have to at least know all the implementing classes at compile time, but perhaps there is a way you can make this work for you as well, with less trouble than the generic solution outlined in the previous paragraph.
I'm using JAXB bindings to unmarshal directly to my domain layer objects, which are subclasses of the generated webservice types. This is a nice solution as I can override methods and provide write custom logic, etc. However, the XJC compiler is insisting on putting the #XmlSeeAlso({MySubclass.class}) annotations on all the generated classes, which is causing them to be tightly coupled to my domain objects. This is obviously undesirable and causing all kinds of reference issues between my projects that I won't get into here.
Is it possible to generate classes that don't have the #XmlSeeAlso annotation? The actual work of unmarshaling to the subclass seems to happen in the ObjectFactory class. Is it possible to omit the jaxb binding, and substitute a custom ObjectFactory for each application? This would allow me to have autogenerated webservice types in a shared util while each web project could unmarshal to different subclasses of these types.
<jaxb:bindings node="//xs:complexType[#name='AutogeneratedWebserviceType']">
<jaxb:class implClass="my.project.CustomSubclass" />
</jaxb:bindings>
This binding will create a method in the ObjectFactory that seems to do the actual work of unmarshaling to my subclass:
public AutogeneratedWebserviceType createAutogeneratedWebserviceType() {
return new CustomSubclass();
}
I want this behavior without the #XmlSeeAlso annotation by providing a customer ObjectFactory, if possible.
Did you try running XJC with the argument -target 2.0? I believe this will disable the generation of the #XmlSeeAlso annotation.
In a jax-ws web service I cannot directly access the JaxbContext object. JaxbContext uses the class ObjectFactory. I tried extending it (like in Jaxb Adding Behaviors). I put generated code in ObjectFactoryBase, then added
public class ObjectFactory extends ObjectFactoryBase {//.. overriden methods}
However IllegalAnnotationsException came up when publishing to weblogic, because it cannot find a certain #XmlElementDecl present in ObjectFactoryBase. When I move the method with this #XmlElementDecl to ObjectFactory it works.
No luck with adding #XmlSeeAlso({ ObjectFactoryBase.class }) either.
Edit: I now discovered that the generated ObjectFactory is not even used by the jaxws web service. So the above error message are not so relevant any more. Any idea why it is generated but not used?
Any ideas?
JAXB ObjectFactories are strange beasts. Your question has many facets, so I'll just answer with a bullet list:
JAXB1 relied on ObjectFactory to create instances of the bound classes, but with JAXB2 everything is a POJO, and the ObjectFactory becomes mostly unnecessary. It's still generated by XJC, partly for reasons of backwards compatibility.
The annotations on an ObjectFactory are complex and non-obvious, but since it's a generated class, this usually doesn't matter, and most people don't look at it anyway.
ObjectFactory is still useful on occasion because it provides factory methods for bound classes that need a JAXBElement wrapper, and it's much easier to use the provided factory methods than to do this by hand.
The JAXWS web service may choose not to use the ObjectFactory, because it's not strictly speaking necessary. However the JAXBContext may still load and parse it, depending on how the context was initialized.
I've never tried creating an ObjectFactory myself; if the model was XJC-generated then the generated ObjectFactory is usually enough, and if you have a hand-written JAXB model, the ObjectFactory is usually completely unnecessary anyway.
I generate Java classes from my XSD schema file using XJC command line tool. The ObjectFactory class generates incomplete content. It generates creation methods without JAXBElement<Type> createType decoration.
What may be the reason of this?
Regards
Dominik
Only some types in a JAXB2 XJC-generated binding need JAXBElement wrappers. Those types that have the #XMLRootElement annotation do not need the wrapper, and so the object factory does not generate one.
JAXB generates factory methods that create a JAXBElement from an object instance only if your XSD contains both a complexType definition and a separate element definition using that complexType WITH THE SAME NAME, for example:
<complexType name="my-type">
...
</complexType>
<element name="my-type" type="tns:my-type"/>
In this case, JAXB won't annotate the generated class with an #XmlRootElement annotation, but will provide the factory methods you need to create a JAXBElement from the object instance. That way, you can serialize instances of non-root-element types as root elements easily.
So, you should just add an "element"-declaration with the same name in addition to any complexType definition you intend to be used as a top-level element, and ObjectFactory will generate the expected factory methods.