これを実行する正当な理由があるかもしれませんが、この種のXMLの生成は一般的に回避するのが最善です。なんで?これは、マップのXML要素がマップの実行時の内容に依存していることを意味するためです。また、XMLは通常、外部インターフェイスまたはインターフェイスレイヤーとして使用されるため、これは望ましくありません。説明させてください。
Xmlスキーマ(xsd)は、XMLドキュメントのインターフェースコントラクトを定義します。XSDからコードを生成できることに加えて、JAXBはコードからXMLスキーマを生成することもできます。これにより、インターフェイスを介して交換されるデータを、XSDで定義された事前に合意された構造に制限できます。
のデフォルトの場合Map<String, String>
、生成されたXSDは、マップ要素が複数のエントリ要素を含むように制限します。各エントリ要素には、1つのxs:string
キーと1つのxs:string
値が含まれている必要があります。これはかなり明確なインターフェース契約です。
説明するのは、実行時にマップのコンテンツによって名前が決定される要素をxmlマップに含めることです。次に、生成されたXSDは、コンパイル時にタイプが不明な要素のリストがマップに含まれている必要があることのみを指定できます。これは、インターフェイスコントラクトを定義するときに一般的に避けるべきものです。
この場合に厳密なコントラクトを実現するには、文字列ではなく、列挙型をマップのキーとして使用する必要があります。例えば
public enum KeyType {
KEY, KEY2;
}
@XmlJavaTypeAdapter(MapAdapter.class)
Map<KeyType , String> mapProperty;
そうすれば、XMLの要素になりたいキーがコンパイル時に認識されるため、JAXBは、事前定義されたキーKEYまたはKEY2のいずれかを使用して、マップの要素を要素に制限するスキーマを生成できる必要があります。
一方、デフォルトで生成された構造を単純化したい場合
<map>
<entry>
<key>KEY</key>
<value>VALUE</value>
</entry>
<entry>
<key>KEY2</key>
<value>VALUE2</value>
</entry>
</map>
このようなもっと単純なものに
<map>
<item key="KEY" value="VALUE"/>
<item key="KEY2" value="VALUE2"/>
</map>
次のように、MapをMapElementsの配列に変換するMapAdapterを使用できます。
class MapElements {
@XmlAttribute
public String key;
@XmlAttribute
public String value;
private MapElements() {
} //Required by JAXB
public MapElements(String key, String value) {
this.key = key;
this.value = value;
}
}
public class MapAdapter extends XmlAdapter<MapElements[], Map<String, String>> {
public MapAdapter() {
}
public MapElements[] marshal(Map<String, String> arg0) throws Exception {
MapElements[] mapElements = new MapElements[arg0.size()];
int i = 0;
for (Map.Entry<String, String> entry : arg0.entrySet())
mapElements[i++] = new MapElements(entry.getKey(), entry.getValue());
return mapElements;
}
public Map<String, String> unmarshal(MapElements[] arg0) throws Exception {
Map<String, String> r = new TreeMap<String, String>();
for (MapElements mapelement : arg0)
r.put(mapelement.key, mapelement.value);
return r;
}
}