杰瑞科技汇

Java XMLSerializer如何高效处理XML序列化?

Of course! Let's dive deep into java.beans.XMLEncoder and XMLDecoder, which is the standard Java way for "XML serialization" of JavaBeans. This is often referred to as "long-term persistence" because it's designed to save and restore the complete state of a Java object graph in a human-readable, version-tolerant format.

Java XMLSerializer如何高效处理XML序列化?-图1
(图片来源网络,侵删)

What is XMLEncoder / XMLDecoder?

The java.beans package provides two classes for serializing Java objects to XML and deserializing them back:

  • XMLEncoder: A class that writes a JavaBeans object graph to an XML document. It's the counterpart to java.io.ObjectOutputStream, but for XML.
  • XMLDecoder: A class that reads an XML document created by XMLEncoder and reconstructs the corresponding Java object graph. It's the counterpart to java.io.ObjectInputStream.

Key Characteristics

  • For JavaBeans: It's specifically designed for classes that follow the JavaBeans conventions (a no-arg constructor, getters, and setters).
  • Declarative, Not Imperative: Unlike ObjectOutputStream which records the sequence of method calls made on an object, XMLEncoder records the state of the object. It looks at the public API (getters/setters) to figure out how to save and restore the object.
  • Human-Readable: The output is XML, which you can read, edit, and debug.
  • Version-Tolerant: This is a huge advantage. If you add a new property to a class, the XMLDecoder will often be able to load an old XML file and simply ignore the missing property. ObjectOutputStream is much more brittle in this regard.
  • Not for Arbitrary Objects: It doesn't work with just any Serializable object like ObjectOutputStream. It relies on the JavaBeans pattern. For arbitrary objects, JAXB or Jackson are better choices.

How It Works: The Process

Serialization with XMLEncoder

The process involves creating an XMLEncoder that writes to an OutputStream (like a FileOutputStream), and then calling its writeObject() method.

Steps:

  1. Create an XMLEncoder instance, specifying an OutputStream.
  2. Call encoder.writeObject(yourObject) on the object you want to serialize.
  3. Call encoder.close() to flush and close the stream.

Deserialization with XMLDecoder

The process is the reverse. You create an XMLDecoder that reads from an InputStream (like a FileInputStream), and then call its readObject() method.

Java XMLSerializer如何高效处理XML序列化?-图2
(图片来源网络,侵删)

Steps:

  1. Create an XMLDecoder instance, specifying an InputStream.
  2. Call decoder.readObject() to get the top-level object from the XML file.
  3. Call decoder.close() when you're done.

Code Example

Let's create a simple Person class that adheres to the JavaBeans convention and then serialize and deserialize it.

Step 1: The JavaBean Class

// Person.java
import java.util.ArrayList;
import java.util.List;
public class Person {
    // 1. A no-arg constructor is required!
    public Person() {
    }
    private String name;
    private int age;
    private List<String> hobbies;
    // 2. Private fields with public getters and setters
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public List<String> getHobbies() {
        if (hobbies == null) {
            hobbies = new ArrayList<>();
        }
        return hobbies;
    }
    public void setHobbies(List<String> hobbies) {
        this.hobbies = hobbies;
    }
    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", hobbies=" + hobbies +
                '}';
    }
}

Step 2: The Serialization and Deserialization Code

