JAXB: #XmlTransient on third-party or external super class - java

I need some help regarding the following issue with JAXB 2.1.
Sample: I've created a SpecialPerson class that extends a abstract class Person.
Now I want to transform my object structure into a XML schema using JAXB. Thereby I don't want the Person XML type to appear in my XML schema to keep the schema simple. Instead I want the fields of the Person class to appear in the SpecialPerson XML type.
Normally I would add the annotation #XmlTransient on class level into the Person code.
The problem is that Person is a third-party class and I have no possibility to add #XmlTransient here. How can I tell JAXB that it should ignore the Person class without annotating the class. Is it possible to configure this externally somehow?
Have you had the same problem before? Any ideas what the best solution for this problem would be?

OK, this was a pain in the you-know-what. Finally, after sifting through many a blog postings, here's what I did,
added a package-info.java class in the 'third-party class' package like this,
#javax.xml.bind.annotation.XmlAccessorType(javax.xml.bind.annotation.XmlAccessType.NONE)
package third-party-package;
In my case, it was just one package so it was easy. Obviously, you will have to do this for for every separate package structure. I haven't tried doing it at a master package level.

You can provide mappings for third-party classes using Annox.

The EclipseLink JAXB (MOXy) implementation offers a means of representing the metadata as XML that you could use:
http://wiki.eclipse.org/EclipseLink/Examples/MOXy/EclipseLink-OXM.XML
You can specify some of the metadata using annotations, and the rest as XML. Below is what your document would look like:
<xml-bindings
xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm">
<java-types>
<java-type name="Person" xml-transient="true"/>
</java-types>
</xml-bindings>

You can annotate your SuperPerson class with #XmlTransient, that will instruct JaxB not to automatically marshal all properties. And then annotate each getter (or field) you want to serialize with the relevant annotation.
This approach is not very elegant, but it should work

I posted another solution with complete code here
JAXB External Custom Binding XJC Issue - Parsing results in empty node
in case you are interested.

Related

Using custom ObjectFactory with JAXB: is there an established "go to" pattern?

