JaxB参考解析 [英] JaxB reference resolving

查看:76
本文介绍了JaxB参考解析的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

对于以下示例XML输入:

For the follwing example XML input:

<Participants course="someCourse">
  <workers>
    <Worker ref="p3">
    <Worker ref="p2">
  </workers>
  <Trainer ref="p1"/>
</Participants>

<Group id="group1" name="some mixed Person group">
   <trainers>
     <Trainer id="p1" name="John Doe">
   </trainers>
   <workers>
     <Worker id="p2" name="Jim Scott">
     <Worker id="p3" name="Walter Peace">
   </workers>
</Group>

我试图确保参与者中的PersonList指向从group1读取的人员。 (有关使用的JaxB注释,请参阅下面的代码片段)。这只是我正在寻求的更通用的
方法的一个例子。我需要通常能够以
的方式跟踪id =和ref =属性,列表元素被正确地解组为引用。

I am trying to make sure that the PersonList in Participants points to the Persons read from group1. (see code snipptes below for the JaxB annotations used). This is just an example for the more generic approach I am seeking. I need to be generally able to follow id="" and ref="" attributes in a way that the list elements are correctly unmarshalled as references.

使用UnmarshalListener和Unmarshalling两次,我解决了从ref属性到id属性的引用问题。在第一阶段,从id属性填充查找映射。在第二阶段,查询参考。不幸的是,此解决方案将创建副本而不是引用。我可以使用父对象来解决这个问题,但我正在寻找更通用的解决方案。以所示方式使用ref / id属性实现正确解除引用的好方法是什么?

With an UnmarshalListener and Unmarshalling twice I get around the problem of the references from the ref attribute to the id attribute. In the first phase the lookup Map is filled from the id attributes. In the second phase the refs are looked up. Unfortunately this solution will create copies instead of references. I could use the parent object to fix this but I am looking for a more generic solution. What would be a good way to achieve the proper dereferencing using ref/id attributes in the manner shown?

/**
 * intercept the unmarshalling
 */
public static class ModelElementMarshallerListener extends javax.xml.bind.Unmarshaller.Listener {

 public Map<String,Person> lookup=new HashMap<String,Person>();

 @Override
 public void afterUnmarshal(java.lang.Object target, java.lang.Object parent) {
  if (target instanceof Person) {
    person=(Person) target;
    if (person.getId()!=null) {
       lookup.put(person.getId(), person);
    }
    if (person.getRef()!=null) {
      if (lookup.containsKey(person.getRef())) {
        Person personRef=lookup.get(person.getRef());
        person.copyFrom(personRef);
        person.setRef(null);
      }
    }
   }
 }

}

@XmlRootElement(name="Participants")
public class Participants  {
  private List<Worker> workers;

 /**
   * getter for List<Worker> workers
   * @return workers
   */
  @XmlElementWrapper(name="workers")
  @XmlElement(name="Worker", type=Worker.class)
  public List<Worker> getWorkers() { 
    return workers; 
  }

...

}

@XmlRootElement(name="Group")
public class Group {

  private List<Worker> workers;

 /**
   * getter for List<Worker> workers
   * @return workers
   */
  @XmlElementWrapper(name="workers")
  @XmlElement(name="Worker", type=Worker.class)
  public List<Worker> getWorkers() { 
    return workers; 
  }
 ...

}
@XmlRootElement(name="Trainer")
public class Trainer extends Person {}


@XmlRootElement(name="Worker")
public class Worker extends Person {}

@XmlRootElement(name="Person")
public class Person {
 private String name;

 /**
   * getter for xsd:string/String name
   * @return name
   */
  @XmlAttribute(name="name")  
  public String getName() {
    return name;
  }

  public void setName(String name) {
     this.name=name;
  }
  private String ref;

 /**
   * getter for xsd:string/String id
   * @return id
   */
  @XmlAttribute(name="ref")  
  public String getRef() {
    return ref;
  }

  public void setRef(String ref) {
    this.ref=ref;
  }

  private String id;
 /**
   * getter for xsd:string/String id
   * @return id
   */
  @XmlAttribute(name="id")  
  @XmlID
  public String getId() { 
    this.id;
  }

  /**
   * setter for xsd:string/String id
   * @param pid - new value for id
   */
  public void setId(String pid) { 
    this.id=pid; 
  }
}


推荐答案

到更好地说明我已修改问题以适合他的答案。现在有一个通用的基类Person,我试图按照使用它来编写通用的XmlAdapter

To better illustrate the point I have modified the question to fit his answer. There is now a generic base class Person and I am trying to use it as per Can generic XmlAdapter be written

