杰瑞科技汇

Java XML用XStream如何高效转换对象?

Of course! Here is a comprehensive guide to using XStream in Java for XML processing.

Java XML用XStream如何高效转换对象?-图1
(图片来源网络,侵删)

What is XStream?

XStream is a simple library to serialize Java objects to XML and deserialize XML back to Java objects. Its key features are:

  • Simplicity: It requires no mappings or configuration for most common use cases.
  • Flexibility: It can be customized extensively for complex scenarios.
  • Bi-directional: It handles both serialization (Object -> XML) and deserialization (XML -> Object).
  • Clean XML: By default, it produces clean, readable, and well-formatted XML.
  • No Dependencies: It has no external dependencies, making it very easy to add to a project.

Adding XStream to Your Project

You'll need to include the XStream JAR file in your project's classpath.

For Maven:

Add this dependency to your pom.xml:

<dependency>
    <groupId>com.thoughtworks.xstream</groupId>
    <artifactId>xstream</artifactId>
    <version>1.4.20</version> <!-- Check for the latest version -->
</dependency>

For Gradle:

Add this dependency to your build.gradle:

Java XML用XStream如何高效转换对象?-图2
(图片来源网络,侵删)
implementation 'com.thoughtworks.xstream:xstream:1.4.20' // Check for the latest version

Basic Serialization: Java Object to XML

Let's start with a simple Java class and convert an instance of it to an XML string.

Step 1: Create a Java POJO (Plain Old Java Object)

public class User {
    private String username;
    private int age;
    private String email;
    // A no-arg constructor is required for XStream to create the object
    public User() {}
    public User(String username, int age, String email) {
        this.username = username;
        this.age = age;
        this.email = email;
    }
    // Getters and Setters (optional but good practice)
    public String getUsername() { return username; }
    public void setUsername(String username) { this.username = username; }
    public int getAge() { return age; }
    public void setAge(int age) { this.age = age; }
    public String getEmail() { return email; }
    public void setEmail(String email) { this.email = email; }
    // Override toString() for easy printing of the object
    @Override
    public String toString() {
        return "User{" +
                "username='" + username + '\'' +
                ", age=" + age +
                ", email='" + email + '\'' +
                '}';
    }
}

Step 2: Serialize the Object to XML

import com.thoughtworks.xstream.XStream;
public class XStreamExample {
    public static void main(String[] args) {
        // 1. Create an XStream instance
        XStream xstream = new XStream();
        // 2. Create an object to serialize
        User user = new User("john_doe", 30, "john.doe@example.com");
        // 3. Convert the object to an XML string
        // The toXML() method does the magic
        String xml = xstream.toXML(user);
        // 4. Print the XML
        System.out.println("--- Serialization to XML ---");
        System.out.println(xml);
    }
}

Expected Output:

--- Serialization to XML ---
<com.example.User>
  <username>john_doe</username>
  <age>30</age>
  <email>john.doe@example.com</email>
</com.example.User>

By default, XStream uses the full class name as the root element name. We can customize this.


Basic Deserialization: XML to Java Object

Now, let's take the XML string we just generated and convert it back into a User object.

import com.thoughtworks.xstream.XStream;
public class XStreamDeserializationExample {
    public static void main(String[] args) {
        // The XML string from the previous example
        String xml = "<com.example.User>\n" +
                     "  <username>john_doe</username>\n" +
                     "  <age>30</age>\n" +
                     "  <email>john.doe@example.com</email>\n" +
                     "</com.example.User>";
        // 1. Create an XStream instance
        XStream xstream = new XStream();
        // 2. Convert the XML string back to an object
        // The fromXML() method does the magic
        Object obj = xstream.fromXML(xml);
        // 3. Cast the object to the correct type
        User user = (User) obj;
        // 4. Print the object to verify
        System.out.println("--- Deserialization from XML ---");
        System.out.println(user);
        System.out.println("Username: " + user.getUsername());
        System.out.println("Age: " + user.getAge());
    }
}

Expected Output:

--- Deserialization from XML ---
User{username='john_doe', age=30, email='john.doe@example.com'}
Username: john_doe
Age: 30

Customizing the XML Output

The default XML is functional but not always ideal. XStream offers several ways to customize it.

Java XML用XStream如何高效转换对象?-图3
(图片来源网络,侵删)

a) Aliasing Class Names

The full class name <com.example.User> is verbose. We can give it a shorter, more readable name.

XStream xstream = new XStream();
// Alias the User class to a simpler XML element name
xstream.alias("user", User.class);
User user = new User("jane_doe", 28, "jane.doe@example.com");
String xml = xstream.toXML(user);
System.out.println(xml);

Output:

<user>
  <username>jane_doe</username>
  <age>28</age>
  <email>jane.doe@example.com</email>
</user>

b) Aliasing Fields/Attributes

We can also rename the fields within the XML.

XStream xstream = new XStream();
xstream.alias("user", User.class);
xstream.aliasField("name", User.class, "username"); // <name> instead of <username>
User user = new User("peter", 45, "peter@example.com");
String xml = xstream.toXML(user);
System.out.println(xml);

Output:

