javajsondata-bindingbindingjsonb-api

Serialize a UUID as canonical hex string in JSON using JSON-B


UUID

A universally unique identifier (UUID) is a 128-bit value. Represented in Java by the java.util.UUID class.

Hex string

For display and for serialization, it is canonically formatted as a 36-character hexadecimal string arranged in five groups delimited by a hyphen. For example:
fd95cb46-8ec3-11e8-9eb6-529269fb1459

When serializing using the Java-standard XML & JSON APIs I expect this hex string. Worked for XML, but failed for JSON. I am using no annotations of any kind for either XML or JSON. My simple POJO knows nothing of XML nor JSON.

XML = success 👍

When I produce XML using the standard XML-binding framework of JSR 222: JavaTM Architecture for XML Binding (JAXB) 2.0, success. I get the hex string as expected. See last element of this snippet:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<panel>
    <connected>3.4kVA</connected>
    <fedFrom>PANEL 'EHE1' &amp; ATS-EM</fedFrom>
    <grounding>ground bus</grounding>
    <id>89d14b92-35ae-4c0c-b61d-ea8dbdeb324b</id>

JSON = fail 👎

When I run that same panel object through the standard JSON-binding framework of JSR 367: JavaTM API for JSON Binding (JSON-B), failure. Instead of the expected hex string, I get numbers.

{"connected":"3.4kVA","fedFrom":"PANEL 'EHE1' & ATS-EM","grounding":"ground bus","id":{"leastSignificantBits":-5323841289984462261,"mostSignificantBits":-8515942329042973684},

If you scroll over, you will see the UUID named id is presented as a pair of numbers rather than as a hex string:

"id":{"leastSignificantBits":-5323841289984462261,"mostSignificantBits":-8515942329042973684}

Is there some way to get the JSON binding to behave as the XML binding does? I want the hex string, not a pair of 64-bit numbers.

And of course this marshaled value should work when unmarshaled, re-hydrated into a Java object.


Solution

  • The JSON-B spec makes no mention of the UUID type, so it's up to the implementation whether or not it provides a (de)serializer out of the box. However, if you are using Eclipse Yasson (the JSON-B ref impl), it does provide a UUID (de)serializer by default. I'm not sure what other JSON-B impls (such as Apache Johnzon) provide by default.

    If you are using Yasson, I would recommend opening a bug on their GitHub repo, because this should work.


    Custom way

    If you are using a JSON-B implementation that does not provide UUID adapters by default, you can create and register your own type adapter:

    public static class MyUUIDAdapter implements JsonbAdapter<UUID, String> {
    
        @Override
        public String adaptToJson(UUID obj) throws Exception {
            return obj.toString();
        }
    
        @Override
        public UUID adaptFromJson(String obj) throws Exception {
            return UUID.fromString(obj);
        }
    
    }
    

    The easiest way to register the adapter is when you create the Jsonb instance:

    Jsonb jsonb = JsonbBuilder.create(new JsonbConfig().withAdapters(new MyUUIDAdapter()));
    

    However, if you don't control instantiation of your Jsonb instance (e.g. JAX-RS is doing it under the covers) you can annotate the field/method to use the adapter on:

    public class Panel {
        @JsonbTypeAdapter(MyUUIDAdapter.class)
        public UUID id;
    }