我解决了通过编写特定的派生类并将它们与@XmlJavaTypeAdapter一起使用来实际确保使用适配器的问题。我使用以下方法预先注册适配器:

I solved the issue of being able to actually make sure the Adapters are used by writing specific derived Classes and using them with @XmlJavaTypeAdapter. I preregister the adapters using:

JAXBContext context = JAXBContext.newInstance(type);
Unmarshaller u = context.createUnmarshaller();
u.setAdapter(Worker.WorkerAdapter.class,new Worker.WorkerAdapter());
u.setAdapter(Trainer.TrainerAdapter.class,new Trainer.TrainerAdapter());

然后解组两次。调试显示两个传递的Adapter实例是相同的。仍然查找似乎失败...原因是@XmlJavaTypeAdapter注释的工作方式见:

and then unmarshalling twice. The debug shows that the Adapter instance for both passes is the same. Still the lookup somehow seemed to fail ... The reason was the way the @XmlJavaTypeAdapter annotation works see:

我用XmlJavaTypeAdapters注释什么包信息?

@XmlJavaTypeAdapter似乎有多种模式:

There seem to be multiple modes for @XmlJavaTypeAdapter:


  • 它可以是类的注释

  • 它可以是字段的注释(getter)

  • 它可以在package-info.java文件中用于注释整个包

此时我正在使用所有三个注释,现在必须调试哪些是必要的。我假设全局注释(类,包)没有按预期工作。原因可能是@XmlElementWrapper中的type = usage显式调用了一个类型。就个人而言,我还不明白发生了什么。至少事情现在按预期工作。

At this point I am using all three annotations and now have to debug which ones are necessary. I assume the global annotations (class,package) are not working as expected. The reason might be the type= usage in the @XmlElementWrapper which explicitly calls for a type. Personally I do not understand what is going on yet. At least things are now working as expected.

现在的本地字段注释例如:

the local field annotation is now e.g.:

@XmlElementWrapper(name="workers")
@XmlElement(name="Worker", type=Worker.class)
@XmlJavaTypeAdapter(WorkerAdapter.class)

package-info.java注释是:

the package-info.java annotation is:

@XmlJavaTypeAdapters({
 @XmlJavaTypeAdapter(value=WorkerAdapter.class,type=Worker.class),
 @XmlJavaTypeAdapter(value=TrainerAdapter.class,type=Trainer.class),
})
package com.bitplan.jaxb.refidtest;

import javax.xml.bind.annotation.adapters。*;

import javax.xml.bind.annotation.adapters.*;

类注释是:

@XmlJavaTypeAdapter(Worker.WorkerAdapter.class)
public class Worker extends Person {

...

/**
 * Worker Adapter
 * @author wf
 *
 */
public static class WorkerAdapter extends  PersonAdapter<Worker>{
    @Override
    public Worker marshal(Worker me)
            throws Exception {
        return super.marshal(me);
    }


    @Override
    public Worker unmarshal(Worker me) throws Exception {
        return super.unmarshal(me);
    }
}


/**
 * https://stackoverflow.com/questions/7587095/can-jaxb-marshal-by-containment-at-first-then-marshal-by-xmlidref-for-subsequen/7587727#7587727
 * @author wf
 *
 */
public class PersonAdapter<T extends Person> extends XmlAdapter<T, T>{

    public boolean debug=true;

    /**
     * keep track of the elements already seen
     */
    public Map<String,T> lookup=new HashMap<String,T>();


    @Override
    public T marshal(T me)
            throws Exception {
        return me;
    }

    /**
     * show debug information
     * @param title
     * @param key
     * @param me
     * @param found
     */
    public void showDebug(String title,String key,T me, T found) {
        String deref="?";
        if (found!=null)
            deref="->"+found.getId()+"("+found.getClass().getSimpleName()+")";
        if (debug)
            System.err.println(title+": "+key+"("+me.getClass().getSimpleName()+")"+deref+" - "+this);
    }


    @Override
    public T unmarshal(T me)    throws Exception {
        if (me.getId()!=null) {
            showDebug("id",me.getId(),me,null);
            lookup.put(me.getId(), me);
            return  me;
        }
        if (me.getRef()!=null) {
            if (lookup.containsKey(me.getRef())) {
                T meRef=lookup.get(me.getRef());
                showDebug("ref",me.getRef(),me,meRef);
                me.setRef(null);
                            return  meRef;
            } else {
                if (debug)
                    showDebug("ref",me.getRef(),me,null);
            }
        }
        return  me;
    }

}

这篇关于JaxB参考解析的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