【问题标题】:Is there something like PostConstruct for JAXB-annnotated classes?对于 JAXB 注释的类,是否有类似 PostConstruct 的东西?
【发布时间】:2009-10-09 18:53:21
【问题描述】:

在 JAXB 中是否有这样的功能可以在解组后(即在由 JAXB 构造后)对类执行操作?如果没有,我怎么能做到这一点?

【问题讨论】:

标签: java dependency-injection constructor jaxb instantiation


【解决方案1】:

您可以使用在您的 JAXB 类中定义的 JAXB Unmarshal Event Callbacks,例如:

// 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 );
}

【讨论】:

    【解决方案2】:

    虽然 JAXB 中似乎不存在所需的功能,但我设法做到了 实现朝着正确方向发展的目标:

    • 我正在使用 JSR-305 的 @PostConstruct 注释
      (这只是一个 nacked 注释,JSR 不提供任何功能)
    • 我向解组器添加了一个解组器侦听器,每次解组对象时 JAXB 都会调用它。
    • 我使用 Java 反射检查此对象并搜索方法上的 @PostConstruct 注释
    • 我执行方法

    经过测试。有效。

    这里是代码。抱歉,我使用一些外部反射 API 来获取所有方法,但我认为这个想法是可以理解的:

    实施

    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);
          }
        }
      }
    
    });
    

    编辑
    添加了对@PostConstruct-annotated 方法的检查,以确保它是最终的。
    你认为这是一个有用的限制吗?

    用法

    下面是如何使用这个概念。

    @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!
    

    提交功能请求

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

    【讨论】:

    • 尝试在postConstructMethod 上调用setAccessible(true),这应该会强制它成为可调用的。
    【解决方案3】:

    这不是 100% 的解决方案,但您始终可以使用 @XmlJavaTypeAdapter annotation 注册 XmlAdapter 对于这种类型。

    缺点是您必须自己序列化该类(?)。我不知道访问和调用默认序列化机制的任何简单方法。但是使用自定义 [XmlAdapter],您可以控制类型如何序列化以及在它之前/之后发生什么。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-12-04
      • 2011-01-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多