XStream 사용 설명서 : 객체를 XML로 변환

1. 개요

이 튜토리얼에서는 XStream 라이브러리를 사용하여 Java 객체를 XML로 직렬화하는 방법을 배웁니다.

2. 특징

XStream을 사용하여 XML을 직렬화 및 역 직렬화하면 몇 가지 흥미로운 이점이 있습니다.

  • 올바르게 구성되어 매우 깨끗한 XML을 생성 합니다.
  • XML 출력 을 사용자 정의 할 수있는 중요한 기회를 제공합니다.
  • 순환 참조를 포함한 객체 그래프 지원
  • 대부분의 사용 사례에서 XStream 인스턴스는 일단 구성되면 스레드로부터 안전합니다 (주석 사용시주의 사항이 있음).
  • 예외 처리 중에 문제 진단에 도움 이되는 명확한 메시지가 제공됩니다.
  • 버전 1.4.7부터 특정 유형의 직렬화를 허용하지 않는 보안 기능이 있습니다.

3. 프로젝트 설정

프로젝트에서 XStream을 사용하기 위해 다음 Maven 종속성을 추가합니다.

 com.thoughtworks.xstream xstream 1.4.9 

4. 기본 사용법

XStream을의 클래스는 API의 외관입니다. XStream 인스턴스를 만들 때 스레드 안전 문제도 처리해야합니다.

XStream xstream = new XStream();

인스턴스가 생성 및 구성되면 주석 처리를 활성화하지 않는 한 마샬링 / 마샬링 해제를 위해 여러 스레드에서 공유 될 수 있습니다.

4.1. 드라이버

DomDriver , StaxDriver , XppDriver 등과 같은 여러 드라이버가 지원됩니다 . 이러한 드라이버는 성능 및 리소스 사용 특성이 다릅니다.

XPP3 드라이버는 기본적으로 사용되지만 물론 쉽게 드라이버를 변경할 수 있습니다.

XStream xstream = new XStream(new StaxDriver()); 

4.2. XML 생성

고객에 대한 간단한 POJO를 정의하여 시작하겠습니다 .

public class Customer { private String firstName; private String lastName; private Date dob; // standard constructor, setters, and getters }

이제 객체의 XML 표현을 생성 해 보겠습니다.

Customer customer = new Customer("John", "Doe", new Date()); String dataXml = xstream.toXML(customer);

기본 설정을 사용하면 다음 출력이 생성됩니다.

 John Doe 1986-02-14 03:46:16.381 UTC  

이 출력에서 ​​포함하는 태그 가 기본적 으로 Customer 라는 정규화 된 클래스 이름을 사용함을 분명히 알 수 있습니다 .

기본 동작이 우리의 요구에 맞지 않는다고 결정할 수있는 여러 가지 이유가 있습니다. 예를 들어 애플리케이션의 패키지 구조를 노출하는 것이 불편할 수 있습니다. 또한 생성 된 XML이 훨씬 더 길어집니다.

5. 별칭

별명은 우리가 오히려 기본 이름을 사용하는 것보다 요소를 사용하고자하는 이름입니다.

예를 들어, Customer 클래스에 대한 별칭을 등록하여 com.baeldung.pojo.Customercustomer 로 바꿀 수 있습니다 . 클래스 속성에 대한 별칭을 추가 할 수도 있습니다. 별칭을 사용하면 XML 출력을 훨씬 더 읽기 쉽고 Java에만 적용되지 않게 만들 수 있습니다.

5.1. 클래스 별칭

별칭은 프로그래밍 방식으로 또는 주석을 사용하여 등록 할 수 있습니다.

이제 @XStreamAlias로 Customer 클래스에 주석을 추가하겠습니다 .

@XStreamAlias("customer")

이제이 주석을 사용하도록 인스턴스를 구성해야합니다.

xstream.processAnnotations(Customer.class);

또는 프로그래밍 방식으로 별칭을 구성하려는 경우 아래 코드를 사용할 수 있습니다.

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

별칭을 사용하든 프로그래밍 방식 구성을 사용하든 고객 개체 의 출력은 훨씬 더 깔끔합니다.

 John Doe 1986-02-14 03:46:16.381 UTC  

5.2. 필드 별칭

별칭 클래스에 사용 된 것과 동일한 주석을 사용하여 필드에 별칭을 추가 할 수도 있습니다. 예를 들어, XML 표현에서 firstName 필드 를 fn 으로 바꾸 려면 다음 주석을 사용할 수 있습니다.

@XStreamAlias("fn") private String firstName;

또는 프로그래밍 방식으로 동일한 목표를 달성 할 수 있습니다.

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

aliasField의 우리가 사용하고자하는 별명, 클래스가있는 속성을 정의하고, 속성 이름은 우리가 별명하고자 : 방법은 세 가지 인수를 받아들입니다.

어떤 방법을 사용하든 출력은 동일합니다.

