# Serialisierung mit JAXB



## CHE123 (15. Mai 2010)

Hallo,

bin nach verzweifelter suche nun hier gelandet und hoffe, dass mir mit meinem problem geholfen werden kann...
da ich gerne JAXB als framework verwenden würde, hänge ich nun bei folgendem fest:
es gibt ein interface, eine implementierung dessen und eine klasse mit einer collection des interfaces, das soll nach xml serialisiert werden.

erste ansatz (unofficial jaxb guide):


```
public interface Animal
{
  String getName();
}
```


```
@XmlRootElement
public class Lion implements Animal
{
  private String name = "Clarence";

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

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


```
@XmlRootElement
public class Zoo
{
  @XmlElement
  public List<Animal> animals = new ArrayList<Animal>();

  public static void main(String[] args)
  {
    final Zoo zoo = new Zoo();
    zoo.animals.add(new Lion());
    
    JAXB.marshal(zoo, System.err);
  }
}
```

gibt folgende exception:


```
Exception in thread "main" javax.xml.bind.DataBindingException: com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException: 2 counts of IllegalAnnotationExceptions
test.jaxb.Animal is an interface, and JAXB can't handle interfaces.
        this problem is related to the following location:
                at test.jaxb.Animal
                at public java.util.List test.jaxb.Zoo.animals
                at test.jaxb.Zoo
test.jaxb.Animal does not have a no-arg default constructor.
        this problem is related to the following location:
                at test.jaxb.Animal
                at public java.util.List test.jaxb.Zoo.animals
                at test.jaxb.Zoo
                
usw...
```

zweiter ansatz nach ein wenig goggeln: 

adapter klasse implementiert


```
public class XmlLionAdapter extends XmlAdapter<Lion, Animal>
{
  @Override
  public Animal unmarshal(Lion v) throws Exception {
    throw new UnsupportedOperationException("Not supported yet.");
  }

  @Override
  public Lion marshal(Animal v) throws Exception {
    System.err.println(getClass().getSimpleName() + ": " + v.getClass());
    return (Lion) v;
  }
}
```

... und die anderen klassen entsprechend annotiert


```
@XmlJavaTypeAdapter(value=XmlLionAdapter.class) //<=== added
public interface Animal
{
  String getName();
}
```


```
@XmlRootElement
public class Zoo
{
  @XmlElement
  @XmlJavaTypeAdapter(value=XmlLionAdapter.class) //<=== added
  public List<Animal> animals = new ArrayList<Animal>();

  public static void main(String[] args)
  {
    final Zoo zoo = new Zoo();
    zoo.animals.add(new Lion());
    
    JAXB.marshal(zoo, System.err);
  }
}
```

die marshal-methode des adapters wird auch ausgeführt, allerdings kommt es zu folgendem 
ergebnis:

[XML]<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<zoo>
    <animals name="Clarence"/>
</zoo>
[/XML]

erwartet wäre allerdings nicht *animals *sonder *lion*, also
[XML]
...
    <lion name="Clarence"/>
...
[/XML]

bin für jede hilfe dankbar,

mfg,
christian


----------



## Noctarius (15. Mai 2010)

Du hast den XmlAdapter genau verkehrt rum mit Generics versehen würde ich jetzt auf den ersten Blick sagen.


----------



## kidsos (15. Mai 2010)

Der entscheidende Punkt ist hier:

```
@XmlElement
public List<Animal> animals = new ArrayList<Animal>();
```
Der XML-Tag bildet sich hier aus dem Variablennamen. Durch 
	
	
	
	





```
@XmlElement(name = "lion")
```
 kannst du die XML-Ausgabe beeinflussen und damit auf "lion" umstellen.


----------



## CHE123 (15. Mai 2010)

Danke für die Antworten!

@Nocatrius

Das Vertauschen der Argumente gibt leider folgende Exception:


```
Exception in thread "main" javax.xml.bind.DataBindingException: com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException: 3 counts of IllegalAnnotationExceptions
Adapter test.jaxb.XmlLionAdapter is not applicable to the field type java.util.List<test.jaxb.Animal>. 
        this problem is related to the following location:
                at @javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter(type=class javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter$DEFAULT, value=class test.jaxb.XmlLionAdapter)
                at public java.util.List test.jaxb.Zoo.animals
                at test.jaxb.Zoo
usw...
```

@kidsos

Das ist schon richtig, allerdings hab ich noch Tiger und Bären im Zoo, die migrieren dann alle zu Löwen

mfg,
Christian


----------



## kidsos (15. Mai 2010)

Ich an deiner Stelle würde das Interface in eine abstrakte Basisklasse überführen. Die jeweiligen Tiere erben dann von Animal. Dadurch kannst du das dann beliebig erweitern. Ein schönes Beispiel, wie man dann Objekte vom Basistyp in eine Liste aufnehmen kann, ist z.B. hier (letzter Punkt "Hierarchien setzen" dürfte für dich interessant sein) erklärt.

Außerdem hast du ja noch das Problem mit dem XMLTypeAdapter. In deinem Fall wäre der ja nur für Lion-Objekte anwendbar. Für andere Objekte ginge das nicht.

Hoffe, dass dir das weiterhilft.


----------



## CHE123 (15. Mai 2010)

Hi,

@kidsos

yep:toll:! der schmäh is


```
...
  @XmlElementRefs({
    @XmlElementRef(type=Lion.class),
    @XmlElementRef(type=Tiger.class)
  })
  public List<Animal> animals = new ArrayList<Animal>();
  ...
```

>>>

[XML]
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<zoo>
    <lion name="Clarence"/>
    <tiger name="Blunzn"/>
</zoo>[/XML]
da kann *Animal *ruhig ein _interface _bleiben und muss keine abstrakte Klasse werden... 

Hab Dank! nu gehts ans deserialisieren...

EDIT: unmarshalling funktioniert auch!

mfg,
Christian


----------



## Noctarius (15. Mai 2010)

Ahh cool das kannte ich auch noch nicht. Muss ich mir mal merken, auch wenn ich es an sich für unschön halte wenn man das extra noch deklarieren muss.


----------

