TLDR: addImplicitMap
не позволит удалить <mapList>
элемент контейнера и entry
элементы и переименовывать элементы ключ/значение всех в один (пример 1 и 2). Для большего контроля над наименованием элементов на картах используйте NamedMapConverter
(пример 3). Чтобы иметь возможность делать все сразу, вам понадобится пользовательская реализация Converter
(пример 4).
Длинный ответ:
Там не кажется, хорошее объяснение на SO, что addImplicitMap
делает, и это тоже не очень понятно, в их документации, поэтому я буду пытаться объяснить Вот.
addImplicitMap
удалит элемент контейнера, но при его использовании он не позволит вам удалить элемент <entry>
или переименовать элементы ключа/значения. Например: (1)
stream.addImplicitMap(MapTest.class, "mapList", "s", Map.Entry.class, null);
Результаты в:
<MapTest>
<s>
<string>ID01</string>
<string>Jack</string>
</s>
<s>
<string>ID02</string>
<string>Neil</string>
</s>
</MapTest>
В качестве альтернативы addImplicitMap
позволяет хранить только значения из карты при записи (опуская элемент контейнера и ключевые элементы) , При чтении XML он воссоздает ключи карты, используя указанное поле объектов значения, поэтому ключ карты должен быть сохранен в объекте значения карты.
Например, мы можем сделать значение карты это Service
объекта с атрибутом ID и сделать Xstream хранить только значения и воссоздать карту из них: (2)
private Map<String, Service> serviceMap; // modified in MapTest
static class Service {
private String id, name;
public Service(String id, String name) {
this.id = id;
this.name = name;
}
}
MapTest services = new MapTest();
services.setService("ID01", new Service("ID01", "Jack"));
services.setService("ID02", new Service("ID02", "Neil"));
stream.addImplicitMap(MapTest.class, "serviceMap", "s", Service.class, "id");
Выходов:
<MapTest>
<s>
<id>ID01</id>
<name>Jack</name>
</s>
<s>
<id>ID02</id>
<name>Neil</name>
</s>
</MapTest>
Обратите внимание, что здесь каждый элемент <s>
фактически сериализованный Service
объекта, а не Map.Entry
объекта.
Это еще не вполне решить вашу проблему (и мы должны были изменить то, что было на карте тоже), так что мы можем вместо этого попробовать namedMapConverter
.Если мы вернемся к использованию карты <String, String>
, как вы имели первоначально, мы можем использовать: (3)
stream.registerConverter(new NamedMapConverter(stream.getMapper(),
null, "id", String.class, "name", String.class));
Что дает выход:
<MapTest>
<serviceMap>
<id>ID01</id>
<name>Jack</name>
<id>ID02</id>
<name>Neil</name>
</serviceMap>
</MapTest>
Еще не совсем правильно, и я не верьте, что вы можете сделать это лучше, не внедряя собственный класс Converter
(есть хороший учебник here). Таким образом, мы добавим строку (вместо NamedMapConverter
):
stream.registerConverter(new MapTestConverter());
и использовать реализацию пользовательского конвертера: (4)
static class MapTestConverter implements Converter {
public boolean canConvert(Class type) {
return type.equals(MapTest.class);
}
public void marshal(Object source, HierarchicalStreamWriter writer,
MarshallingContext context) {
MapTest mt = (MapTest) source;
for (Entry<String, String> e : mt.serviceMap.entrySet()) {
writer.startNode("id");
writer.setValue(e.getKey());
writer.endNode();
writer.startNode("name");
writer.setValue(e.getValue());
writer.endNode();
}
}
public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
MapTest mt = new MapTest();
String id = null;
while (reader.hasMoreChildren()) {
reader.moveDown();
if ("id".equals(reader.getNodeName())) {
if (id != null) { throw new RuntimeException("Malformed XML, ID was set twice: " + id); }
id = (String) context.convertAnother(mt, String.class);
} else if ("name".equals(reader.getNodeName())) {
String name = (String) context.convertAnother(mt, String.class);
if (id == null) { throw new RuntimeException("Malformed XML: Found name without ID: " + name); }
mt.serviceMap.put(id, name);
id = null;
}
reader.moveUp();
}
return mt;
}
}
Наконец мы получаем желаемый результат:
<MapTest>
<id>ID01</id>
<name>Jack</name>
<id>ID02</id>
<name>Neil</name>
</MapTest>
(извините, мне не хватает репутации, чтобы сделать следующее в ссылках)
Полный код addImplicitMap
Например: pastebin.com/MYiAde3m
Полный код namedMapConverter
Например: pastebin.com/kVChup5x
Полный код Converter
Например: pastebin.com/vUTwaHkk
Спасибо за ваш ответ , Ваш ответ поддержан – Samraan