JAXB переопределить тип списка @XmlElement

Там простой класс Bean1 с подсписком типа BeanChild1,

@XmlRootElement(name="bean")
@XmlAccessorType(XmlAccessType.PROPERTY)
public static class Bean1
{
  public Bean1()
  {
    super();
  }

  private List<BeanChild1> childList = new ArrayList<>();

  @XmlElement(name="child")
  public List<BeanChild1> getChildList()
  {
    return childList;
  }

  public void setChildList(List<BeanChild1> pChildList)
  {
    childList = pChildList;
  }
}

public static class BeanChild1 { ... }

Я пытаюсь переопределить класс, чтобы изменить тип списка. Новый дочерний класс (т.е. BeanChild2) расширяет предыдущий (т.е. BeanChild1)

public static class Bean2 extends Bean1
{
  public Bean2()
  {
    super();
  }

  @Override
  @XmlElement(name="child", type=BeanChild2.class)
  public List<BeanChild1> getChildList()
  {
    return super.getChildList();
  }
}

public static class BeanChild2 extends BeanChild1 { }

Итак, вот как я это проверил:

public static void main(String[] args)
{
  String xml = "<bean>" +
               "  <child></child>" +
               "  <child></child>" +
               "  <child></child>" +
               "</bean>";
  Reader reader = new StringReader(xml);

  Bean2 b2 =  JAXB.unmarshal(reader, Bean2.class);
  assert b2.getChildList().get(0) instanceof BeanChild2; // fails
}

Тест показывает, что этот список все еще содержит потомков BeanChild1,

Итак, как я могу заставить его заполнить childList поле с BeanChild2 случаи?

Если нет простых решений, не стесняйтесь размещать более креативные решения (например, используя XmlAdapter s, Unmarshaller.Listener Возможно, дополнительная аннотация на родительский или дочерний класс...)

1 ответ

Нет способа изменить (например, переопределить) @XmlElement аннотация суперкласса. По крайней мере, не используя аннотации.

  • Не важно что @XmlAccessorType вы используете (например, FIELD, PROPERTY, PUBLIC, NONE).
  • Это не имеет никакого значения, если вы размещаете аннотации на полях или на получателях.

Однако есть разумная альтернатива. Реализация JAXB для MOXy предлагает возможность определять метаданные / привязки в файле XML. Фактически, у каждой java-аннотации есть альтернатива XML. Но это становится лучше: вы можете комбинировать как Java-аннотации, так и XML-метаданные. Круто то, что MOXy объединит оба объявления, и в случае конфликта метаданные, определенные в XML, получат более высокий приоритет.

Предполагая, что Bean1 класс аннотирован, как указано выше. Затем можно переопределить привязку в файле XML. например:

<xml-bindings xml-accessor-type="PROPERTY">
  <java-types>
    <java-type name="Bean1">
      <xml-element java-attribute="childList" name="child" 
                   type="BeanChild2" container-type="java.util.ArrayList" />
    </java-type>
  </java-types>
</xml-bindings>

Этот новый файл привязок необходим при создании объекта контекста.

// use a map to reference the xml file
Map<String, Object> propertyMap = new HashMap<>();
propertyMap.put(JAXBContextProperties.OXM_METADATA_SOURCE, "bindings.xml");

// pass this properyMap during the creation of the JAXB context.
JAXBContext context = JAXBContext.newInstance(..., propertyMap);

MOXy объединит Java-аннотации и XML-привязки, и в случае конфликта применяются определенные XML-параметры. В этом случае, чем раньше @XmlElement(name=child) аннотация заменяется определением XML, которое эквивалентно @XmlElement(name=child, type=BeanChild2.class),

Вы можете прочитать больше о привязках XML здесь.

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