JAXB unmarshalling Custom entities without annotation - jaxb

We have an xml file which we need to unmarshall(convert into a Java Object). Now the Java object is of third party and I cannot annotate it for unmarshalling. Any idea as to how I can Unmarshal without annotation. Please find my code snippet below
JAXBContext context;
try {
context = JAXBContext.newInstance(Abc.class);
Unmarshaller unMarshaller = context.createUnmarshaller();
Abc abc= (Abc) unMarshaller.unmarshal(new FileInputStream("C:\\Documents and Settings\\sandeep.nair\\Desktop\\abc.xml"));
} catch (JAXBException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}catch (Exception e){
}
I am getting the following exception. One for No argument Constructor(I know I can solve this by adding annotation for Adapter but I want to know or see a sample snippet for handling it without annotation)
Similarly I am getting another message as to Interfaces cannot be handle by JAXB.
com.sun.xml.bind.v2.runtime.IllegalAnnotationsException: 5 counts of IllegalAnnotationExceptions
java.sql.Timestamp does not have a no-arg default constructor.
this problem is related to the following location:
at java.sql.Timestamp
at public java.sql.Timestamp com.test.Abc.getSomeTimestamp()
at com.riteaid.entities.customer.Customer
com.test.Def does not have a no-arg default constructor.
this problem is related to the following location:
at com.test.Def...
java.sql.Date does not have a no-arg default constructor.
this problem is related to the following location:
at java.sql.Date
...
com.test.Ghi is an interface, and JAXB can't handle interfaces.
this problem is related to the following location:
...
com.test.Ghi does not have a no-arg default constructor.
this problem is related to the following location:
..

Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB (JSR-222) expert group.
JAXB is configuration by exception , so you only need to add annotations where you want to override the default mapping behaviour:
http://blog.bdoughan.com/2012/07/jaxb-no-annotations-required.html
The standard way of supplying metadata is through annotations. In situations where you can't annotate such as 3rd party classes, then you may be interested in MOXy's external mapping document extension.
http://blog.bdoughan.com/2010/12/extending-jaxb-representing-annotations.html
http://blog.bdoughan.com/2012/04/extending-jaxb-representing-metadata-as.html
You can use an XmlAdapter to handle the javax.sql.Date and javax.sql.Timestamp types:
jaxb unmarshal timestamp

Related

Is it possible to make Map<?, ?> someMethod work with JAX-B?

When trying to generate web service artifacts using cxf-java2ws-plugin, which in turn uses JAX-B, I get the error below on a method that looks like this:
Map<?, ?> myMethod(...);
Changing the method signature is a last resort so i'm looking for alternatives.
Caused by: com.sun.xml.bind.v2.runtime.IllegalAnnotationsException: 2 counts of IllegalAnnotationExceptions
java.util.Map is an interface, and JAXB can't handle interfaces.
this problem is related to the following location:
at java.util.Map
at private java.util.Map com.company.SomeClass.arg2
at com.company.SomeClass
java.util.Map does not have a no-arg default constructor.
this problem is related to the following location:
at java.util.Map
at private java.util.Map
JAXB will allow you to have a property of type Map, but not to use it as a root level object.
http://blog.bdoughan.com/2013/03/jaxb-and-javautilmap.html

Null handling when Jersey unmarshals JSON via JAXB?

Jersey appears to have a set of predetermined default values for JSON nulls while unmarshalling via JAXB: String => "", Integer => 0, ... is there anyway to easily control these values either with configuration or annotations?
Using Jersey's POJO mapping I get what I want, which is to map JSON null to Java null, but for other reasons we really need to use JAXB.
It seems like this should be simple however I'm drawing a blank.
Thanks.
Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB (JSR-222) expert group.
The JAXB (JSR-222) specification does not cover JSON-binding so what you are experiencing is Jersey code interacting with the JAXB reference implementation producing some odd results wrt null handling. EclipseLink MOXy is a JAXB compliant implementation that also offers JSON binding that has more natural null handling.
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Customer {
private String firstName;
#XmlElement(nillable=true)
private String lastName;
}
If this was marshalled to JSON the result would be the following. Null values are not marshalled to JSON unless they are annotated with #XmlElement(nillable=true):
{
lastName: null
}
For More Information
http://blog.bdoughan.com/2012/04/binding-to-json-xml-handling-null.html
Jersey Integration
http://blog.bdoughan.com/2012/05/moxy-as-your-jax-rs-json-provider.html
https://github.com/jersey/jersey/tree/master/examples/json-moxy

