在复杂类上使用JAXB unmarshaller时,AtomicInteger会递增

时间:2018-06-11 06:42:20

标签: java jaxb

使用JAXB unmarshaller时,我遇到了有关AtomicInteger的问题。我有以下示例代码,我试图从xml文件解组MyTree。我使用AtomicInteger为每个Vertex创建一个唯一的id。解组MyTree时,它会在创建边时增加。如果我在topexList中有三个顶点,在myTree.xml中有edgeList中的两个边,则在解组后创建一个新顶点的nextID将创建8而不是4.因为对于每个边,它为sourceVertex和targetVertex添加一个顶点。你能帮我弄清楚我做错了什么吗?我该如何克服这个问题。非常感谢。 (我是JAVA和JAXB的新手)

JAXBContext context= JAXBContext.newInstance(MyTree.class);
Unmarshaller unmarshaller= context.createUnmarshaller();
MyTree newTree= (MyTree) unmarshaller.unmarshal(new File("MyTree.xml"));


@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement
public class MyTree{

   ArrayList<Vertex> vertexList =new ArrayList<Vertex>();
   ArrayList<Edge> edgeList = new ArrayList<Edge>();

   public MyTree() {

   }
   ...
}

@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement
public class Vertex{

  public int vertexId;
  private static AtomicInteger nextId = new AtomicInteger(0);
  public Vertex() {
    this.vertexId=nextId.incrementAndGet();     
  }
  ...
}

 @XmlAccessorType(XmlAccessType.FIELD)
 @XmlRootElement
 public class Edge {

    private Vertex sourceVertex;
    private Vertex targetVertex;
    private EdgeType edgeType;

    public Edge () {

    }
    ... 
 }
   enum EdgeType 
   {
     White,
     Red, 
     Blue;
   }

1 个答案:

答案 0 :(得分:0)

很难从你提供的代码中看出实际的最佳解决方案,但你可以这样做:

据我所知,有两种方法可以通过构造函数或反序列化来创建Vertex,后者通过过于频繁地调用构造函数来创建问题。因此,将id管理删除到另一个类,并在您确定需要时仅请求ID。

首先,您需要将代码重构为构造函数,而不是递增计数器。所以

@XmlRootElement
class Vertex {
    private int vertexId;
    public Vertex() { // initialize without incrementing the counter
    }
}

将id管理移至单独的类。例如

class VertexManager {
    // Singleton
    private static VertexManager INSTANCE;
    private VertexManager() { }
    public static VertexManager getInstance() {
        if (INSTANCE == null) { INSTANCE = new VertexManager(); }
        return INSTANCE;
    }

    // keep track of the ids
    private AtomicInteger currentId = new AtomicInteger();

    // create new vertex
    public static Vertex create() {
        Vertex created = new Vertex();
        register(created);
        return created;
    }
    // add previously created vertex
    public void register(Vertex v) {
        int id = currentId.incrementAndGet();
        v.setId(id);
    }
}

现在你所有的当前代码都依赖于构造函数递增它,你必须确保所有这些地方都使用VertexManager#create()代替!我建议将Vertex构造函数设置为private以在使用它时引发编译器错误,然后在更改它们之后重置。

您的反序列化完成时可以使用的register方法;在读取树之后,所有Vertex es都是稳定的 - 但是它们仍然需要分配它们的ID。所以

JAXBContext context= JAXBContext.newInstance(MyTree.class);
Unmarshaller unmarshaller= context.createUnmarshaller();
MyTree newTree= (MyTree) unmarshaller.unmarshal(new File("MyTree.xml"));
newTree.getVertices().forEach(v -> VertexManager.getInstance().register(v));