Проблема в том, что ваша структура POJO не соответствует xml (и, как мы выяснили в конце, RestTemplate не использовал аннотации JAXB, см. Редактирование 4 ниже).
Давайте исправим это, чтобы вы могли правильно выполнить демаршаллинг.
Большинство полей используют пространство имен http://www.w3.org/2005/Atom
. Мы будем использовать информацию о пакете вместо того, чтобы добавлять ее в каждый элемент. Поэтому создайте файл package-info.java в пакете ваших классов с содержимым:
@javax.xml.bind.annotation.XmlSchema(namespace = "http://www.w3.org/2005/Atom", elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
package the.package.of.your.classes;
Тогда давайте исправим подачу. У вашего xml есть элементы, которых нет у вашего класса, и это проблема, потому что он встречает неожиданные элементы. Подача будет:
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Feed {
@XmlElement(name="schema-version", namespace = "http://www.example.com/publications/api")
private String schemaVersion;
@XmlElement
private String category;
@XmlElement
private String id;
@XmlElement(name="entry")
private Entry entry;
}
Обратите внимание, что версия схемы имеет другое пространство имен, чем то, что мы имеем в информации о пакете, поэтому мы явно переопределяем ее в аннотациях.
Теперь это упрощено. Например, категория имеет атрибуты xml, например, термин и метка. Если вы хотите получить эту информацию, вы должны создать класс для представления Category вместо String. Но если вы этого не сделаете, Лента, подобная этой, позволяет нам продолжать демаршаллинг. Следующая запись:
@XmlAccessorType(XmlAccessType.FIELD)
public class Entry {
@XmlElement
private String id;
@XmlElement
private String category;
@XmlElement
private String content;
@XmlElement(name="object", namespace = "http://www.example.com/publications/api")
private ApiObject object;
}
Снова атрибуты здесь игнорируются с использованием String. Я изменил Object на класс с именем ApiObject, структура которого соответствует xml. Это выглядит так:
@XmlAccessorType(XmlAccessType.FIELD)
public class ApiObject {
@XmlElement(name= "last-name", namespace = "http://www.example.com/publications/api")
private String lastName;
@XmlElement(name = "first-name", namespace = "http://www.example.com/publications/api")
private String firstName;
@XmlElement(name = "email-address", namespace = "http://www.example.com/publications/api")
private String emailAddress;
}
И, наконец, xml. Недопустимый xml, тег «content» не закрыт в вставленном образце. Я изменил его на <content type="xhtml" />
, чтобы проверить мое решение.
И действительно, это работает и отлично разбирается :) 1023 *
РЕДАКТИРОВАТЬ, чтобы ответить:
Для вопроса 1 вы бы добавили пространство имен в каждый элемент, который прямо не указывает пространство имен.
Для вопроса 2 Вы можете игнорировать неизвестные элементы, используя то, что было предложено здесь: JAXB Игнорировать «дополнительные» элементы из XML-ответа
Лента, например, будет выглядеть так:
@XmlRootElement(namespace = "http://www.w3.org/2005/Atom")
@XmlAccessorType(XmlAccessType.FIELD)
public class Feed {
@XmlAnyElement(lax = true)
private List<Object> anything;
@XmlElement(name="entry", namespace = "http://www.w3.org/2005/Atom")
private Entry entry;
}
РЕДАКТИРОВАТЬ 2:
Возьмите xml, который вы пытаетесь разобрать, и сделайте что-то вроде ниже:
try {
File file = new File("/path/to/your/file.xml");
JAXBContext jaxbContext = JAXBContext.newInstance(YouRootClass.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
jaxbUnmarshaller.setEventHandler(
new ValidationEventHandler() {
public boolean handleEvent(ValidationEvent event ) {
throw new RuntimeException(event.getMessage(),
event.getLinkedException());
}
});
YouRootClass pojo = (YouRootClass) jaxbUnmarshaller.unmarshal(file);
} catch (JAXBException e) {
e.printStackTrace();
}
Какое бы несоответствие между вашими xml и POJO не возникло, вы можете исправить это
РЕДАКТИРОВАТЬ 3:
Поток
@XmlRootElement(namespace = "http://www.w3.org/2005/Atom")
@XmlAccessorType(XmlAccessType.FIELD)
public class Feed {
@XmlAnyElement(lax = true)
private List<Object> anything;
@XmlElement(name="entry", namespace = "http://www.w3.org/2005/Atom")
private Entry entry;
}
запись
@XmlAccessorType(XmlAccessType.FIELD)
public class Entry {
@XmlAnyElement(lax = true)
private List<Object> anything;
@XmlElement(name="object", namespace = "http://www.example.com/publications/api")
private ApiObject object;
}
ApiObject:
@XmlAccessorType(XmlAccessType.FIELD)
public class ApiObject {
@XmlAnyElement(lax = true)
private List<Object> anything;
@XmlElement(name= "last-name", namespace = "http://www.example.com/publications/api")
private String lastName;
@XmlElement(name = "first-name", namespace = "http://www.example.com/publications/api")
private String firstName;
@XmlElement(name = "email-address", namespace = "http://www.example.com/publications/api")
private String emailAddress;
}
РЕДАКТИРОВАТЬ 4:
В вашем проекте github класс Test после создания RestTemplate (строка 31) добавляет:
List<HttpMessageConverter<?>> messageConverters = new ArrayList<>();
Jaxb2RootElementHttpMessageConverter jaxb2RootElementHttpMessageConverter = new Jaxb2RootElementHttpMessageConverter();
messageConverters.add(jaxb2RootElementHttpMessageConverter);
rest.setMessageConverters(messageConverters);