Jaxb Xjc: make generated classes subtype of Exception?

How is it possible to make some xjc generated classes subclasses of a custom Exception, such that you can actually throw them, and processable by the JAXBContext? Often webservices return various faults defined that really should be an exception, but since they aren't you need to wrap them unneccesarily.
Even if you could create a JAXB (JSR-222) model that extended from Exception you wouldn't be able to create a JAXBContext from it. I would recommend wrapping the Exception in a domain model that is compatible with JAXB.
Java Model (Foo)
Below is a simple Java class that extends Exception.
package forum12840627;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement
public class Foo extends Exception {
}
Demo
The demo code below attempts to creates a JAXBContext on the Java model.
package forum12840627;
import javax.xml.bind.JAXBContext;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Foo.class);
}
}
Output
Below is the exception returned from running the demo code. The problem is that Exception is not a valid JAXB class and JAXB implementations pull in the super classes as it processes the Java model. (Note: In your own domain model you can annotate super classes with #XmlTransient to prevent them from being processed: http://blog.bdoughan.com/2011/06/ignoring-inheritance-with-xmltransient.html)
Exception in thread "main" com.sun.xml.bind.v2.runtime.IllegalAnnotationsException: 1 counts of IllegalAnnotationExceptions
java.lang.StackTraceElement does not have a no-arg default constructor.
this problem is related to the following location:
at java.lang.StackTraceElement
at public java.lang.StackTraceElement[] java.lang.Throwable.getStackTrace()
at java.lang.Throwable
at java.lang.Exception
at forum12840627.Foo
at com.sun.xml.bind.v2.runtime.IllegalAnnotationsException$Builder.check(IllegalAnnotationsException.java:102)
at com.sun.xml.bind.v2.runtime.JAXBContextImpl.getTypeInfoSet(JAXBContextImpl.java:472)
at com.sun.xml.bind.v2.runtime.JAXBContextImpl.<init>(JAXBContextImpl.java:302)
at com.sun.xml.bind.v2.runtime.JAXBContextImpl$JAXBContextBuilder.build(JAXBContextImpl.java:1140)
at com.sun.xml.bind.v2.ContextFactory.createContext(ContextFactory.java:154)
at com.sun.xml.bind.v2.ContextFactory.createContext(ContextFactory.java:121)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:202)
at javax.xml.bind.ContextFinder.find(ContextFinder.java:363)
at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:574)
at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:522)
at forum12840627.Demo.main(Demo.java:8)
UPDATE #1
If you are using EclipseLink JAXB (MOXy) as your JAXB provider then you will not see this exception as classes in the javax.* and java.* packages are not treated as domain classes. MOXy is the default JAXB provider in the WebLogic 12c environment or can be configured using a jaxb.properties file.
For More Information
http://blog.bdoughan.com/2011/05/specifying-eclipselink-moxy-as-your.html
http://blog.bdoughan.com/2011/12/eclipselink-moxy-is-jaxb-provider-in.html
UPDATE #2
The latest versions of the JAXB reference implementation appear to handle this use case now as well as MOXy. My original portability concerns may not be so much of an issue.
Yeah, I finally found something! The Inheritance plugin is able to make the generated classes inherit from classes or implement additional interfaces.
You need to include something like
<bindings node="//xsd:complexType[#name='WhateverException']">
<inheritance:extends>foo.bar.WhateverException</inheritance:extends>
</bindings>
into the binding file and override getStackTrace() to return null such that it doesn't get marshalled.
Unfortunately you might run into trouble with some JAXB implementations (see Blaise Doughan's answer) - I haven't found a workaround for that yet. So you can either use a not quite nonportable solution, or wrap the JAXB objects into Exceptions.

Why JAXB is not marshalling my own subclass

I have a jaxb object which can be marshalled successfully, and it has a list object, then I make a new object like below
public class Sub extends SuperJAXBClass{
#Override
public List getList1(){
//override here
return ...;
}
}
Then the code like below:
SuperJAXBClass sjc=new Sub();
marshall(sjc)
Then I found the List1 in Sub is not marshalled successfully.
Any one knows why this happens?
How to solve it?
You could do one of the following:
Option #1 - #XmlSeeAlso Annotation
JAXB (JSR-222) implementations can not use Java reflection to determine all the possible suclasses. As a work around you can annotate the super class with the #XmlSeeAlso annotation that provides JAXB a reference to the subclasses.
#XmlSeeAlso({Sub.class})
public class SuperJAXBClass {
}
Option #2 - Pass the Subclass When Creating JAXBContext
If you include the subclass when creating the JAXBContext then JAXB implementations will be aware of it. When a subclass is passed in metadata for the super classes is also created.
JAXBContext.newInstance(Sub.class);

JAXB is not picking up #XmlJavaTypeAdapter

I have the following class that I need to serialize as XML:
#XmlAccessorType(XmlAccessType.FIELD)
public class Position {
#XmlElement(name = "Quantity", required = true)
private DecimalQuantity quantity;
...
}
I have put an XmlJavaTypeAdapter on the DecimalQuantity class because I want it to be serialized simply as a BigDecimal without the DecimalQuantity wrapper.
#XmlJavaTypeAdapter(DecimalQuantityAdapter.class)
#Embeddable
public class DecimalQuantity {
private BigDecimal value;
...
}
Here's the very simple DecimalQuantityAdapter class:
public class DecimalQuantityAdapter
extends XmlAdapter<BigDecimal, DecimalQuantity> {
public DecimalQuantity unmarshal(BigDecimal val) throws Exception {
return new DecimalQuantity(val);
}
public BigDecimal marshal(DecimalQuantity val) throws Exception {
return val.getValue();
}
}
I have a unit test that shows that the adapter is working correctly. The following Order object that has a DecimalQuantity gets serialized correctly (notice that this test class looks almost identical to the Position class above):
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name = "Order")
public class Order {
#XmlElement(name = "Quantity", required = true)
private DecimalQuantity quantity;
...
}
This gets serialized as shown below - no wrapper around the decimal number - life is good!
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Order>
<Quantity>10.2</Quantity>
</Order>
The trouble starts when I try to use DecimalQuantity in other maven projects. For example, the Position class shown at the beginning of this post is in a different maven project. The web service that uses the Position class is in yet another maven project. When the web service tries to deserialize DecimalQuantity, it does not know what DecimalQuantity is and is not able to pick up the DecimalQuantityAdapter. This is the error I get:
Caused by: javax.xml.bind.JAXBException:
class org.archfirst.common.quantity.DecimalQuantity nor any of its super class is known to this context.
at com.sun.xml.bind.v2.runtime.JAXBContextImpl.getBeanInfo(JAXBContextImpl.java:594)
at com.sun.xml.bind.v2.runtime.XMLSerializer.childAsXsiType(XMLSerializer.java:648)
... 53 more
I have event tried to add the #XmlJavaTypeAdapter annotation on the attribute itself, but JAXB does not pick it up. The only way to get rid of the exception is to put an #XmlSeeAlso({DecimalQuantity.class}) on the Position class itself. However, this disables the adapter and I get the following (undesired) serialization:
<Quantity xsi:type="ns2:decimalQuantity" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
Any idea where the problem is? I feel it has something to do with the visibility of JAXB annotations on DecimalQuantity and DecimalQuantityAdapter across packages/projects.
Thanks.
Naresh
Ok, I finally found the problem. My unit test was picking up the JAXB implementation in the Java runtime, whereas my real application (a web service) was picking up the JAXB implementation from GlassFish. Apparently the implementation bundled with GlassFish (2.2.1.1) cannot handle my use case. I proved it by forcing my unit test to use jaxb-impl-2.2.1.1.jar. Also it seems that the bug has been fixed in the latest JAXB implementation (2.2.3-1), but I am struggling to figure out how to replace GlassFish's implementation with this new version (see my post here).
Are you sure the problem is with the XmlJavaTypeAdapter for decimals, not the DecimalQuantity type. Because the exception you've posted is the one that happens when JAXB encounters a value of unknown class.
What happens if you omit the #XmlJavaTypeAdapter annotation? I know it probably can't work the way you intend, but what is the error message? Isn't it the same?
As you wrote the exception is gone when you added:
#XmlSeeAlso({DecimalQuantity.class})
I would leave the annotation in the code and try to find the reason why the adapter doesn't work.
Can you debug in the your XML adapter and/or add some trace output there, just to make sure the adapter really returns a non-empty String?

Resources