// XMLEncoderDemo.java
import java.beans.XMLDecoder;
import java.beans.XMLEncoder;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Arrays;
public class XMLEncoderDemo {
    public static void main(String[] args) {
        // --- 1. Create an object to serialize ---
        Person person = new Person();
        person.setName("Alice");
        person.setAge(30);
        person.setHobbies(Arrays.asList("Reading", "Hiking", "Coding"));
        System.out.println("Original object: " + person);
        // --- 2. Serialize the object to an XML file ---
        String xmlFilePath = "person.xml";
        try (XMLEncoder encoder = new XMLEncoder(new FileOutputStream(xmlFilePath))) {
            encoder.writeObject(person);
            System.out.println("Object successfully serialized to " + xmlFilePath);
        } catch (IOException e) {
            e.printStackTrace();
        }
        // --- 3. Deserialize the object from the XML file ---
        Person deserializedPerson = null;
        try (XMLDecoder decoder = new XMLDecoder(new FileInputStream(xmlFilePath))) {
            deserializedPerson = (Person) decoder.readObject();
            System.out.println("Object successfully deserialized from " + xmlFilePath);
        } catch (IOException e) {
            e.printStackTrace();
        }
        // --- 4. Verify the deserialized object ---
        if (deserializedPerson != null) {
            System.out.println("Deserialized object: " + deserializedPerson);
            System.out.println("Are they equal? " + person.equals(deserializedPerson)); // Note: You might need to implement equals()
        }
    }
}

Step 3: The Generated XML Output

After running the code, a file named person.xml will be created with the following content:

<?xml version="1.0" encoding="UTF-8"?>
<java version="17.0.2" class="java.beans.XMLDecoder">
 <object class="Person">
  <void property="age">
   <int>30</int>
  </void>
  <void property="hobbies">
   <object class="java.util.ArrayList">
    <void method="add">
     <string>Reading</string>
    </void>
    <void method="add">
     <string>Hiking</string>
    </void>
    <void method="add">
     <string>Coding</string>
    </void>
   </object>
  </void>
  <void property="name">
   <string>Alice</string>
  </void>
 </object>
</java>

As you can see, the XML is very descriptive. It creates a Person object and then calls the setAge, setHobbies, and setName methods (represented as <void property="...">) to restore its state.


Limitations and Alternatives

When to Avoid XMLEncoder:

  1. Performance: It is significantly slower than ObjectOutputStream because it generates text-based XML and has more complex logic.
  2. Not for General Serialization: It only works with JavaBeans. You cannot use it to serialize a java.net.Socket or a java.lang.Thread. For these, ObjectOutputStream is the standard.
  3. Complexity with Non-Bean Objects: If your object graph contains non-bean objects, you may need to register custom persistence delegates, which can become complicated.

Better Alternatives:

For modern applications, especially those involving web services or APIs, other technologies are preferred.

Technology Use Case Key Features
XMLEncoder/XMLDecoder Saving application settings, UI state, or "long-term persistence" of JavaBeans in a human-readable format. - Built into Java SE
- Human-readable
- Version-tolerant
- Only for JavaBeans
ObjectOutputStream General-purpose binary serialization for RMI, storing objects to a file/DB, or network transmission. - Very fast and compact
- Part of Java since v1.1
- Brittle across JVM versions
JAXB (Java Architecture for XML Binding) Mapping Java classes to XML for web services (SOAP, REST) and data interchange. - Standard (JSR-222)
- Annotated (@XmlRootElement, etc.)
- Schema generation (xsd)
- Better for complex data structures
Jackson / Gson The de-facto standard for JSON processing in Java. Can also be configured for XML. - Extremely fast and popular
- Excellent for web APIs
- Flexible configuration
- Can handle non-bean objects

Summary

Feature XMLEncoder ObjectOutputStream JAXB / Jackson
Format XML Binary JSON (or XML for JAXB)
Primary Use Long-term persistence of UI/JavaBeans General-purpose RMI/network/file storage Web APIs, Data Interchange
Readability High None JSON is readable, XML is readable
Performance Slow Fast Very Fast
Flexibility Low (JavaBeans only) Medium (any Serializable) High (annotations, custom logic)
Tolerance High (version-tolerant) Low (brittle) Medium

For simple, human-readable persistence of standard JavaBeans, XMLEncoder is a solid choice. For almost everything else, especially performance-critical or web-related tasks, look to ObjectOutputStream or, more likely, modern libraries like Jackson or JAXB.

分享:
扫描分享到社交APP
上一篇
下一篇