Демаршал синхронизированная карта

Я использую 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 не будет способа узнать, что он делает.

Другие вопросы по тегам