 John Doe 1986-02-14 03:46:16.381 UTC 

5.3. 기본 별칭

클래스에 대해 사전 등록 된 별칭이 여러 개 있습니다. 다음은 몇 가지입니다.

alias("float", Float.class); alias("date", Date.class); alias("gregorian-calendar", Calendar.class); alias("url", URL.class); alias("list", List.class); alias("locale", Locale.class); alias("currency", Currency.class);

6. 컬렉션

이제 Customer 클래스 안에 ContactDetails 목록을 추가합니다 .

private List contactDetailsList;

With default settings for collection handling, this is the output:

 John Doe 1986-02-14 04:14:05.874 UTC   6673543265 0124-2460311   4676543565 0120-223312   

Let's suppose we need to omit the contactDetailsList parent tags, and we just want each ContactDetails element to be a child of the customer element. Let us modify our example again:

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

Now, when the XML is generated, the root tags are omitted, resulting in the XML below:

 John Doe 1986-02-14 04:14:20.541 UTC  6673543265 0124-2460311   4676543565 0120-223312  

The same can also be achieved using annotations:

@XStreamImplicit private List contactDetailsList;

7. Converters

XStream uses a map of Converter instances, each with its own conversion strategy. These convert supplied data to a particular format in XML and back again.

In addition to using the default converters, we can modify the defaults or register custom converters.

7.1. Modifying an Existing Converter

Suppose we weren't happy with the way the dob tags were generatedusing the default settings. We can modify the custom converter for Date provided by XStream (DateConverter):

xstream.registerConverter(new DateConverter("dd-MM-yyyy", null));

The above will produce the output in “dd-MM-yyyy” format:

 John Doe 14-02-1986 

7.2. Custom Converters

We can also create a custom converter to accomplish the same output as in the previous section:

public class MyDateConverter implements Converter { private SimpleDateFormat formatter = new SimpleDateFormat("dd-MM-yyyy"); @Override public boolean canConvert(Class clazz) { return Date.class.isAssignableFrom(clazz); } @Override public void marshal( Object value, HierarchicalStreamWriter writer, MarshallingContext arg2) { Date date = (Date)value; writer.setValue(formatter.format(date)); } // other methods }

Finally, we register our MyDateConverter class as below:

xstream.registerConverter(new MyDateConverter());

We can also create converters that implement the SingleValueConverter interface, which is designed to convert an object into a string.

public class MySingleValueConverter implements SingleValueConverter { @Override public boolean canConvert(Class clazz) { return Customer.class.isAssignableFrom(clazz); } @Override public String toString(Object obj) { SimpleDateFormat formatter = new SimpleDateFormat("dd-MM-yyyy"); Date date = ((Customer) obj).getDob(); return ((Customer) obj).getFirstName() + "," + ((Customer) obj).getLastName() + "," + formatter.format(date); } // other methods }

Finally, we register MySingleValueConverter:

xstream.registerConverter(new MySingleValueConverter()); 

Using MySingleValueConverter, the XML output for a Customer is as follows:

John,Doe,14-02-1986

7.3. Converter Priority

When registering Converter objects, is is possible to set their priority level, as well.

From the XStream javadocs:

The converters can be registered with an explicit priority. By default they are registered with XStream.PRIORITY_NORMAL. Converters of same priority will be used in the reverse sequence they have been registered. The default converter, i.e. the converter which will be used if no other registered converter is suitable, can be registered with priority XStream.PRIORITY_VERY_LOW. XStream uses by default the ReflectionConverter as the fallback converter.

The API provides several named priority values:

private static final int PRIORITY_NORMAL = 0; private static final int PRIORITY_LOW = -10; private static final int PRIORITY_VERY_LOW = -20; 

8.Omitting Fields

We can omit fields from our generated XML using either annotations or programmatic configuration. In order to omit a field using an annotation, we simply apply the @XStreamOmitField annotation to the field in question:

@XStreamOmitField private String firstName;

In order to omit the field programmatically, we use the following method:

xstream.omitField(Customer.class, "firstName");

Whichever method we select, the output is the same:

 Doe 14-02-1986 

9. Attribute Fields

Sometimes we may wish to serialize a field as an attribute of an element rather than as element itself. Suppose we add a contactType field:

private String contactType;

If we want to set contactType as an XML attribute, we can use the @XStreamAsAttribute annotation:

@XStreamAsAttribute private String contactType; 

Alternatively, we can accomplish the same goal programmatically:

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

The output of either of the above methods is the same:

 6673543265 0124-2460311 

10. Concurrency

XStream's processing model presents some challenges. Once the instance is configured, it is thread-safe.

It is important to note that processing of annotations modifies the configuration just before marshalling/unmarshalling. And so – if we require the instance to be configured on-the-fly using annotations, it is generally a good idea to use a separate XStream instance for each thread.

11. Conclusion

In this article, we covered the basics of using XStream to convert objects to XML. We also learned about customizations we can use to ensure the XML output meets our needs. Finally, we looked at thread-safety problems with annotations.

In the next article in this series, we will learn about converting XML back to Java objects.

The complete source code for this article can be downloaded from the linked GitHub repository.