Reputation: 1431
I'm trying to convert a POJO (Plain old Java Object) into XML using java.beans.XMLEncoder. My code works fine but I found one interesting problem that occurs when I omit the default constructor in my POJO. Classes are below.
POJO without default constructor
public class NFLTeam implements Serializable {
private String name;
private String description;
// public NFLTeam() {
//
// }
public NFLTeam(String name, String description) {
this.name = name;
this.description = description;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}
Invocation of XMLEncoder
public static void main(String args[]) {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
XMLEncoder xmlEncoder = new XMLEncoder(byteArrayOutputStream);
NFLTeam team = new NFLTeam("Bears", "Play for Chicago");
xmlEncoder.writeObject(team);
xmlEncoder.close();
System.out.println(byteArrayOutputStream);
}
Console output with default constructor omitted
java.lang.InstantiationException: oce.wsd.pojos.NFLTeam
Continuing ...
java.lang.Exception: XMLEncoder: discarding statement XMLEncoder.writeObject(NFLTeam);
Continuing ...
<?xml version="1.0" encoding="UTF-8"?>
<java version="1.7.0_45" class="java.beans.XMLDecoder">
</java>
Console output with default constructor
<?xml version="1.0" encoding="UTF-8"?>
<java version="1.7.0_45" class="java.beans.XMLDecoder">
<object class="oce.wsd.pojos.NFLTeam">
<void property="description">
<string>Play for Chicago</string>
</void>
<void property="name">
<string>Bears</string>
</void>
</object>
</java>
I was googling around but cannot find any explanation for this. Why is the implicit default constructor not enough for XMLEncoder?
Upvotes: 4
Views: 1265
Reputation: 1431
I found the answer I was looking for here. "The XMLEncoder class is a complementary alternative to the ObjectOutputStream and can be used to generate a textual representation of a JavaBean ". JavaBean is the key here. In order for the NFLTeam bean in the posted example to be considered a JavaBean, it needs the default constructor as mentioned here. "The class must have a public default constructor (with no arguments). This allows easy instantiation within editing and activation frameworks."
Upvotes: 2
Reputation: 11386
Unfortunately JAXB (and linked technologies) requires a non-arg constructor (implicit default constructor is fine as well).
According to the specification and in case of native Oracle JAX library it is required for both marshaling and un-marshaling.
According to the human logic it is not needed for marshaling/serialization. For example the most popular JSON library Jackson does have such a requirement only for de-serialization.
There are third party XML JAX compatible parsers which are less restrictive as well... but this issue is usually not a reason for struggling with a third party library.
JAX allows to have a non-argument constructor non-public. I usually create it as follow:
/** For JAXB only. Do not call directly and do not delete! */
@Deprecated
protected NFLTeam () {
// nothing
}
Upvotes: 4
Reputation: 48837
From http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.8.9:
If a class contains no constructor declarations, then a default constructor with no formal parameters and no throws clause is implicitly declared.
In other words, a nullary constructor is implicit iff there is no other n-arg constructor. Try it yourself:
public class Main {
public Main(int i) {
}
public static void main(String[] args) {
new Main(); // error: the constructor Main() is undefined
}
}
If you cannot, XMLEncoder neither.
Upvotes: 1