We have an XSD of this form:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified" version="1.0.0">
<xs:element name="SomeEndpoint">
<xs:complexType>
<xs:choice>
<xs:element name="RequestPayload">
<!-- snip -->
</xs:element>
<xs:element name="ResponsePayload">
<!-- snip -->
</xs:element>
<xs:element name="ErrorPayload">
<!-- snip -->
</xs:element>
<xs:choice>
</xs:complexType>
</xs:element>
</xs:schema>
Never mind if we like it; it's given. So for instance, for a request, we'd get XML of the form
<SomeEndpoint>
<RequestPayload>
<!-- snip -->
</RequestPayload>
</SomeEndpoint>
For our own sanity, we want to have three POXOs, so to speak:
@JsonTypeName("RequestPayload")
class SomeEndpointRequestPayload {
}
@JsonTypeName("ResponsePayload")
class SomeEndpointResponsePayload {
}
@JsonTypeName("ErrorPayload")
class SomeEndpointErrorPayload {
}
So far, so good -- we can, using Jackon 2.11.0 with jackson-dataformat-xml:2.11.2, serialize the "real" objects just fine. FWIW, we use a mapper configured like so:
public XmlMapper payloadMapper() {
var xmlMapper = new XmlMapper();
xmlMapper.registerModule(new JavaTimeModule());
xmlMapper.registerModule(new JaxbAnnotationModule());
return xmlMapper;
}
Now we "only" need that wrapping tag, SomeEndpoint. Things we've tried:
Root Path: We thought that it might be possible to inject a custom "root path" for a POXO via
@JsonRootNameor@JacksonXmlRootElement. We tried passing names likeSomeEndpoint.RequestPayloadorSomeEndpoint/RequestPayload; no luck.Wrapper Object: This seems the most natural solution, but we struggled not getting an additional wrapping tag named after the property. In particular, this variant is not accepted by Jackson:
@JsonRootName(value = "SomeEndpoint") class SomeEndpointWrapper { @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.WRAPPER_OBJECT) @JsonUnwrapped Object payload; }This one still outputs a
<payload>tag:@JsonRootName(value = "SomeEndpoint") class SomeEndpointWrapper { @XmlElements({ @XmlElement(name="RequestPayload", type=SomeEndpointRequestPayload.class), @XmlElement(name="ResponsePayload", type=SomeEndpointResponsePayload.class), @XmlElement(name="ErrorPayload", type=SomeEndpointErrorPayload.class) }) Object payload; }We've tried too many mixes of annotations to count, or reproduce here, but these two seemed like "should work".
Note bene: We've been using a marker interface instead of
Objectto restrict values to the three types. Since it doesn't seem to make a difference to Jackson, I've left it out for the sake of simplicity.Workaround: We can have one property per choice option:
@Data @JsonRootName(value = "SomeEndpoint") class SomeEndpointWrapper { @JsonProperty(value = "Request") private SomeEndpointRequestPayload request; @JsonProperty(value = "Antwort") private SomeEndpointResponsePayload successResponse; @JsonProperty(value = "Fehlerinformation") private SomeEndpointErrorPayload errorResponse; }This works, but ... nah, really?
What's a good way to implement an XML choice in POXOs without creating spurious wrapping tags?