Можно ли настроить XStream так, чтобы он имел двунаправленные (родительские / дочерние) ссылки? - PullRequest
3 голосов
/ 14 января 2011

Я использую XStream для загрузки файла, структурированного так:

<parent>
  <child/>
  <child/>
</parent>

В такой класс:

public class Parent(){
 private List<Child> children;
}

public class Child { 
 private Parent parent; 
}

Я бы хотел сделать это: parent.getChildren().get(0).getParent()

Я бы хотел использовать XML, как он есть. Я знаю, что могу добавить ссылки на родителя под детьми, но это кажется очень излишним. Я знаю родителя childs из-за его структуры XML.

Поддерживает ли XStream это?

Ответы [ 3 ]

3 голосов
/ 14 января 2011

Да. Xstream поддерживает обратные ссылки, чтобы избежать циклических ссылок.Он делает это по умолчанию, но можно утверждать, действительно ли это сообщение подходит.Это просто для передачи некоторых данных по сети, но на самом деле это не «сообщение», а скорее сериализированный объект.

Ваши дочерние объекты должны иметь «указатель» на родителя.

2 голосов
/ 10 декабря 2013

Одним из вариантов является использование readResolve в родительском элементе для установки обратных ссылок. Это будет вызываться так же, как и при стандартной сериализации библиотеки в соответствии с часто задаваемыми вопросами XStream: http://x -stream.github.io / faq.html # Serialization_initialize_transient

Когда вызывается readResolve, Parent и все его дочерние элементы уже будут десериализованы, поэтому вы можете установить обратную ссылку в это время.

public class Parent {
  private List<Child> children = new ArrayList<Child>();
  private Object readResolve() {
    for( Child child: children ) {
      child.setParent(this);
    }
    return this;
  }
}
0 голосов
/ 19 января 2011

Если вы готовы рассмотреть возможность использования чего-то другого, кроме XStream, тогда EclipseLink JAXB (MOXy) легко обрабатывает двунаправленные свойства с помощью @ XmlInverseReference (я технический руководитель MOXy).

Ваша объектная модель будет отображаться как:

import java.util.List;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class Parent {

    private List<Child> children;

    @XmlElement(name="child")
    public List<Child> getChildren() {
        return children;
    }

    public void setChildren(List<Child> children) {
        this.children = children;
    }

}

и (обратите внимание на использование @XmlInverseReference для родительского свойства):

import org.eclipse.persistence.oxm.annotations.XmlInverseReference;

public class Child {

    private Parent parent;

    @XmlInverseReference(mappedBy="children")
    public Parent getParent() {
        return parent;
    }

    public void setParent(Parent parent) {
        this.parent = parent;
    }

}

Демонстрационная версиякод будет выглядеть так (input.xml ссылается на XML из вашего вопроса):

import java.io.File;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;

public class Demo {

    public static void main(String[] args) throws Exception {
        JAXBContext jc = JAXBContext.newInstance(Parent.class);

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        Parent parent = (Parent) unmarshaller.unmarshal(new File("input.xml"));

        for(Child child : parent.getChildren()) {
            System.out.println(child.getParent());
        }
    }

}

Чтобы указать MOXy в качестве реализации JAXB, вам нужно включить файл с именем jaxb.properties в тот же пакет, что и ваша модельклассы со следующей записью:

javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory

Ниже приведена ссылка на мое сравнение JAXB и XStream:

...