I need to perform certain operations on a class after it was unmarshalled (after it is constructed by JAXB, rather then by myself).
Is there such a functionality in JAXB?
If not, how could I achieve it?
I need to perform certain operations on a class after it was unmarshalled (after it is constructed by JAXB, rather then by myself).
Is there such a functionality in JAXB?
If not, how could I achieve it?
It's not a 100% solution, but you can always register a XmlAdapter
using @XmlJavaTypeAdapter annotation
for this type.
The downside would be that you have to serialize the class yourself (?). I am not aware of any simple way of accessing and calling the default serialization mechanism. But with custom [XmlAdapter
] you can control how is the type serialized and what happens before/after it.
Though the the demanded functionality seems not to be present in JAXB, I managed to achieve something which goes into the right direction:
@PostConstruct
annotation@PostConstruct
annotation on a methodTested. Works.
Here is the code. Sorry, I'm using some external reflection API to get all methods, but I think the idea is understandable:
JAXBContext context = // create the context with desired classes
Unmarshaller unmarshaller = context.createUnmarshaller();
unmarshaller.setListener(new Unmarshaller.Listener() {
@Override
public void afterUnmarshal(Object object, Object arg1) {
System.out.println("unmarshalling finished on: " + object);
Class<?> type = object.getClass();
Method postConstructMethod = null;
for (Method m : ReflectionUtils.getAllMethods(type)) {
if (m.getAnnotation(PostConstruct.class) != null) {
if (postConstructMethod != null) {
throw new IllegalStateException(
"@PostConstruct used multiple times");
}
postConstructMethod = m;
}
}
if (postConstructMethod != null) {
System.out.println("invoking post construct: "
+ postConstructMethod.getName() + "()");
if (!Modifier.isFinal(postConstructMethod.getModifiers())) {
throw new IllegalArgumentException("post construct method ["
+ postConstructMethod.getName() + "] must be final");
}
try {
postConstructMethod.setAccessible(true); // thanks to skaffman
postConstructMethod.invoke(object);
} catch (IllegalAccessException ex) {
throw new RuntimeException(ex);
} catch (InvocationTargetException ex) {
throw new RuntimeException(ex);
}
}
}
});
EDIT
Added a check for @PostConstruct
-annotated method, to ensure it is final.
Do you think it's a useful restriction?
Here is how the concept might be used.
@XmlAccessorType(XmlAccessType.NONE)
public abstract class AbstractKeywordWithProps
extends KeywordCommand {
@XmlAnyElement
protected final List<Element> allElements = new LinkedList<Element>();
public AbstractKeywordWithProps() {
}
@PostConstruct
public final void postConstruct() {
// now, that "allElements" were successfully initialized,
// do something very important with them ;)
}
}
// further classes can be derived from this one. postConstruct still works!
You can use the 'class defined' event callbacks.
Read more here http://java.sun.com/javase/6/docs/api/javax/xml/bind/Unmarshaller.html#unmarshalEventCallback
For example put this method in you JAXB object:
//This method is called after all the properties (except IDREF) are unmarshalled for this object, //but before this object is set to the parent object. void afterUnmarshal( Unmarshaller u, Object parent ) { System.out.println( "After unmarshal: " + this.state ); }