Перейти к основному содержимому

Руководство пользователя XStream: преобразование XML в объекты

· 4 мин. чтения

1. Обзор

В предыдущей статье мы узнали, как использовать XStream для сериализации объектов Java в XML. В этом руководстве мы узнаем, как сделать обратное: десериализовать XML в объекты Java. Эти задачи могут быть выполнены с помощью аннотаций или программно.

Чтобы узнать об основных требованиях для настройки XStream и его зависимостей, обратитесь к предыдущей статье.

2. Десериализовать объект из XML

Для начала предположим, что у нас есть следующий XML:

<com.foreach.pojo.Customer>
<firstName>John</firstName>
<lastName>Doe</lastName>
<dob>1986-02-14 03:46:16.381 UTC</dob>
</com.foreach.pojo.Customer>

Нам нужно преобразовать это в объект Java Customer :

public class Customer {

private String firstName;
private String lastName;
private Date dob;

// standard setters and getters
}

XML можно вводить несколькими способами, включая File , InputStream , Reader или String . Для простоты предположим, что у нас есть приведенный выше XML в объекте String .

Customer convertedCustomer = (Customer) xstream.fromXML(customerXmlString);
Assert.assertTrue(convertedCustomer.getFirstName().equals("John"));

3. Аспекты безопасности

Поскольку XStream использует недокументированные функции Java, а также Java Reflection, он может быть уязвим для атак с выполнением произвольного кода или удаленным выполнением команд.

Подробные соображения безопасности выходят за рамки этого руководства, но у нас есть специальная статья , в которой объясняется эта угроза. Также стоит заглянуть на официальную страницу XStream .

Для целей нашего руководства предположим, что все наши классы «безопасны». Следовательно, нам нужно настроить XStream:

XStream xstream = new XStream();
xstream.allowTypesByWildcard(new String[]{"com.foreach.**"});

4. Псевдонимы

В первом примере XML имел полное имя класса в самом внешнем XML-теге, совпадающем с местоположением нашего класса Customer . С этой настройкой XStream легко преобразует XML в наш объект без какой-либо дополнительной настройки. Но у нас не всегда могут быть эти условия. У нас может не быть контроля над именами тегов XML, или мы можем решить добавить псевдонимы для полей.

Например, предположим, что мы изменили наш XML, чтобы не использовать полное имя класса для внешнего тега:

<customer>
<firstName>John</firstName>
<lastName>Doe</lastName>
<dob>1986-02-14 03:46:16.381 UTC</dob>
</customer>

Мы можем скрыть этот XML, создав псевдонимы.

4.1. Псевдонимы классов

Мы регистрируем псевдонимы с экземпляром XStream либо программно, либо с помощью аннотаций. Мы можем аннотировать наш класс Customer с помощью @XStreamAlias :

@XStreamAlias("customer")
public class Customer {
//...
}

Теперь нам нужно настроить наш экземпляр XStream для использования этой аннотации:

xstream.processAnnotations(Customer.class);

В качестве альтернативы, если мы хотим настроить псевдоним программно, мы можем использовать следующий код:

~~

xstream.alias("customer", Customer.class);

4.2. Псевдонимы полей

Предположим, у нас есть следующий XML:

<customer>
<fn>John</fn>
<lastName>Doe</lastName>
<dob>1986-02-14 03:46:16.381 UTC</dob>
</customer>

Тег fn не соответствует ни одному полю в нашем объекте Customer , поэтому нам потребуется определить псевдоним для этого поля, если мы хотим его десериализовать. Мы можем добиться этого, используя следующую аннотацию:

@XStreamAlias("fn")
private String firstName;

Кроме того, мы можем достичь той же цели программно:

xstream.aliasField("fn", Customer.class, "firstName");

5. Неявные коллекции

Допустим, у нас есть следующий XML, содержащий простой список ContactDetails :

<customer>
<firstName>John</firstName>
<lastName>Doe</lastName>
<dob>1986-02-14 04:14:20.541 UTC</dob>
<ContactDetails>
<mobile>6673543265</mobile>
<landline>0124-2460311</landline>
</ContactDetails>
<ContactDetails>...</ContactDetails>
</customer>

Мы хотим загрузить список ContactDetails в поле List<ContactDetails> нашего объекта Java. Мы можем добиться этого, используя следующую аннотацию:

@XStreamImplicit
private List<ContactDetails> contactDetailsList;

Кроме того, мы можем достичь той же цели программно:

xstream.addImplicitCollection(Customer.class, "contactDetailsList");

6. Игнорировать поля

Допустим, у нас есть следующий XML:

<customer>
<firstName>John</firstName>
<lastName>Doe</lastName>
<dob>1986-02-14 04:14:20.541 UTC</dob>
<fullName>John Doe</fullName>
</customer>

В приведенном выше XML у нас есть дополнительный элемент <fullName> , который отсутствует в нашем объекте Java Customer .

Если мы попытаемся десериализовать приведенный выше xml, не заботясь о дополнительных элементах, программа выдаст исключение UnknownFieldException .

No such field com.foreach.pojo.Customer.fullName

Как ясно сказано в исключении, XStream не распознает поле fullName .

Чтобы решить эту проблему, нам нужно настроить его так, чтобы он игнорировал неизвестные элементы:

xstream.ignoreUnknownElements();

7. Поля атрибутов

Предположим, у нас есть XML с атрибутами как часть элементов, которые мы хотели бы десериализовать как поле в нашем объекте. Мы добавим атрибут contactType в наш объект ContactDetails :

<ContactDetails contactType="Office">
<mobile>6673543265</mobile>
<landline>0124-2460311</landline>
</ContactDetails>

Если мы хотим десериализовать XML-атрибут contactType , мы можем использовать аннотацию @XStreamAsAttribute в поле, в котором мы хотим, чтобы он отображался:

@XStreamAsAttribute
private String contactType;

Кроме того, мы можем достичь той же цели программно:

xstream.useAttributeFor(ContactDetails.class, "contactType");

8. Заключение

В этой статье мы рассмотрели доступные параметры при десериализации объектов XML в Java с помощью XStream.

Полный исходный код для этой статьи можно скачать из связанного репозитория GitHub .