没有默认POJO构造函数,如何将POJO转换为XML

4
我将尝试使用java.beans.XMLEncoder将POJO(普通旧Java对象)转换为XML。我的代码可以正常工作,但是当我省略POJO中的默认构造函数时,会出现一个有趣的问题。以下为类示例:

没有默认构造函数的POJO

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;
  }

}

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);
}

控制台输出与默认构造函数省略
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>

使用默认构造函数的控制台输出

<?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>

我在谷歌上搜索了一下,但找不到关于这个问题的解释。为什么隐式默认构造函数对于XMLEncoder来说不够?
3个回答

4
很遗憾,JAXB(及其相关技术)需要一个无参构造函数(隐式默认构造函数同样可行)。
根据规范,在本机Oracle JAX库的情况下,这对于编组和非编组都是必需的。
按照人类逻辑,它在编组/序列化时是不必要的。例如,最流行的JSON库Jackson仅在反序列化时具有此要求。
也有第三方XML JAX兼容解析器,这些解析器限制较少...但通常不需要为此与第三方库斗争。
JAX允许具有非公共非参数构造函数。我通常按以下方式创建:
/** For JAXB only. Do not call directly and do not delete! */
@Deprecated
protected NFLTeam () {
    // nothing
}

1
我喜欢你在那里放置的Javadoc。今后我会采用相同的方法! - Jason

2
我在这里找到了我需要的答案(链接)。“XMLEncoder类是ObjectOutputStream的补充替代品,可用于生成JavaBean的文本表示形式”。重点在于JavaBean。为了使发布示例中的NFLTeam bean成为JavaBean,它需要像(链接)中所提到的那样具有默认构造函数。“该类必须具有公共默认构造函数(无参数)。这使得在编辑和激活框架内轻松实例化。”请注意保留HTML标签。

1

来自http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.8.9:

如果一个类不包含构造函数声明,则会隐式声明一个没有形式参数和无throws子句的默认构造函数。

换句话说,当不存在其他n个参数的构造函数时,零元构造函数是隐式的。请自行尝试:

public class Main {

    public Main(int i) {

    }

    public static void main(String[] args) {
        new Main(); // error: the constructor Main() is undefined
    }

}

如果你不能,XMLEncoder也不能。

我理解这一点,但我并不想使用默认构造函数实例化一个新对象。我已经构建了该对象并将其传递给XMLEncoder。我猜测XMLEncoder是以需要显式默认构造函数的方式编码的。 - Jason
我认为Java无法区分显式和隐式的n-arg构造函数。在字节码级别上,它看起来完全相同... - 30thh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接