Демаршал синхронизированная карта
Я использую JAXB для сохранения объектов в XML-файлах.
@XmlRootElement(name="jaxbobjt")
@XmlAccessorType(XmlAccessType.FIELD)
public class SomeJAXBObject
{
@XmlElementWrapper(name="myEntry")
private Map<Integer, AnotherJAXBObject> map = Collections.synchronizedMap(new LinkedHashMap<Integer, AnotherJAXBObject>());
}
Обратите внимание на то, что я использую synchronizedMap(...)
обертка.
Выше приведены результаты в следующем XML:
<jaxbobjt>
<map>
<myEntry>
<key>key</key>
<value>value</value>
</myEntry>
</map>
</jaxbobjt>
На самом деле я думал, что мне понадобится XmlAdapter
чтобы это заработало. Но к моему удивлению это маршалы и немаршалы нормально. Тесты показали, что он правильно использует java.util.Collections$SynchronizedMap
содержащий LinkedHashMap$Entry
объект.
Так что, если я правильно понимаю. Unmarshaller JAXB, просто создает экземпляр моего объекта с помощью конструктора. Поскольку после создания экземпляра объекта уже есть экземпляр карты, он не создает саму карту. Он использует putAll
Я предполагаю?
Я просто пытаюсь получить более глубокое понимание того, что происходит. Было бы здорово, если бы кто-нибудь дал мне дополнительную информацию об этом. Верны ли мои предположения?
Если я прав, я предполагаю, что следующая реализация потерпела бы неудачу:
@XmlRootElement(name="jaxbobjt")
@XmlAccessorType(XmlAccessType.FIELD)
public class SomeJAXBObject
{
// no instance yet.
@XmlElementWrapper(name="myEntry")
private Map<Integer, AnotherJAXBObject> map = null;
public synchronized void addObject(Integer i, AnotherJAXBObject obj)
{
// instantiates map on-the-fly.
if (map == null) map = Collections.synchronizedMap(new LinkedHashMap<Integer, AnotherJAXBObject>());
map.put(i, obj);
}
}
1 ответ
Стратегия, используемая JAXB, заключается в создании контейнерных классов только тогда, когда это необходимо. Для всего, что связано со списком, JJXB создает xjc
protected List<Foo> foos;
public List<Foo> getFoos(){
if( foos == null ) foos = new ArrayList<>();
return foos;
}
и, таким образом, удаление другого Foo для добавления в этот список
parent.getFoos().add( foo );
Что касается карт: предположительно, рабочая версия вашего класса SomeJAXBObject
содержит getMap
метод, и это будет работать так же. Установщики для списков и карт не нужны, и они не будут использоваться, если они присутствуют. Метод put в родительском классе также не ожидается; если он присутствует, он не будет использоваться, потому что у JAXB не будет способа узнать, что он делает.