Я определил следующие ObjectFactory
:
@XmlRegistry
public class ObjectFactory {
public Dogs createDogs() {
return new Dogs();
}
@XmlElementDecl(name = "dog")
public Dog createDog(DogType value) {
return new Dog(value);
}
@XmlElementDecl(name = "fido", substitutionHeadName = "dog", substitutionHeadNamespace = "")
public Dog createFido(DogType value) {
return new Dog("fido", value);
}
@XmlElementDecl(name = "barks", substitutionHeadName = "dog", substitutionHeadNamespace = "")
public Dog createBarks(DogType value) {
return new Dog("barks", value);
}
}
(класс Dogs
тривиален, Dog
и DogType
см. ниже или здесь.)
Я распаковываю следующий XML:
<listOfDogs>
<dogs>
<dog>
<name>henry</name>
<sound>bark</sound>
</dog>
<fido>
<sound>woof</sound>
</fido>
<barks>
<sound>miau</sound>
</barks>
</dogs>
</listOfDogs>
Я искренне ожидал, что JAXB вызовет мои методы createFido(...)
и createBarks(...)
во время десортировки. Но этого не происходит. Конструктор Dog
вызывается напрямую через отражение, соответствующие методы create...
не используются.
Мой вопрос:
Почему ObjectFactory
не вызывается во время разупорядочения?
Разве это не должно быть? Или это просто манекен для хранения объявлений @XmlRegistry
/@XmlElementDecl
?
Я также проверил этот вопрос:
Какова роль ObjectFactory во время JAXB-Unmarshalling?
Решение заключается в использовании @XmlType.factoryClass
и factoryMethod
. Здесь это не сработает, потому что я не хочу статически связывать свой DogType
с определенной процедурой создания экземпляра. Я хочу, чтобы это решалось во время выполнения на основе имени элемента. Моя цель — создать экземпляр одного и того же класса, но по-разному, в зависимости от имени элемента.
Теперь немного кода, чтобы завершить его.
Класс корневого элемента:
@XmlRootElement(name = "listOfDogs")
public class Dogs {
private List<JAXBElement<DogType>> dogs = new LinkedList<JAXBElement<DogType>>();
@XmlElementWrapper(name = "dogs")
@XmlElementRef(name = "dog")
public List<JAXBElement<DogType>> getDogs() {
return this.dogs;
}
@Override
public String toString() {
return "Dogs [dogs=" + dogs + "]";
}
}
Dog
, класс элемента-оболочки для DogType
:
public class Dog extends JAXBElement<DogType> {
public static final QName NAME = new QName("dog");
private static final long serialVersionUID = 1L;
public Dog(DogType value) {
super(NAME, DogType.class, value);
}
public Dog(String dogName, DogType value) {
super(NAME, DogType.class, value);
}
@Override
public QName getName() {
final DogType value = getValue();
if (value != null && value.getName() != null) {
return new QName(value.getName());
} else {
return super.getName();
}
}
}
DogType
:
public class DogType {
private String name;
private String sound;
public String getName() {
return name;
}
public void setName(String dogName) {
this.name = dogName;
}
public String getSound() {
return sound;
}
public void setSound(String sound) {
this.sound = sound;
}
}
Контрольная работа:
public class DogTest {
@Test
public void unmarshallsDogs() throws JAXBException {
final JAXBContext context = JAXBContext
.newInstance(ObjectFactory.class);
final Dogs dogs = (Dogs) context.createUnmarshaller().unmarshal(
getClass().getResource("dogs.xml"));
Assert.assertEquals(3, dogs.getDogs().size());
// Does not work
// Assert.assertEquals("henry", dogs.getDogs().get(0).getValue()
// .getName());
Assert.assertEquals("bark", dogs.getDogs().get(0).getValue().getSound());
// Does not work
// Assert.assertEquals("fido", dogs.getDogs().get(1).getValue()
// .getName());
Assert.assertEquals("woof", dogs.getDogs().get(1).getValue().getSound());
// Does not work
// Assert.assertEquals("barks", dogs.getDogs().get(2).getValue()
// .getName());
Assert.assertEquals("miau", dogs.getDogs().get(2).getValue().getSound());
}
}
ObjectFactory
— это просто манекен для хранения объявлений@XmlRegistry
/@XmlElementDecl
? Не кажется мне правильным. 07.11.2014ObjectFactory
класс? 07.11.2014createDog
,createFido
иcreateBarks
в моем примере. Они создают один и тот же экземпляр, но передают конструктору разные имена. 07.11.2014@XmlType
сfactoryClass
иfactoryMethod
- я хочу использовать один и тот же класс для разных корневых элементов. 07.11.2014XmlAdapter
пример, который должен дать вам поведение, эквивалентное тому, что вы ищете. 07.11.2014create*
методы изObjectFactory
? Если они должны, то в JAXB RI есть ошибка. Если нет, вы предоставили очень хороший обходной путь. Итак, практически проблема решена, но мне также интересно разобраться в спецификации. 07.11.2014