# JAXB und Maps -> Marshalling-Problem



## kidsos (15. Apr 2010)

Hallo,

ich baue mir zur Zeit eine Anwendung zusammen, die mit XML-Daten operiert. Dabei habe ich folgendes Grundgerüst:

```
@XmlRootElement(name = "jobApplications")
@XmlAccessorType(XmlAccessType.NONE)
public class ApplicationList {

	private Map<String, ApplicationItem> itemHashMap;

	public ApplicationList() {
		itemHashMap = new HashMap<String, ApplicationItem>();
	}

	public void setItemHashMap(Map<String, ApplicationItem> itemHashMap) {
		this.itemHashMap = itemHashMap;
	}

	@XmlJavaTypeAdapter(CompanyListAdapter.class)
	@XmlElement(name = "company")
	public Map<String, ApplicationItem> getItemHashMap() {
		return itemHashMap;
	}
}
```


```
@XmlAccessorType(XmlAccessType.NONE)
public class ApplicationItem {
	private String id;

	public ApplicationItem() {
	}

	@XmlAttribute
	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}
}
```
Da das Marshalling bzw. Unmarshalling von Maps ja so nicht direkt geht, habe ich mir dazu eine Adapter-Klasse erstellt, die folgendermaßen aussieht:

```
public class CompanyListAdapter extends
		XmlAdapter<ArrayList<ApplicationItem>, Map<String, ApplicationItem>> {

	@Override
	public ArrayList<ApplicationItem> marshal(Map<String, ApplicationItem> value)
			throws Exception {
		ArrayList<ApplicationItem> itemList = new ArrayList<ApplicationItem>();
		for(Map.Entry<String, ApplicationItem> e : value.entrySet())
			itemList.add(e.getValue());
		return itemList;
	}

	@Override
	public Map<String, ApplicationItem> unmarshal(
			ArrayList<ApplicationItem> value) throws Exception {
		Map<String, ApplicationItem> map = new HashMap<String, ApplicationItem>();
		for (ApplicationItem c : value)
			map.put(c.getId(), c);
		return map;
	}
}
```
Ich bin dabei nach diesem Beispiel vorgegangen.

Nach der XML-Erstellung erhalte ich jedoch folgende Datei:

```
<jobApplications>
    <company/>
</jobApplications>
```
Ziel des Adaptierens soll jedoch folgende XML-Struktur sein:

```
<jobApplications>
    <company id="0">
    </company>
    <company id="1">
    </company>
    usw.
</jobApplications>
```
Die Klassen habe ich übrigens nur auf das notwendigste reduziert, damit es hier etwas übersichtlicher sein soll.

Wo liegt denn da jetzt mein Denkfehler?

Ich bedanke mich schon mal im Voraus bei Euch!


----------



## kidsos (19. Apr 2010)

Schade, dass bis jetzt noch keiner geantwortet hat! 

Naja, ich weiß jetzt wenigstens, warum die Adapter-Klasse die Einträge nicht reinschreiben bzw. lesen kann. Ich habe da probehalber mal die 
	
	
	
	





```
@XmlJavaTypeAdapter(CompanyListAdapter.class)
```
-Annotation in den Klassenkopf von der ApplicationList-Klasse gesteckt. Damit das klappt, musste ich noch die Sichtbarkeit auf 
	
	
	
	





```
@XmlAccessorType(XmlAccessType.FIELD)
```
 ändern und das 
	
	
	
	





```
@XmlElement(name = "company")
```
 löschen, sonst wirft der Compiler eine Exception. Als Ergebnis habe ich dann folgende XML-Struktur erhalten:

```
<jobApplications>
    <itemHashMap>
        <entry>
            <key>0</key>
            <value id="0">
                hier der entsprechende Eintrag
            </value>
        </entry>
    </itemHashMap>
</jobApplications>
```
Wie man sieht, wrappt der um den Key-Value-Eintrag noch ein Entry-Element dazu. Und da wird wohl der Fehler liegen. Die Adapter-Klasse sieht nur das Entry-Element und kann dadurch nicht die Liste schreiben bzw. lesen.

