Xml Serialization in Java

XML serialization in Java?

2008 Answer
The "Official" Java API for this is now JAXB - Java API for XML Binding. See Tutorial by Oracle. The reference implementation lives at http://jaxb.java.net/

2018 Update
Note that the Java EE and CORBA Modules are deprecated in SE in JDK9 and to be removed from SE in JDK11. Therefore, to use JAXB it will either need to be in your existing enterprise class environment bundled by your e.g. app server, or you will need to bring it in manually.

A way to serialize an into an XML with attributes in java

You can use JAXB, with @XmlAnyElement for support of elements with arbitrary names.

The following works natively with Java 8. For Java 7, the stream logic in toString() needs to be changed to regular for loop. For Java 9+, where JAXB was removed, a JAXB library is needed.

@XmlRootElement(name = "Person")
@XmlAccessorType(XmlAccessType.NONE)
class Person {

private String version;
private List<Element> properties;

@XmlAttribute
public String getVersion() {
return this.version;
}

public void setVersion(String version) {
this.version = version;
}

@XmlElementWrapper(name = "properties")
@XmlAnyElement
public List<Element> getProperties() {
return this.properties;
}

public void setProperties(List<Element> properties) {
this.properties = properties;
}

public void addProperty(String name, String value) {
try {
Element elem = DocumentBuilderFactory.newInstance()
.newDocumentBuilder().newDocument().createElement(name);
elem.setTextContent(value);
if (this.properties == null)
this.properties = new ArrayList<>();
this.properties.add(elem);
} catch (ParserConfigurationException e) {
throw new IllegalStateException(e);
}
}

@Override
public String toString() {
String propertiesAsString = this.properties.stream()
.map(e -> e.getLocalName() + ": \"" + e.getTextContent() + "\"")
.collect(Collectors.joining(", ", "[", "]"));
return "Person[version=" + this.version + ", properties=" + propertiesAsString + "]";
}

}

Test

Person person = new Person();
person.setVersion("xyz");
person.addProperty("name", " John");
person.addProperty("city", "nyc");

JAXBContext jaxbContext = JAXBContext.newInstance(Person.class);
Marshaller marshaller = jaxbContext.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
StringWriter xml = new StringWriter();
marshaller.marshal(person, xml);
System.out.println(xml);

Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
Person person2 = (Person) unmarshaller.unmarshal(new StringReader(xml.toString()));
System.out.println(person2);

Output

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Person version="xyz">
<properties>
<name> John</name>
<city>nyc</city>
</properties>
</Person>

Person[version=xyz, properties=[name: " John", city: "nyc"]]

Easy XML Serializer for Java

My vote would be for XStream. The lack of generics support is a small price to pay for the amount of flexibility it offers. You can also easily implement generics by serializing the generic class type at serialization time, or build this into your domain objects. E.g.

   class Customer
{
List<Order> orders;

public List<Order> getOrders()
{
return orders;
}
}

In the stream, the element type denotes the type of each object. When the type is an abstract type or interface, the element listed with the implementing class, unless that has been specified as the default for that interface type. (E.g. ArrayList as the default for instances of static type List.)

Generics are "rose coloured glasses" in java - they don't really change what you are seeing, just how you see it. The objects would be sent over the wire exactly the same if they were sent with generics support or not.

Manually XML-serializing a Java object

You can do

 private byte[] encode(YourObject obj)
{
byte[] bytes = null;
try
{
YourObject vsNew = new YourObject(obj)
ByteArrayOutputStream baos = new ByteArrayOutputStream();
GZIPOutputStream out = new GZIPOutputStream(baos);
XMLEncoder encoder = new XMLEncoder(out);
encoder.writeObject(vsNew);
encoder.close();
bytes = baos.toByteArray();
}
catch (Exception e)
{
_log.error("Exception caught while encoding/zipping ", e);
}
return bytes;
}

/*
* Decode the report definition blob back to the
* ScheduledReport object.
*/
private YourObject decode(byte[] bytes)
{
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
YourObject vSNew = null;
try
{
GZIPInputStream in = new GZIPInputStream(bais);
XMLDecoder decoder = new XMLDecoder(in);
vSNew = (YourObject)decoder.readObject();
decoder.close();
}
catch (Exception e)
{
_log.error("IOException caught while decoding/unzipping ", e);
}
return vSNew ;
}

Best Practice for Serialize/Deserialize from Java to XML

I've always had positive experiences with XStream:

http://x-stream.github.io/tutorial.html#to-xml

As you can see, it's simple to use.

I haven't actually used XStream with Generics (I've only ever used it for simple JavaBean type classes), but Google seems to suggest it handles them without problems. e.g. http://techo-ecco.com/blog/xstream-spring-ws-oxm-and-generics/

Serialize Object To XML in java ignores some variable fields of my object

Two things worth noting:

  1. XMLEncoder does not look at private fields. It only looks at matching pairs of 'get' and 'set' methods (or 'is' and 'set' methods). You have a getNullableState method but the set-method does not match; you should rename setNullable to setNullableState.
  2. XMLEncoder only writes values for properties which are different from their initial state. The initial state of each property is whatever value it has when the object is initially constructed.

So, one way to force a property value to be written is to make sure it has a value that's different from what it had when the object was constructed.

If you want to always write XML for every property, you may want to consider using JAXB instead of XMLEncoder.

Java+Jackson+XML: serialize a java object properties as XML elements with same names

You need to mark those properties as attributes like this:

public class Point {

@JacksonXmlProperty(isAttribute = true)
private Integer x;
@JacksonXmlProperty(isAttribute = true)
private Integer y;
//getters/setters
}


Related Topics



Leave a reply



Submit