2012-02-13 9 views
43

Se si tenta di schierare una classe che fa riferimento a un tipo complesso che non ha un costruttore no-arg, come ad esempio:Perché JAXB ha bisogno di un costruttore no arg per il marshalling?

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 l'attuazione JAXB che fa parte di Java, come segue:

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

JAXB lancerà una

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

Ora, capisco perché JAXB ha bisogno di un costruttore no-arg on unmarshalling - perché ha bisogno di creare un'istanza del ob Ject. Ma perché JAXB ha bisogno di un costruttore no-arg durante il marshalling?

Inoltre, un altro pidocchio, perché l'implementazione JAXB di Java lancia un'eccezione se il campo è nullo e non verrà comunque eseguito il marshalling?

Mi manca qualcosa o sono solo delle cattive scelte di implementazione nell'implementazione JAXB di Java?

+2

In realtà è un'implementazione errata IMHO. JAXB avrebbe dovuto fare quello che Jackson fa e offrire un'annotazione argomento costruttore: http://www.cowtowncoder.com/blog/archives/2011/07/entry_457.html. Detto questo, JAXB è ancora molto meglio di altri JSR. –

risposta

22

Quando un'implementazione di JAXB (JSR-222) inizializza i suoi metadati, assicura che sia in grado di supportare sia il marshalling che lo smantellamento.

Per le classi POJO che non dispongono di un costruttore no-arg è possibile utilizzare un livello di tipo XmlAdapter di gestire la cosa:

java.sql.Date non è supportata di default (anche se in EclipseLink JAXB (MOXy) è). Questo può anche essere gestito usando un XmlAdapter specificato tramite @XmlJavaTypeAdapter al campo, la proprietà o livello di pacchetto:


Inoltre, un altro nit, perché Java L'implementazione JAXB genera un'eccezione se il campo è nullo e non verrà eseguito il marshalling in ogni caso?

Che eccezione vedi? Normalmente quando un campo è nullo non è incluso nel risultato XML, a meno che non sia annotato con @XmlElement(nillable=true) nel qual caso l'elemento includerà xsi:nil="true".


UPDATE

Si potrebbe fare la seguente:

SqlDateAdapter

seguito è riportato un XmlAdapter che convertirà dalla java.sql.Date che l'implementazione JAXB non sa come per gestire a un java.util.Date che fa:

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

Il XmlAdapter è registrato tramite il @XmlJavaTypeAdapter annotazione:

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 
} 
+0

Se si tenta di eseguire il marshalling della classe che ho incollato nella domanda così com'è, genererà un'eccezione, anche se l'oggetto Date è nullo e non sarà nemmeno parte dell'XML. – rouble

+0

Ho aggiornato la mia risposta per includere un 'XmlAdapter' che potresti usare per gestire il campo' java.sql.Date'. –

+1

Blaise - grazie. Ho già usato un adattatore simile. Si noti che non è necessario il controllo nullo nell'adattatore. Stavo solo indicando alcune cose interessanti sull'implementazione JAXB di Java, in quanto prevede un adattatore (e genera un'eccezione), anche se il campo è nullo e non utilizzerà l'adattatore. Lo trovo strano. – rouble

-2

Alcune strutture aziendali e Dependency Injection utilizzano la riflessione Class.newInstance() per creare una nuova istanza delle classi. Questo metodo richiede un costruttore no-arg pubblico per essere in grado di creare un'istanza dell'oggetto.

+3

grazie - Capisco che - sono solo curioso di sapere, dove nel processo di marshalling c'è la necessità di creare una nuova istanza della classe da sottoporre a marshalling? – rouble

0

ti sembra di essere sotto l'impressione che il codice introspezione JAXB avrà percorsi specifici di azione per l'inizializzazione. in caso affermativo, ciò comporterebbe un sacco di codice duplicato e sarebbe una cattiva implementazione. Immagino che il codice JAXB abbia una routine comune che esamina la classe del modello la prima volta che è necessaria e convalida che segue tutte le convenzioni necessarie. in questa situazione, non funziona perché uno dei membri non ha il costruttore no-arg richiesto. molto probabilmente la logica di inizializzazione non è specifica del marshall/unmarshall ed è altamente improbabile prendere in considerazione l'istanza dell'oggetto corrente.

Problemi correlati