JAXB: Поместите тег XML на абстрактные классы

1

Я использую интерфейс от третьей стороны, и у них есть своеобразный (по крайней мере, мой разум) формат XML для запроса/ответа и уведомления. XML должен выглядеть так:

<Message>
  <Version>3.1</Version>
  <Request>
    <Request_Name>
      <RequestID> Request ID </RequestID>
      ...
    </Request_Name>
  </Request>
</Message>

Тег Request также может быть одним из Notification или Response. Все Messages будут иметь только один из этих трех. Request и Response имеют RequestID. Response имеет ReturnValue. Notification имеет Session.

Чтобы предотвратить дублирование, я хотел создать абстрактный класс для каждого из этих трех типов, и он почти работает! То, что я могу настроить и отменить, выглядит следующим образом:

<Message>
  <Version>3.1</Version>
  <Request_Name>
    <RequestID> Request ID </RequestID>
    ...
  </Request_Name>
</Message>

Обратите внимание на отсутствующий тег Request ! То же самое для Notification и Response. Вся информация есть, но эти теги-обертки меня убивают!

Вопрос: Можно ли поместить тег XML в абстрактный класс? Или мне нужно сделать его не абстрактным и создать еще один абстрактный класс верхнего уровня в качестве "реального" абстрактного базового класса?

У меня мало опыта работы с JAXB, поэтому я надеюсь, что есть простой способ сделать это. Я попытался сделать поле request в сообщении XMLElement вместо этого, но это только изменяет тег Request_Name Request и добавляет спецификацию типа.

Мой код в основном такой, как показано ниже, с сеттерами и CTOR, выведенными для краткости.

Основной класс Message:

@XmlRootElement(name = "Message")
public class Message {
    @XmlElement(required = true, name = "Version") private String version;
    private Request request;
    private Response response;
    private Notification notification;

    @XmlElementRef(required = false)
    public Request getRequest() {
        return request;
    }

    @XmlElementRef(required = false)
    public Response getResponse() {
        return response;
    }

    @XmlElementRef(required = false)
    public Notification getNotification() {
        return notification;
    }
}

Абстрактный класс Request. Аналогично для Notification и Response:

@XmlAccessorOrder(XmlAccessOrder.ALPHABETICAL)
public abstract class Request {
    private String requestId;

    @XmlElement(name = "RequestID", required = true)
    public String getRequestId() {
        return requestId;
    }
}

Пример реализации Request:

@XmlRootElement(name = "RegForAllNotificationsRequest")
public class RegForAllNotificationsRequest extends Request {
    private long session;
    private boolean register;

    @XmlElement(name = "SessionToUse")
    public long getSession() {
        return session;
    }
    @XmlElement(name = "Register")
    public boolean isRegister() {
        return register;
    }
}

Вышеприведенное приводит к следующему:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Message>
    <Version>8.3</Version>
    <RegForAllNotificationsRequest>
        <RequestID>94668</RequestID>
        <SessionToUse>548248</SessionToUse>
        <Register>true</Register>
    </RegForAllNotificationsRequest>
</Message>

Где мне это нужно:

<?xml version="1.0" encoding="UTF-8"?>
<Message>
    <Version>8.3</Version>
    <Request>
        <RegForAllNotificationsRequest>
            <RequestID>94668</RequestID>
            <SessionToUse>548248</SessionToUse>
            <Register>true</Register>
        </RegForAllNotificationsRequest>
    </Request>
</Message>
Теги:
inheritance
jaxb

1 ответ

1
Лучший ответ

Здесь вам нужен класс RequestContainer, у которого есть запрос имени тега. Этот класс будет содержать фактическую реализацию запроса. Это необходимо, потому что JAXB будет отображать каждый класс как отдельный тег. Иерархия тегов не построена на основе иерархии классов.

Класс контейнера будет выглядеть примерно так:

@XmlRootElement(name = "Request")
public class RequestContainer {
   private Request request;
}

Аналогично, для Notification и Response. Класс Message будет содержать экземпляр классов контейнеров для каждого из них, как показано ниже:

@XmlRootElement(name = "Message")
public class Message {
    @XmlElement(required = true, name = "Version") private String version;
    private RequestContainer request;
    private ResponseContainer response;
    private NotificationContainer notification;

    @XmlElementRef(required = false)
    public Request getRequest() {
        return request;
    }

    @XmlElementRef(required = false)
    public Response getResponse() {
        return response;
    }

    @XmlElementRef(required = false)
    public Notification getNotification() {
        return notification;
    }
}

Надеюсь это поможет.

  • 0
    Это на самом деле очень близко к тому, что я закончил. Я также опубликую свое решение, но отмечу ваше правильно.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню