Is there something like PostConstruct for JAXB-annnotated classes?

I need to perform certain operations on a class after it has been unarmored (after being built by JAXB, not by me).

Is there such functionality in JAXB?

If not, how can I achieve this?

+2


source to share


3 answers


While the required functionality doesn't seem to be present in JAXB, I've managed to achieve something that goes in the right direction:

  • I am using JSR-305 annotation @PostConstruct

    (this is just a deprecated annotation, functionality is not provided by JSR)
  • I am adding unmasrshaller-listener to unmarshaller, which is called by JAXB every time the object was unmarshalled.
  • I am checking this object using Java reflection and looking for an annotation @PostConstruct

    for the method
  • I am executing method

Tested. Works.

Here is the code. Sorry, I'm using the external reflection API to get all methods, but I think the idea is clear:

Implementation

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 the @PostConstruct

non-nominated method to make sure it is final.
Do you find this a useful constraint?

Using

This is how the concept can 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!

      

Feature request submitted

https://jaxb.dev.java.net/issues/show_bug.cgi?id=698

+3


source


You can use class-defined event callbacks. More details here http://java.sun.com/javase/6/docs/api/javax/xml/bind/Unmarshaller.html#unmarshalEventCallback
For example, put this method in a 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);
    }
+5


source


This is not a 100% solution, but you can always register XmlAdapter

with a help @XmlJavaTypeAdapter annotation

for this type.

The downside would be that you have to serialize the class yourself (?). I don't know what a simple way to access and call the default serialization mechanism. But with a custom [ XmlAdapter

] you can control how the type is serialized and what happens before / after it.

0


source







All Articles