在复杂类上使用 JAXB 解组器时,AtomicInteger 递增



我在使用 JAXB 解组器时遇到了关于 AtomicInteger 的问题。我有以下示例代码,我正在尝试从 xml 文件中取消封送 MyTree。我使用 AtomicInteger 为每个顶点创建一个唯一的 id。当解组 MyTree 时,它在创建 Edge 时会递增。如果我在 myTree.xml 的 vertexList 中有三个顶点,在 edgeList 中有两个边,则在解组后,用于创建新顶点的 nextID 将创建 8 而不是 4。因为对于每条边,它都会为源顶点和目标顶点添加一个顶点。你能帮我弄清楚我做错了什么吗?以及我如何克服这个问题。多谢。(我对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;
}

很难从您给出的代码中判断出实际的最佳解决方案是什么,但您可以执行以下操作:

据我所知,有两种方法可以通过构造函数或反序列化来创建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都是稳定的 - 但它们仍然需要分配其 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));

最新更新