I understand that the ObjectFactory is often automatically generated when working with JAXB as one might define schema and XML first. However, this is not the way I can approach the project.
I have existing code which needs to be annotated and extended to use JAXB to then use it in conjunction with a REST service. I have only a handful of classes and annotated them already. As far as I understood the documentation (I am new to JAXB), I need an implementation of ObjectFactory either by package for automatic invocation on package level, or a multitude of implementations when they are referred to directly rather than referred to by package context.
I am a bit unsure what the best approach would be. If I were to use one implementation per package then the manager would be rather abstract, instantiating many classes. However, I am not sure this is the "right" way to do it. I would personally opt to separate the concerns for instantiation into separate instances of the ObjectFactory, i.e., have one factory per class. Hence, I would implement something similar to the Data Access Object pattern.
My engineering background tells me that separation of concerns and opting for extension over modification would be a better choice. Hence, my intuition tells me that the monolithic ObjectFactory is only used when produced as a result of the approach starting from XML rather than code. Yet I don't have enough experience to make an informed choice.
I would like to ask you not only for your experience with the technology and recommendation (which would be to opinion based) but also whether this approach will introduce any risks that I am missing as well as technical limitations regarding JAXB that I might run into if I pursue my course of action. Thank you!
Creating a JAXBContext on a Package Name
When you create a JAXBContext on a package name:
JAXBContext jc = JAXBContext.newInstance("com.example.foo");
The JAXB implementation doesn't do package scanning, so it needs to find something in that package from which it can derive the rest of the model. This can either be:
An ObjectFactory class with create methods that reference the domain model. Bootstrapping of this is best when your model is generated from an XML Schema
A jaxb.index file, which is just a carriage return separated list of short class names (not package qualified) of the classes you want to bootstrap the JAXBContext on. This does not need to be the whole list as JAXB will pull in referenced classes. It is best to use this approach when you start from Java classe.
What ObjectFactory is Used For
As far as metadata is concerned the ObjectFactory has:
create methods from the signature of which the domain model can be determined (if you bootstrapped on the ObjectFactory alone.
#XmlElementDecl annotations. An #XmlElementDecl annotation is like an #XmlRootElement annotation but used in the cased for top-level elements that have a named type (see: http://blog.bdoughan.com/2012/07/jaxb-and-root-elements.html).
What ObjectFactory is Not Used For
The ObjectFactory is not used during the umarshal operation to create instances of the domain classes. For more information see the question linked below:
Why is the ObjectFactory not used during unmarshalling?
Creating a JAXBContext in a JAX-RS Environment
You mentioned you are doing REST. If you are using a JAX-RS implementation for this (such as Jersey) then I would suggest using a ContextResolver to create your JAXBContext. Below is an example from my blog. In that example an extension in the MOXy JAXB impl is used to provide the metadata, but you can create that JAXBContext anyway you want to.
http://blog.bdoughan.com/2011/04/moxys-xml-metadata-in-jax-rs-service.html

How to prevent JAXB from writing unused namespaces during marshalling

Has someone ever been able to remove unused namespaces during marshal of an object using JAXB? Here is a link of the requested feature: https://github.com/javaee/jaxb-v2/issues/103 (see description)
Is there a property for configuring JAXB for this?
Has this been fixed in MOXy?
I am currently traversing the object that needs to be marshalled and extract all classes that need to be bound into Class[] classesToBeBound.
Then I create a new JAXBContext.newInstance(classesToBeBound)
The unused namespaces now are not included in the XML.
I know that xml validation is valid even with the unused namespaces but to me this is something a framework should handle.
The following link https://blogs.oracle.com/enterprisetechtips/entry/customizing_jaxb mentions various fixed (see middle of the text somewhere) but when trying to find the solution in those links either the link is broken or no-one really solved it.
Any comments are welcome.
(EDIT)
Plain text:
GIVEN
a new instance of JAXBContext and add 2 classes with each a separate namespace.
WHEN
marshalling a class that has these 2 classes as a property but only 1 of them is not null
THEN
I expect only the namespace of the property that is not null to be visible in the XML.
BUT the ACTUAL is
that both namespaces are in the xml.
So my question was how can I remove or tell JAXB to NOT write the unused namespaces?
To put it in java-code:
GIVEN
public class Foo{
private Bar bar; //namespace something2
private User user; //namespace user
}
WHEN
JAXBContext c = JAXBContext.newInstance(Foo.class, Bar.class, User.class);
...
Foo foo = new Foo();
foo.setBar(null);
foo.setUser(new User("Bob"));
marshaller.umarshal(foo);
THEN I expect the xml to be
<foo xmlns="something1" xmlns:user="user">
<user:name>Bob</user:name>
</foo>
BUT the ACTUAL is (note the something2 namespace)
<foo xmlns="something1" xmlns:user="user" xmlns:bar="something2">
<user:name>Bob</user:name>
</foo>
Of course this is a simplified example and our specification of a type has around 30 different namespaces.
As far as I know, this is indeed not possible in JAXB - and is actually a well-known issue. As you have noticed it, the list of produced namespaces are the ones that have been registered in your JAXBContext, and not the ones that are effectively used when marshalling :-(
I the past, I used the same workaround as you (identify the various used classes and narrow the JAXBContext to this limited set of classes).
Another typical workaround is a 2-step processing: a first marshalling with JAXB, followed by a XSLT transformation to get rid of let's says "polluting" namespaces.
This may not be possible as while marshaling of this objects hierarchy happen, at the time of creating root tag, information about which objects are null v/s not null may not be available. Any attempt to get this information in advance may also have side-effects associated with it as respective accessor methods are invoked. Hence JAXB will statically use info from JAXBContext to have this information populated.
You can try using a different javax.xml.bind.Marshaller implementation.
For example org.eclipse.persistence.jaxb.JAXBMarshaller implementation deals well with this case and remove all unnecessary namespaces when marshall the object.
To do so you need to do the next steps:
Add eclipselink-2.6.5.jar to the classpath in order to use the org.eclipse.persistence.jaxb.JAXBMarshaller. If you're using gradle you can add compile 'org.eclipse.persistence:eclipselink:2.6.5' to your dependencies.
Create a jaxb.properties file in the same package where you've the objects to marshall (following the example in your question - JAXBContext c = JAXBContext.newInstance(Foo.class, Bar.class, User.class);, in the package of one of these classes Foo, Bar or User).
In the jaxb.properties file, add the follow property which specify the desired Context factory:
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
Doing this, the org.eclipse.persistence.jaxb.JAXBMarshaller will be used as a javax.xml.bind.Marshaller implementation on Runtime. And then no unnecessary namespaces will appear when you marshall the objects.
I tried the solution albciff suggested in this thread and it turns out that Eclipse Moxy handles this much better than the reference implementation (org.glassfish.jaxb).
Here's info on how to switch to the Moxy implemenation of JAXB:
https://wiki.eclipse.org/EclipseLink/Examples/MOXy/JAXB/SpecifyRuntime
The documentation doesn't specify it but you can also change the jaxb implemenation with just a single configuration file instead of a jaxb.properties in each package where your jaxb annotated classes exists. Just create a file META-INF/services/javax.xml.bind.JAXBContext (yep unconventional filename) with the contents:
org.eclipse.persistence.jaxb.JAXBContextFactory
This makes the jaxb ContextFinder use the Eclipse Moxy implementation for all jaxb marshalling in the jvm.
Another option is to use a system property -Djavax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
Disclaimer though: The namespaces declaration aren't minimized/optimized for the current payload, but at least it doesn't include ALL namespaces that are part of the jaxb grammar. The integration I'm working on went from a staggering 700+ declared namespaces (about 60KB worth of useless overhead per sent message) to at best 3 declarations in a message. Though for messages which have a lot of different types in them, all of the namespaces which are valid in that particular message is declared. That means in some case I still get ~30 declared namespaces when only one would suffice for the current payload.
I guess that SOAP isn't the way to go if you need to optimize on bandwidth.
Yes, they could be omitted. I'm not sure I understood the problem you face correctly. But there is no problem to marshal an object without namespaces.
Try something like this marshaller.setProperty(Marshaller.JAXB_NO_NAMESPACE_SCHEMA_LOCATION, "class for which namepsace not needed"); in your case it should be
marshaller.setProperty(Marshaller.JAXB_NO_NAMESPACE_SCHEMA_LOCATION, bar.class);

Apply JAXB annotation dynamically

Suppose i have a BOOK.java file with the fields(id, name, author) and now while marshalling it to XML file, I want only id to be written in XML file but that has to be decided by some condition. So I was thinking to inject #XmlTransient annotations to other two fields on that condition at runtime. Is it possible to inject an JAXB annotations at runtime? Can i do that and if i can, how can i do so?
Is there any way other then using javassist to do so ?
It sounds like you just want something that's not JAXB. JAXB is great when it fits, but it's pretty restrictive in what it allows you to do. Something like XStream would probably fit your needs better. You can write a custom Converter that will handle all the logic of whether to write a particular field or not.

JPA Hibernate Typedef

In the project I am using JPA with Hibernate implementation. All the entities are annotation based and listed in persistence.xml.
All Entities are packaged into jar.
I need to define a typedef for few properties(in all the entities) which are a string to a enum type. In DB the Columns is varchar. How can i achieve this?
Can I achieve this by adding hbm.xml and hibernate-cfg.xml?
Thanks in advance.
Straight from the documentation:
#org.hibernate.annotations.TypeDef and
#org.hibernate.annotations.TypeDefs allows you to declare type
definitions. These annotations can be placed at the class or package
level. Note that these definitions are global for the session factory
(even when defined at the class level). If the type is used on a
single entity, you can place the definition on the entity itself.
Otherwise, it is recommended to place the definition at the package
level.
If you can't change the classes but can change the hibernate config, I think you could change hibernate.mapping.precedence to be "hbm,class", and then add hbm files with all the information in the annotations for the relevant classes. There is hbm syntax to specify a UserType or an EnumType. You'd also have to define your UserType class if using that.
You might want to try this out on a test project before taking my word for it, I'm assuming it would work but I don't know for sure.
Copying all of the persistence information from annotations to hbm could be a pain, and would duplicate information. Try if possible to find a way to add the annotations to the classes themselves.

Simple Java Xml to POJO mapping/binding?

I'm trying to figure out the simplest way to map an xml file to to a plain old java object.
Note: That in my example the xml doesn't quite match up with my intended POJO.
///////// THE XML
<?xml version="1.0" encoding="UTF-8"?>
<Animal>
<standardName>
<Name>Cat</Name>
</standardName>
<standardVersion>
<VersionIdentifier>V02.00</VersionIdentifier>
</standardVersion>
</Animal>
////// THE INTENDED POJO
class Animal
{
private String name;
private String versionIdentifier;
}
Regular JAXB (with annotations) won't work as the JAXM Element name annotations don't allow me to specifiy nested elements. (i.e. standardName/Name).
I've looked at Jibx but it seems overly complicated, and no full examples are provided for what I want to do.
Castro seems like it would be able to do what I want (using mapping files), but I wonder if there are any other possible solutions. (Possibly that would allow me to skip mapping files, and just allow me to specify everything in annotations).
Thanks
EclipseLink JAXB (MOXy) allows you to do the path based mapping that you are looking for:
#XmlRootElement
class Animal
{
#XmlPath("standardName/Name/text()")
private String name;
#XmlPath("standardVersion/VersionIdentifier/text()");
private String versionIdentifier;
}
For more information see:
http://bdoughan.blogspot.com/2010/09/xpath-based-mapping-geocode-example.html
http://bdoughan.blogspot.com/2010/07/xpath-based-mapping.html
http://wiki.eclipse.org/EclipseLink/Examples/MOXy/GettingStarted/MOXyExtensions
EclipseLink also allows the metadata to be specified using an external configuration file:
http://wiki.eclipse.org/EclipseLink/Examples/MOXy/GettingStarted/ExternalizedMetadata
This article may help you... it only requires you to know xpath
http://onjava.com/onjava/2007/09/07/schema-less-java-xml-data-binding-with-vtd-xml.html
Jakarta Commons Digester should do what you want.
Alternatively, I would recommend writing a transformation class that uses XPath to retrieve elements from the XML.
I consider JiBX the best of the bunch (JAXB, Castor, XMLBeans, etc.), particularly because I favor mapping files over annotations. Admittedly it has a decent learning curve, but the website has a lot of good examples. You must have missed the tutorial.
If you are only going one way (XML --> POJO) you could use Digester.
Side comment: I prefer mapping files over annotations because annotations:
clutter the code (especially when using annotations from several products)
mix concerns (XML, database, etc. in domain layer)
can only bind to a single XML (or database, or web service, etc.) representation

Categories