JAXB Ignore a method at runtime - jaxb

I have a class which is a 3rd party class. I can marshall and unmarshall in Java 7 but not Java 6. The reason is because it contains the following method
public PrintWriter getLogWriter() and PrintWriter does not have a default constructor. I am not using this method and the value is always null. I just want ignore this method, but I do not have the source code.
I am looking for the simplest way to do this.

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

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?

Inspect Groovy object properties with Java reflection

I have an Expando class which I need to inspect its properties from Java.
In Groovy:
def worker = new Expando()
worker.name = "John"
worker.surname = "Doe"
In Java:
Introspector.getBeanInfo(groovyObject.getClass())
Is it possible to compile at runtime the class from the object in Groovy?
The Expando is completely dynamic. It does not generate any bytecode getters or setters and therefore cannot be used as a JavaBean. What do you need to use the bean introspector for? You may be able to implement that logic using the expando directly if you write it in Groovy.
You might try the JSR 223 / Script engine with Groovy (example here) if you are using Java 6. It allows you to evaluate Groovy code from Java.
Depending on the location/definition of the Expando, you might be able to get its properties by evaluating getProperties() (as of Groovy 1.7).

How can I have JAXB call a method after it has completed unmarshalling an XML file into an object?

I am using JAXB to unmarshall an XML file into a Java object -- standard stuff. Once JAXB has completed this, I'd like a method to be called on the newly created object.
Is there a mechanism to do this? I'd prefer the object, not an external entity, do this to keep construction in one place.
Thanks.
You can simple add the following method to your object definition:
void afterUnmarshal(Unmarshaller u, Object parent) {
...
}
It will be called once the current object has been completely deserialized.
See also the documentation about unmarshalling callbacks
In addition to the Unmarshaller.Listener you can add the following methods to your domain model classes themselves.
public void beforeUnmarshal(Unmarshaller unmarshaller, Object parent)
public void afterUnmarshal(Unmarshaller unmarshaller, Object parent)
From:
http://java.sun.com/javase/6/docs/api/javax/xml/bind/Unmarshaller.Listener.html
To be able to execute code after unmarshalling took place, you need
an Unmarshaller-Listener
However, I'm not sure, if the listener is invoked after the
properties are set or before.
NOTE: The listener is available since JAXB-2.0 (JDK-6)

Resources