Pourquoi JAXB a-t-il besoin d’un constructeur no arg pour le marshalling?

Si vous essayez de rassembler une classe faisant référence à un type complexe qui ne possède pas de constructeur sans argument, par exemple:

import java.sql.Date; @XmlRootElement(name = "Foo") @XmlAccessorType(XmlAccessType.FIELD) public class Foo { int i; Date d; //java.sql.Date does not have a no-arg constructor } 

avec l’implémentation JAXB qui fait partie de Java, comme suit:

  Foo foo = new Foo(); JAXBContext jc = JAXBContext.newInstance(Foo.class); ByteArrayOutputStream baos = new ByteArrayOutputStream(); Marshaller marshaller = jc.createMarshaller(); marshaller.marshal(foo, baos); 

JAXB lancera un

 com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException: 1 counts of IllegalAnnotationExceptions java.sql.Date does not have a no-arg default constructor 

Maintenant, je comprends pourquoi JAXB a besoin d’un constructeur sans argument sur unmarshalling – car il doit instancier l’object. Mais pourquoi JAXB a-t-il besoin d’un constructeur sans argument lors de la mise en forme?

Aussi, une autre raison, pourquoi l’implémentation JAXB de Java jette-t-elle une exception si le champ est nul, et ne va pas être regroupé de toute façon?

Est-ce que je manque quelque chose ou est-ce que ce sont de mauvais choix d’implémentation dans l’implémentation de Java JAXB?

Lorsqu’une implémentation JAXB (JSR-222) initialise ses métadonnées, elle garantit qu’elle peut prendre en charge à la fois le regroupement et le démasquage.

Pour les classes POJO qui ne possèdent pas de constructeur no-arg, vous pouvez utiliser un XmlAdapter au niveau du type pour le gérer:

java.sql.Date n’est pas pris en charge par défaut (bien que dans EclipseLink JAXB (MOXy) il le soit). Cela peut également être géré à l’aide d’un XmlAdapter spécifié via @XmlJavaTypeAdapter au niveau du champ, de la propriété ou du package:


Aussi, une autre raison, pourquoi l’implémentation JAXB de Java jette-t-elle une exception si le champ est nul, et ne va pas être regroupé de toute façon?

Quelle exception voyez-vous? Normalement, lorsqu’un champ est nul, il n’est pas inclus dans le résultat XML, sauf s’il est annoté avec @XmlElement(nillable=true) auquel cas l’élément inclura xsi:nil="true" .


METTRE À JOUR

Vous pouvez faire ce qui suit:

SqlDateAdapter

Vous trouverez ci-dessous un XmlAdapter qui sera converti à partir du java.sql.Date que votre implémentation JAXB ne sait pas gérer avec un java.util.Date :

 package forum9268074; import javax.xml.bind.annotation.adapters.*; public class SqlDateAdapter extends XmlAdapter { @Override public java.util.Date marshal(java.sql.Date sqlDate) throws Exception { if(null == sqlDate) { return null; } return new java.util.Date(sqlDate.getTime()); } @Override public java.sql.Date unmarshal(java.util.Date utilDate) throws Exception { if(null == utilDate) { return null; } return new java.sql.Date(utilDate.getTime()); } } 

Foo

XmlAdapter est enregistré via l’annotation @XmlJavaTypeAdapter :

 package forum9268074; import java.sql.Date; import javax.xml.bind.annotation.*; import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; @XmlRootElement(name = "Foo") @XmlAccessorType(XmlAccessType.FIELD) public class Foo { int i; @XmlJavaTypeAdapter(SqlDateAdapter.class) Date d; //java.sql.Date does not have a no-arg constructor } 

Vous semblez avoir l’impression que le code d’introspection de JAXB aura des chemins spécifiques à l’action pour l’initialisation. Si tel est le cas, cela entraînerait beaucoup de code en double et serait une mauvaise mise en œuvre. J’imagine que le code JAXB a une routine commune qui examine une classe de modèle la première fois qu’il est nécessaire et valide qu’il respecte toutes les conventions nécessaires. dans cette situation, il échoue car l’un des membres n’a pas le constructeur no-arg requirejs. la logique d’initialisation n’est probablement pas spécifique à marshall / unmarshall et très peu probable pour prendre en compte l’instance d’object en cours.

Certains frameworks Enterprise et Dependency Injection utilisent la reflection Class.newInstance () pour créer une nouvelle instance de vos classes. Cette méthode nécessite un constructeur public no-arg pour pouvoir instancier l’object.