Reputation: 3731
I am using an interface from a third party and they have a peculiar (to my mind at least) XML format for request/response and notification. The XML needs to look like this:
<Message>
<Version>3.1</Version>
<Request>
<Request_Name>
<RequestID> Request ID </RequestID>
...
</Request_Name>
</Request>
</Message>
The Request
tag could also be one of Notification
or Response
. All Messages
will have only one of these three. Request
and Response
both have RequestID
. Response
has ReturnValue
as well. Notification
s have a Session
.
In order to prevent duplication I wanted to create an abstract class for each of these three types, and it almost works! What I can marshall to and unmarshall from looks like this:
<Message>
<Version>3.1</Version>
<Request_Name>
<RequestID> Request ID </RequestID>
...
</Request_Name>
</Message>
Note the missing Request
tag! Same for Notification
and Response
. All information is there but these wrapper tags are killing me!
The Question: Can I put an XML tag on the abstract class? Or do I need make it non-abstract and create another top-level abstract class as the "real" abstract base class?
I haven't much experience with JAXB, so I'm hoping there is a simple way to do this. I tried making the request
field on message an XMLElement
instead but that only changes the Request_Name
tag to Request
and adds a type specification.
My code is basically as below, with setters and CTORs taken out for brevity.
The base Message
class:
@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;
}
}
Abstract Request
class. Similar for Notification
and Response
:
@XmlAccessorOrder(XmlAccessOrder.ALPHABETICAL)
public abstract class Request {
private String requestId;
@XmlElement(name = "RequestID", required = true)
public String getRequestId() {
return requestId;
}
}
An example Request
implementation:
@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;
}
}
The above gets marshalled something like this:
<?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>
Where I need this:
<?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>
Upvotes: 1
Views: 249
Reputation: 2071
What you need here is a RequestContainer
class that has the tag name Request. This class will contain the actual request implementation. This is required because, JAXB will render each class as a separate tag. The tag hierarchy is not built based on the class hierarchy.
The container class will look something like this:
@XmlRootElement(name = "Request")
public class RequestContainer {
private Request request;
}
Similarly, for the Notification
and Response
. The Message
class will contain an instance of the container classes for each like below:
@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;
}
}
Hope this helps.
Upvotes: 2