2012-02-13 12 views
43

Jeśli spróbujesz zebrać klasy, która odwołuje się typ złożony, który nie ma konstruktora nie-Arg, takich jak:Dlaczego JAXB potrzebuje konstruktora bez argumentów do zestawiania?

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 
} 

z realizacją JAXB, który jest częścią Java, co następuje:

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

JAXB rzuci

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

teraz rozumiem dlaczego JAXB potrzebuje żadnego-Arg konstruktora na unmarshalling - ponieważ musi instancję ob ject. Ale dlaczego JAXB potrzebuje konstruktora no-arg podczas ustawiania?

Jeszcze jedna nitka, dlaczego implementacja Java JAXB rzuca wyjątek, jeśli pole ma wartość zerową i czy i tak nie zostanie ono wysłane?

Czy brakuje mi czegoś lub czy są to tylko złe wybory wdrożeniowe w implementacji Java JAXB?

+2

To faktycznie złe wdrożenie IMHO. JAXB powinien był zrobić to, co robi Jackson i podać adnotację do argumentu konstruktora: http://www.cowtowncoder.com/blog/archives/2011/07/entry_457.html. Biorąc to pod uwagę, JAXB jest nadal dużo lepszy od innych JSR. –

Odpowiedz

22

Gdy implementacja JAXB (JSR-222) inicjuje metadane, zapewnia obsługę zarówno rozbiegania, jak i zaniku.

Dla klas POJO, które nie mają konstruktor nie-Arg można użyć poziomu typu XmlAdapter go obsłużyć:

java.sql.Date nie jest obsługiwany domyślnie (choć w EclipseLink JAXB (MOXy) to jest). To również może być obsługiwane przy użyciu XmlAdapter określony poprzez @XmlJavaTypeAdapter na polu, własności, lub poziomu pakietu:


Również inna nit, dlaczego Java Wdrożenie JAXB rzuca wyjątek , jeśli pole ma wartość zerową, i czy nie ma zamiaru uzyskać odpowiedzi na pytanie: ?

Jakiego wyjątku widzisz? Zwykle, gdy pole ma wartość zerową, nie jest uwzględniane w wyniku XML, o ile nie jest opatrzone adnotacją z @XmlElement(nillable=true), w którym to przypadku element będzie zawierał xsi:nil="true".


UPDATE

Można wykonać następujące czynności:

SqlDateAdapter

Poniżej znajduje się XmlAdapter że zamieni z java.sql.Date że realizacja JAXB nie wie, w jaki sposób obsłużyć do java.util.Date, które robi:

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

XmlAdapter jest zarejestrowany przez @XmlJavaTypeAdapter adnotacji:

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

Jeśli spróbujesz zmobilizować klasę, którą wkleiłem w pytaniu, tak jak jest, rzuci wyjątek, mimo że obiekt Date jest pusty i nawet nie będzie częścią XML. – rouble

+0

Zaktualizowałem swoją odpowiedź, dodając "XmlAdapter", którego można użyć do obsługi pola 'java.sql.Date'. –

+1

Blaise - dzięki. Już używam podobnego adaptera. Zauważ, że nie potrzebujesz kontroli zerowej w adapterze. Właśnie wskazywałem pewne interesujące rzeczy na temat implementacji JAXB w Javie, w tym, że oczekuje adaptera (i zgłasza wyjątek) - nawet jeśli pole ma wartość zerową i nie zamierza używać adaptera. Uważam to za dziwne. – rouble

-2

Niektóre przedsiębiorstwa i modele Dependency Injection używają refleksji Class.newInstance(), aby utworzyć nową instancję swoich zajęć. Ta metoda wymaga publicznego konstruktora no-arg, aby móc utworzyć instancję obiektu.

+3

dziękuję - Rozumiem to - jestem tylko ciekawy, gdzie w procesie rozstawiania istnieje potrzeba stworzenia nowej instancji prowadzonej klasy? – rouble

0

Wydaje się być pod wrażeniem, że kod introspekcja JAXB będą miały działania konkretne ścieżki dla inicjalizacji. jeśli tak, spowodowałoby to powstanie wielu duplikatów kodu i byłoby kiepską implementacją. wyobrażam sobie, że kod JAXB ma wspólną procedurę, która bada klasę modelu za pierwszym razem, gdy jest potrzebna i potwierdza, że ​​przestrzega wszystkich niezbędnych konwencji. w tej sytuacji nie działa, ponieważ jeden z członków nie ma wymaganego konstruktora no-arg. logika inicjalizacji najprawdopodobniej nie jest specyficzna dla układu typu "marshall/unmarshall", a także bardzo mało prawdopodobna jest uwzględnianie bieżącej instancji obiektu.

Powiązane problemy