jackson-dataformat-xml
jackson-dataformat-xml copied to clipboard
Type-safe record wrappers
Is your feature request related to a problem? Please describe.
The following example code uses a trivial wrapper record (LocationID) to allow some extra type-safety when working with elements declared in an existing schema:
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
import java.io.IOException;
import java.util.Objects;
import java.util.UUID;
public final class SerialDemo2
{
private SerialDemo2()
{
}
record LocationID(UUID id) {
LocationID {
Objects.requireNonNull(id, "id");
}
}
@JacksonXmlRootElement(namespace = "urn:com.io7m.cardant.inventory:1")
record Location(
@JsonProperty(required = true)
@JacksonXmlProperty(isAttribute = true, localName = "id")
LocationID id,
@JsonProperty(required = false)
@JacksonXmlProperty(isAttribute = true, localName = "parent")
LocationID parent
) {
Location {
Objects.requireNonNull(id, "id");
}
}
public static void main(
final String[] args)
throws IOException
{
final var mapper =
XmlMapper.builder()
.build();
System.out.println("Expected: ");
System.out.println();
System.out.println("""
<Location xmlns="urn:com.io7m.cardant.inventory:1"
id="6e3f4213-db36-4ea3-91ba-1ce6917cbcbb"
parent="265f34b3-8c86-4a1f-b23a-bb104238bfc6"/>
""");
System.out.println("Received: ");
System.out.println();
mapper.writeValue(
System.out,
new Location(
new LocationID(UUID.randomUUID()),
new LocationID(UUID.randomUUID())
)
);
System.out.println();
}
}
The output of the program ends up as:
Expected:
<Location xmlns="urn:com.io7m.cardant.inventory:1"
id="6e3f4213-db36-4ea3-91ba-1ce6917cbcbb"
parent="265f34b3-8c86-4a1f-b23a-bb104238bfc6"/>
Received:
<Location xmlns="urn:com.io7m.cardant.inventory:1"><id xmlns=""><id>c09fb552-e36c-4213-b56a-7729cd5b7999</id></id><parent xmlns=""><id>58c399ae-0256-4dbd-a00e-0c1c01189559</id></parent></Location>
The desired output can be produced with the following definitions instead:
final class CA1LocationID
{
private final UUID id;
@JsonCreator(mode = JsonCreator.Mode.DELEGATING)
public CA1LocationID(
final UUID inId)
{
this.id = Objects.requireNonNull(inId, "id");
}
@JsonValue
@Override
public UUID id()
{
return this.id;
}
}
But it's slightly unfortunate that the definitions have to be declared in this way, because we lose a lot of the nice properties of record classes in the process.
Describe the solution you'd like
I'd like to be able to use records instead of POJOs in the above example.
Usage example
See above. :slightly_smiling_face:
Additional context
See this thread on the mailing list: https://groups.google.com/d/msgid/jackson-user/20210911172814.62fd2925%40sunflower.int.arc7.info