Die entscheidende Frage ist: Wie kann man das umgehen? ???:L

Was ich da noch bemerkt habe, ist die Sache, dass ich bei Verwendung von 
	
	
	
	





```
@XmlJavaTypeAdapter(CompanyListAdapter.class)
```
 im Klassenkopf die Klassenattribute (wie z.B. "itemHashMap") nicht mehr ala 
	
	
	
	





```
@XmlElement(name = "company")
```
 modifizieren kann. Für mich ist diese Lösung nicht brauchbar: XML-Datei wird zu unübersichtlich und ich habe keine Kontrolle über die Element-Name. 

Günstiger ist da wahrscheinlich die Methode aus dem ersten Post, aber da ist auch die Frage: Wie kann ichs lösen?


----------



## Noctarius (19. Apr 2010)

Wie wär's mit zweiten Post: Old Nabble - Metro - Users - Does JAXB 2.0 support Map?


----------



## kidsos (19. Apr 2010)

Der Tipp hat mir schon mal sehr geholfen. Das Schreiben funktioniert jetzt prima und die XML-Datei hat die gewünschte Struktur.

Probleme bereitet mir jetzt nur noch das Lesen. Aktueller Stand der ApplicationList-Klasse ist folgender:

```
@XmlRootElement(name = "jobApplications")
@XmlAccessorType(XmlAccessType.NONE)
public class ApplicationList {

	private Map<String, ApplicationItem> itemHashMap;

	public ApplicationList() {
		itemHashMap = new HashMap<String, ApplicationItem>();
	}

	public void setItemHashMap(Map<String, ApplicationItem> itemHashMap) {
		this.itemHashMap = itemHashMap;
	}

	public Map<String, ApplicationItem> getItemHashMap() {
		return itemHashMap;
	}
	
	@XmlElement(name="company")
	private ArrayList<ApplicationItem> getXmpApplicationList(){
		ArrayList<ApplicationItem> appList = new ArrayList<ApplicationItem>();
		
		for (String id : itemHashMap.keySet()){
			appList.add(itemHashMap.get(id));
		}
		return appList;
	}

	private void setXmpApplicationList(ArrayList<ApplicationItem> replacements) {
		itemHashMap.clear();
		for (ApplicationItem c : replacements){
			itemHashMap.put(c.getId(), c);
		}
	}
}
```
Gelesen wird die Datei so (wie üblich):

```
JAXBContext context = JAXBContext.newInstance(ApplicationList.class);
Unmarshaller um = context.createUnmarshaller();
ApplicationList list = (ApplicationList) um.unmarshal( new FileReader( "job-applications.xml" ) );
```
Mir ist klar, dass beim Initialisieren von dem ApplicationList-Objekt nur eine leere HashMap (siehe oben) erzeugt wird, weshalb mir bei 
	
	
	
	





```
System.out.println(list.getItemHashMap().isEmpty());
```
 true ausgegeben wird. 

Nur wie kann ich jetzt die Umsetzung von der ArrayList in die HashMap automatisch anstoßen, sodass dann in der HashMap auch wirklich die Objekte drin sind, die ich benötige? Ruft da JAXB automatisch die setXmpApplicationList-Methode auf? Ich sehe den Wald vor lauter Bäumen nicht mehr. :rtfm:


----------



## Noctarius (19. Apr 2010)

War doch beides im MarshallerDemo in dem Link hinterlegt. Du arbeitest nicht über Listen, sondern über Arrays.


----------



## kidsos (19. Apr 2010)

Das geht anscheinend wirklich nur mit Arrays. Listen werfen immer eine NullPointer-Exception.

Weißt du oder jemand anders, warum das so ist?

Danke auf jeden Fall für den entscheidenden Tipp!


----------



## Noctarius (19. Apr 2010)

Nee ka


----------

