anchor anchor - 3 months ago 23
reST (reStructuredText) Question

Jersey cannot deserialize java.util.UUID out of String in request object

I have an endpoint which accepts a

DriverJson
class instance as http request payload. The
DriverJson
class has a property
userId
which is of type
java.util.UUID
.
The problem is that Jersey cannot deserialize
UUID
string into
UUID
object. When I debug and inspected
driverJson
,
userId1
property is
null
(luckily it does not throw exception). I have read this article (article) that explains that classes that have
fromString(String string)
method (
java.util.UUID
has it) or have constructor with one (
String
) argument are deserialized by Jersey automatically (without writing any additional deserializer classes). If I change
UUID
type to
String
and I convert it my self (
UUID.fromString(userId)
) it's working perfectly.

In addition I use a
@PathParam UUID
arguments in some of my endpoints and they are working perfectly (as expected).

Below is my code:

My resource endpoint:

@POST
public Response add(DriverJson driverJson) {
DriverJson driver = service.add(driverJson);
return Response.status(Response.Status.CREATED).entity(driver).build();
}


My Driver class:

@XmlRootElement
public class DriverJson {

private UUID id;
private String name;
private UUID userId;

public DriverJson() {}

public DriverJson(UUID id, String name, UUID userId){
this.id = id;
this.name = name;
this.userId = userId;
}


/// getters & setters /////////

public UUID getId() {
return id;
}

public void setId(UUID id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public UUID getUserId() {
return userId;
}

public void setUserId(UUID userId) {
this.userId = userId;
}
}


My JSON request object:

{
"name" : "John",
"userId" : "ff06c5a4-135c-40b7-83f3-3648ec035efc"
}


I am using the standard Jersey archetype (version 2.23.2) with the following dependencies:

<dependencies>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet-core</artifactId>
<!-- use the following artifactId if you don't need servlet 2.x compatibility -->
<!-- artifactId>jersey-container-servlet</artifactId -->
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-moxy</artifactId>
</dependency>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>7.0</version>
</dependency>
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongo-java-driver</artifactId>
<version>3.3.0</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.50</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>16.0.1</version>
</dependency>
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>2.2.0</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.7</version>
</dependency>
</dependencies>

Answer

AFAIK you can fix it by using custom XmlAdapter:

public class UUIDAdapter extends XmlAdapter<String, UUID> {

    @Override
    public UUID unmarshal(String v) throws Exception {
        return UUID.fromString(v);
    }

    @Override
    public String marshal(UUID v) throws Exception {
        return v.toString();
    }
}

And then mark your fields with @XmlJavaTypeAdapter annotation

@XmlRootElement
public class DriverJson {

    @XmlJavaTypeAdapter(UUIDAdapter.class)
    private UUID id;
    @XmlJavaTypeAdapter(UUIDAdapter.class)
    private UUID userId;

    /* ... */
}