Конвертиране на POJO в XML без POJO конструктор по подразбиране

Опитвам се да конвертирам POJO (обикновен стар Java обект) в XML с помощта на java.beans.XMLEncoder. Кодът ми работи добре, но открих един интересен проблем, който възниква, когато пропусна конструктора по подразбиране в моя 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?


person Jason    schedule 01.08.2014    source източник


Отговори (3)


За съжаление JAXB (и свързаните технологии) изисква не-arg конструктор (имплицитният конструктор по подразбиране също е добре).

Съгласно спецификацията и в случай на собствена библиотека на Oracle JAX се изисква както за маршалинг, така и за демаршалинг.

Според човешката логика не е необходимо за маршалинг/сериализация. Например най-популярната JSON библиотека Jackson има такова изискване само за десериализация.

Има XML JAX съвместими парсери на трета страна, които също са по-малко ограничителни... но този проблем обикновено не е причина да се борите с библиотека на трета страна.

JAX позволява да има непубличен конструктор без аргументи. Обикновено го създавам, както следва:

/** For JAXB only. Do not call directly and do not delete! */
@Deprecated
protected NFLTeam () {
    // nothing
}
person 30thh    schedule 01.08.2014
comment
Харесва ми Javadoc, който сте поставили там. Ще следвам същия подход и занапред! - person Jason; 01.08.2014

Намерих отговора, който търсех тук . „Класът XMLEncoder е допълнителна алтернатива на ObjectOutputStream и може да се използва за генериране на текстово представяне на JavaBean “. JavaBean е ключът тук. За да може NFLTeam bean в публикувания пример да се счита за JavaBean, той се нуждае от конструктора по подразбиране, както е споменато тук. „Класът трябва да има публичен конструктор по подразбиране (без аргументи). Това позволява лесно инстанциране в рамки за редактиране и активиране.“

person Jason    schedule 01.08.2014

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

Ако даден клас не съдържа декларации на конструктор, тогава имплицитно се декларира конструктор по подразбиране без формални параметри и клауза за хвърляния.

С други думи, нулевият конструктор е имплицитен, ако няма друг n-arg конструктор. Опитайте сами:

public class Main {

    public Main(int i) {

    }

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

}

Ако не можете, XMLEncoder също.

person sp00m    schedule 01.08.2014
comment
Разбирам това, но не се опитвам да инстанцирам нов обект с конструктор по подразбиране. Вече създадох обекта и го предадох на XMLEncoder. Предполагам, че XMLEncoder е кодиран по начин, който изисква изричен конструктор по подразбиране. - person Jason; 01.08.2014
comment
Не мисля, че Java може да разграничи изричния и имплицитния n-arg конструктор. На ниво байт код трябва да изглежда абсолютно същото... - person 30thh; 01.08.2014