Home > Software design >  How do I use a UUID in a @MultipartForm Pojo?
How do I use a UUID in a @MultipartForm Pojo?

Time:11-04

I would like to transfer a UUID in my DTO to my resource method.

My method:

    @POST
    @Path(("/upload"))
    @Consumes(MediaType.MULTIPART_FORM_DATA)
    @Produces(MediaType.APPLICATION_JSON)
    public Response sendMultipartData(@MultipartForm MultipartBodyRequestDto data) {
      // Do stuff [...]
        return Response.ok().entity(responseDto).build();
    }

My DTO:

public class MultipartBodyRequestDto {

    // Other properties [...]

    @NotNull
    @FormParam("file")
    @PartType(MediaType.APPLICATION_OCTET_STREAM)
    public InputStream file;

    @NotNull
    @FormParam("id")
    @PartType(MediaType.TEXT_PLAIN) // <-- What do I have to select here ?
    public UUID id;
}

I am getting this error:

"RESTEASY007545: Unable to find a MessageBodyReader for media type: text/plain;charset=UTF-8 and class type java.util.UUID"

When switching to String and @PartType(MediaType.TEXT_PLAIN), it works, but I have to convert the id myself.

Resteasy should be able to convert it, after all I am using UUIDs in other endpoints like this:

@GET
@Path("/{id}")
public Response get(@PathParam("id") @NotNull UUID id) {
   // Do stuff [...]
}

Do I have to implement a specific MessageBodyReader ?

CodePudding user response:

You'd need to provide a MessageBodyReader<UUID> which knows how to read the data. Something like the following:

@Provider
public class UuidMessageBodyReader implements MessageBodyReader<UUID> {
    @Override
    public boolean isReadable(final Class<?> type, final Type genericType, final Annotation[] annotations, final MediaType mediaType) {
        return type.isAssignableFrom(UUID.class);
    }

    @Override
    public UUID readFrom(final Class<UUID> type, final Type genericType, final Annotation[] annotations, final MediaType mediaType, final MultivaluedMap<String, String> httpHeaders, final InputStream entityStream) throws IOException, WebApplicationException {
        try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
            final byte[] buffer = new byte[256];
            int len;
            while ((len = entityStream.read(buffer)) != -1) {
                out.write(buffer, 0, len);
            }
            return UUID.fromString(out.toString(resolve(mediaType)));
        } finally {
            entityStream.close();
        }
    }

    private String resolve(final MediaType mediaType) {
        if (mediaType != null) {
            final String charset = mediaType.getParameters().get("charset");
            if (charset != null) {
                return charset;
            }
        }
        return "UTF-8";
    }
}

Please note this is just a quick example and there is probably a more efficient way of doing this.

The reason it works on your other endpoint is it will just return the UUID.toString(). However, there is no default way to read the type as there is not UUID.valueOf() method.

  • Related