<user>
  <name>peter</name>
  <age>45</age>
  <email>peter@example.com</email>
</user>

c) Converting Fields to Attributes

Instead of elements, you can make fields appear as XML attributes.

XStream xstream = new XStream();
xstream.alias("user", User.class);
xstream.useAttributeFor(User.class, "username"); // Make username an attribute
User user = new User("alice", 32, "alice@example.com");
String xml = xstream.toXML(user);
System.out.println(xml);

Output:

<user username="alice">
  <age>32</age>
  <email>alice@example.com</email>
</user>

Handling Collections (Lists)

XStream handles collections like List, Set, and Map seamlessly.

Step 1: Create a Class with a List

import java.util.ArrayList;
import java.util.List;
public class Department {
    private String name;
    private List<User> employees;
    public Department(String name) {
        this.name = name;
        this.employees = new ArrayList<>();
    }
    public void addEmployee(User user) {
        employees.add(user);
    }
    // Getters
    public String getName() { return name; }
    public List<User> getEmployees() { return employees; }
}

Step 2: Serialize the Department Object

XStream xstream = new XStream();
xstream.alias("department", Department.class);
xstream.alias("user", User.class);
xstream.useAttributeFor(User.class, "username");
Department dept = new Department("Engineering");
dept.addEmployee(new User("bob", 40, "bob@eng.com"));
dept.addEmployee(new User("carol", 35, "carol@eng.com"));
String xml = xstream.toXML(dept);
System.out.println("--- Serializing a List ---");
System.out.println(xml);

Expected Output:

--- Serializing a List ---
<department>
  <name>Engineering</name>
  <employees>
    <user username="bob">
      <age>40</age>
      <email>bob@eng.com</email>
    </user>
    <user username="carol">
      <age>35</age>
      <email>carol@eng.com</email>
    </user>
  </employees>
</department>

Security Considerations

XStream is powerful, but this power comes with a security warning. By default, XStream can deserialize any class from the classpath, which could lead to Remote Code Execution (RCE) if you process untrusted XML.

You must configure XStream to only allow the types you expect.

The Safe Way: Whitelist Allowed Types

import com.thoughtworks.xsecurity.Security;
public class SecureXStreamExample {
    public static void main(String[] args) {
        // 1. Create XStream
        XStream xstream = new XStream();
        // 2. IMPORTANT: Configure a security framework
        // This is the most critical step for security
        // A simple way is to use the built-in allowTypesByWildcard
        xstream.allowTypesByWildcard(new String[] {
            "com.example.**" // Allow any class in the com.example package
        });
        // Now, you can serialize/deserialize safely
        User user = new User("safe_user", 25, "safe@example.com");
        String xml = xstream.toXML(user);
        System.out.println(xml);
        User deserializedUser = (User) xstream.fromXML(xml);
        System.out.println(deserializedUser);
    }
}

For production applications, consider using more robust security frameworks like OVal or Javax Validation with XStream for a more fine-grained control over allowed types and fields.


Alternative: Using Annotations

XStream can also be configured using annotations directly on your Java classes. This keeps the configuration close to the code.

import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.annotations.XStreamAsAttribute;
@XStreamAlias("user") // This is equivalent to xstream.alias("user", User.class.class);
public class AnnotatedUser {
    @XStreamAsAttribute // This is equivalent to xstream.useAttributeFor(User.class, "id");
    private long id;
    private String name;
    private String email;
    public AnnotatedUser(long id, String name, String email) {
        this.id = id;
        this.name = name;
        this.email = email;
    }
    // Getters and Setters...
    @Override
    public String toString() {
        return "AnnotatedUser{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", email='" + email + '\'' +
                '}';
    }
}

Now, you just need to tell XStream to process these annotations.

public class AnnotationExample {
    public static void main(String[] args) {
        XStream xstream = new XStream();
        xstream.processAnnotations(AnnotatedUser.class); // Enable annotation processing
        AnnotatedUser user = new AnnotatedUser(101L, "annotated_user", "user@annotated.com");
        String xml = xstream.toXML(user);
        System.out.println("--- Using Annotations ---");
        System.out.println(xml);
        AnnotatedUser deserializedUser = (AnnotatedUser) xstream.fromXML(xml);
        System.out.println(deserializedUser);
    }
}

Expected Output:

--- Using Annotations ---
<user id="101">
  <name>annotated_user</name>
  <email>user@annotated.com</email>
</user>
AnnotatedUser{id=101, name='annotated_user', email='user@annotated.com'}

Summary

Task XStream API / Configuration
Create Instance XStream xstream = new XStream();
Serialize (Object -> XML) String xml = xstream.toXML(myObject);
Deserialize (XML -> Object) MyObject obj = (MyObject) xstream.fromXML(xml);
Alias Class xstream.alias("user", User.class);
Alias Field xstream.aliasField("name", User.class, "username");
Make Field an Attribute xstream.useAttributeFor(User.class, "username");
Process Annotations xstream.processAnnotations(MyClass.class);
Security (Whitelist) xstream.allowTypesByWildcard(new String[]{"com.example.**"});
分享:
扫描分享到社交APP
上一篇
下一篇