Я использую интерфейс от третьей стороны, и у них есть своеобразный (по крайней мере, мой разум) формат 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>
Здесь вам нужен класс 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;
}
}
Надеюсь это поможет.