2012-08-15 16 views
9

Speriamo che un compito facile per gli esperti JAXB:XmlJavaTypeAdapter non essere rilevato

Sto cercando di schierare una classe immutabile, che fa non definire un costruttore no-arg predefinito. Ho definito un'implementazione XmlAdapter ma non sembra essere stata prelevata. Ho messo insieme un semplice esempio autosufficiente, che ancora non funziona. Qualcuno può consigliare quello che sto facendo di sbagliato?

Classe Immutabile

@XmlJavaTypeAdapter(FooAdapter.class) 
@XmlRootElement 
public class Foo { 
    private final String name; 
    private final int age; 

    public Foo(String name, int age) { 
    this.name = name; 
    this.age = age; 
    } 

    public String getName() { return name; } 
    public int getAge() { return age; } 
} 

Adapter e Valore Tipo

public class FooAdapter extends XmlAdapter<AdaptedFoo, Foo> { 
    public Foo unmarshal(AdaptedFoo af) throws Exception { 
    return new Foo(af.getName(), af.getAge()); 
    } 

    public AdaptedFoo marshal(Foo foo) throws Exception { 
    return new AdaptedFoo(foo); 
    } 
} 

class AdaptedFoo { 
    private String name; 
    private int age; 

    public AdaptedFoo() {} 

    public AdaptedFoo(Foo foo) { 
    this.name = foo.getName(); 
    this.age = foo.getAge(); 
    } 

    @XmlAttribute 
    public String getName() { return name; } 
    public void setName(String name) { this.name = name; } 

    @XmlAttribute 
    public int getAge() { return age; } 
    public void setAge(int age) { this.age = age; } 
} 

Marshaller

public class Marshal { 
    public static void main(String[] args) { 
    Foo foo = new Foo("Adam", 34); 

    try { 
     JAXBContext jaxbContext = JAXBContext.newInstance(Foo.class); 
     Marshaller jaxbMarshaller = jaxbContext.createMarshaller(); 

     // output pretty printed 
     jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); 

     jaxbMarshaller.marshal(foo, System.out);    
    } catch (JAXBException e) { 
     e.printStackTrace(); 
    } 
    } 
} 

Stack Trace

com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException: 1 counts of IllegalAnnotationExceptions 
Foo does not have a no-arg default constructor. 
     this problem is related to the following location: 
       at Foo 

     at com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException$Builder.check(IllegalAnnotationsException.java:91) 
     at com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl.getTypeInfoSet(JAXBContextImpl.java:451) 
     at com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl.<init>(JAXBContextImpl.java:283) 
     at com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl.<init>(JAXBContextImpl.java:126) 
     at com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl$JAXBContextBuilder.build(JAXBContextImpl.java:1142) 
     at com.sun.xml.internal.bind.v2.ContextFactory.createContext(ContextFactory.java:130) 
     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) 
     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
     at java.lang.reflect.Method.invoke(Method.java:601) 
     at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:248) 
     at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:235) 
     at javax.xml.bind.ContextFinder.find(ContextFinder.java:445) 
     at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:637) 
     at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:584) 
     at Marshal2.main(Marshal2.java:11) 

Nota che sto usando JDK 1.7.0_05.

risposta

7

segue dovrebbe aiutare:

FOO AS oggetto principale

Quando @XmlJavaTypeAdapter viene specificato a livello tipo si applica solo a campi/proprietà riferimento a tale classe, e non quando un'istanza di quella classe è un oggetto radice nella struttura XML. Ciò significa che dovrai convertire da te Foo a AdaptedFoo e creare lo JAXBContext su AdaptedFoo e non su Foo.

maresciallo

package forum11966714; 

import javax.xml.bind.*; 

public class Marshal { 
    public static void main(String[] args) { 
     Foo foo = new Foo("Adam", 34); 

     try { 
     JAXBContext jaxbContext = JAXBContext.newInstance(AdaptedFoo.class); 
     Marshaller jaxbMarshaller = jaxbContext.createMarshaller(); 

     // output pretty printed 
     jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); 

     jaxbMarshaller.marshal(new AdaptedFoo(foo), System.out);    
     } catch (JAXBException e) { 
     e.printStackTrace(); 
     } 
    } 
    } 

AdaptedFoo

Sarà necessario aggiungere un @XmlRootElement un'annotazione alla classe AdaptedFoo. È possibile rimuovere la stessa annotazione dalla classe Foo.

package forum11966714; 

import javax.xml.bind.annotation.*; 

@XmlRootElement 
class AdaptedFoo { 
    private String name; 
    private int age; 

    public AdaptedFoo() { 
    } 

    public AdaptedFoo(Foo foo) { 
     this.name = foo.getName(); 
     this.age = foo.getAge(); 
    } 

    @XmlAttribute 
    public String getName() { 
     return name; 
    } 

    public void setName(String name) { 
     this.name = name; 
    } 

    @XmlAttribute 
    public int getAge() { 
     return age; 
    } 

    public void setAge(int age) { 
     this.age = age; 
    } 
} 

FOO AS oggetto nidificato

Quando Foo non è il tutto oggetto principale funziona il modo in cui lo avete mappato. Ho esteso il tuo modello per dimostrare come funzionerebbe.

Bar

package forum11966714; 

import javax.xml.bind.annotation.XmlRootElement; 

@XmlRootElement 
public class Bar { 

    private Foo foo; 

    public Foo getFoo() { 
     return foo; 
    } 

    public void setFoo(Foo foo) { 
     this.foo = foo; 
    } 

} 

Demo

Si noti che l'implementazione di riferimento JAXB non ti consente di specificare la classe Foo quando bootstrapping la JAXBContext.

package forum11966714; 

import java.io.File; 

import javax.xml.bind.JAXBContext; 
import javax.xml.bind.JAXBException; 
import javax.xml.bind.Marshaller; 
import javax.xml.bind.Unmarshaller; 

public class Demo { 
    public static void main(String[] args) { 
     try { 
      JAXBContext jaxbContext = JAXBContext.newInstance(Bar.class); 

      Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller(); 
      File xml = new File("src/forum11966714/input.xml"); 
      Bar bar = (Bar) jaxbUnmarshaller.unmarshal(xml); 

      Marshaller jaxbMarshaller = jaxbContext.createMarshaller(); 
      jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); 
      jaxbMarshaller.marshal(bar, System.out); 
     } catch (JAXBException e) { 
      e.printStackTrace(); 
     } 
    } 
} 

input.xml/Output

<?xml version="1.0" encoding="UTF-8"?> 
<bar> 
    <foo name="Jane Doe" age="35"/> 
</bar> 
+1

Grazie Blaise! (Penso che fosse il tuo blog che stavo originariamente guardando). Sembra che il problema consistesse nel specificare Foo.class nel JAXBContext durante il bootstrap. Vergogna JAXB non funziona a questo punto che ho specificato un adattatore per Foo ... rende il bootstrap un po 'complicato. – Adamski

Problemi correlati