¿Por qué JAXB necesita un constructor no arg para marshalling?


Si intenta combinar una clase que hace referencia a un tipo complejo que no tiene un constructor no-arg, como:

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
}

Con la implementación JAXB que es parte de Java, de la siguiente manera:

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

JAXB lanzará un

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

Ahora, entiendo por qué JAXB necesita un constructor no-arg en unmarshalling - porque necesita instanciar el objeto. Pero, ¿por qué JAXB necesita un constructor no-arg durante el marshalling?

También, otro nit, ¿por qué JAXB de Java implementación lanzar una excepción si el campo es null, y no va a ser marshalled de todos modos?

¿Me estoy perdiendo algo o son solo malas opciones de implementación en la implementación JAXB de Java?

Author: bluish, 2012-02-14

3 answers

Cuando un JAXB (JSR-222) la implementación inicializa sus metadatos y se asegura de que pueda admitir tanto marshalling como unshalling.

Para las clases POJO que no tienen un constructor no-arg, puede usar un nivel de tipo XmlAdapter para manejarlo:

java.sql.Date no es compatible de forma predeterminada (aunque en EclipseLink JAXB (MOXy) lo es). Esto también se puede manejar usando un XmlAdapter especificado a través de @XmlJavaTypeAdapter a nivel de campo, propiedad o paquete:


También, otro nit, ¿por qué la implementación JAXB de Java arroja un excepción si el campo es null, y no va a ser marshalled de todos modos?

¿Qué ¿estás viendo una excepción? Normalmente cuando un campo es null no se incluye en el resultado XML, a menos que esté anotado con @XmlElement(nillable=true) en cuyo caso el elemento incluirá xsi:nil="true".


UPDATE

Puedes hacer lo siguiente: {[18]]}

SqlDateAdapter

A continuación se muestra un XmlAdapter que se convertirá del java.sql.Date que su implementación JAXB no sabe cómo manejar a un java.util.Date que lo hace:

package forum9268074;

import javax.xml.bind.annotation.adapters.*;

public class SqlDateAdapter extends XmlAdapter<java.util.Date, java.sql.Date> {

    @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

El XmlAdapter se registra mediante la anotación @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
}
 22
Author: Blaise Doughan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-02-14 00:55:41

Parece tener la impresión de que el código de introspección de JAXB tendrá rutas específicas de acción para la inicialización. si es así, eso resultaría en una gran cantidad de código duplicado y sería una implementación pobre. me imagino que el código JAXB tiene una rutina común que examina una clase modelo la primera vez que se necesita y valida que sigue todas las convenciones necesarias. en esta situación, está fallando porque uno de los miembros no tiene el no-arg requerido constructor. es muy probable que la lógica de inicialización no sea específica de marshall/unmarshall y también es muy poco probable que tenga en cuenta la instancia del objeto actual.

 0
Author: jtahlborn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-02-13 21:43:46

Algunos frameworks enterprise y Dependency Injection utilizan la clase reflection .newInstance () para crear una nueva instancia de tus clases. Este método requiere un constructor público no-arg para poder instanciar el objeto.

 -2
Author: fiction,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-02-13 21:25:12