Christophe Labouisse bio photo

Christophe Labouisse

Freelance Java expert, Docker enthusiast

Email Twitter Google+ LinkedIn Github Stackoverflow Hopwork

RESTX is a great REST framework. Easy to learn and to use, fast, well documented and actively developed this is definitely worth a look if you are looking to make a REST application. I started a REST application which needed to upload and download videos which is not supported by restx, at least in version 0.33.1.

The Problem

In a nutshell I already have a client and RESTX server and I wanted to add the ability for the client to upload and download videos. Using the same RESTX server would be great in order not to add too much complexity. So basically I’ll need to implement a PUT and a GET working directly on the http stream.

A naive implementation could be:

@Component
@RestxResource
@PermitAll
public class VideoResource {

    private VideoRepository repo;

    @PUT("/videos")
    public String addVideo(InputStream videoStream) {
        return repo.addVideo(videoStream);
    }

    @GET("/videos/{videoId}")
    public InputStream getVideo(String videoId) {
        return repo.getVideo(videoId);
    }
}

When calling the GET I got the following stackstrace:

com.fasterxml.jackson.databind.JsonMappingException: No serializer found for class com.mongodb.gridfs.GridFSDBFile$MyInputStream and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) )
	at com.fasterxml.jackson.databind.ser.impl.UnknownSerializer.failForEmpty(UnknownSerializer.java:59) ~[jackson-databind-2.3.3.jar:2.3.3]
	at com.fasterxml.jackson.databind.ser.impl.UnknownSerializer.serialize(UnknownSerializer.java:26) ~[jackson-databind-2.3.3.jar:2.3.3]
	at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:114) ~[jackson-databind-2.3.3.jar:2.3.3]
	at com.fasterxml.jackson.databind.ObjectWriter._configAndWriteValue(ObjectWriter.java:809) ~[jackson-databind-2.3.3.jar:2.3.3]
	at com.fasterxml.jackson.databind.ObjectWriter.writeValue(ObjectWriter.java:666) ~[jackson-databind-2.3.3.jar:2.3.3]
	at restx.jackson.JsonEntityResponseWriter.write(JsonEntityResponseWriter.java:30) ~[restx-core-0.33.1.jar:na]
	at restx.entity.AbstractEntityResponseWriter.sendResponse(AbstractEntityResponseWriter.java:35) ~[restx-core-0.33.1.jar:na]
	at restx.entity.StdEntityRoute.handle(StdEntityRoute.java:142) ~[restx-core-0.33.1.jar:na]

This is not unexpected as RESTX is handling only JSON payloads. So my solution will be to create custom routes not using the Jackson stuff.

My Solution

First part is to create a custom Router for the video stuff:

@Component
public class VideoRouter extends RestxRouter {
    public VideoRouter(EntityRequestBodyReaderRegistry readerRegistry, EntityResponseWriterRegistry writerRegistry, VideoResource videoResource) {
        super("Videos",
                new PutVideoRoute(writerRegistry, videoResource),
                new GetVideoRoute(readerRegistry, videoResource)
        );
    }
}

PutVideoRoute

I created this class after the code generated by the RESTX annotation processor. The important part is only line 14 where readBody returns directly the request content stream.

GetVideoRoute

The magic is on line 10 to 15 where we just copy the video stream to the response output stream.

Video Repository

RESTX provides a good support for MongoDB through the Jongo library. I implemented the video repository using Grid FS:

@Component
public class JongoVideoRepository {

    private final GridFS gridFS;

    public JongoVideoRepository(Jongo jongo) {
        gridFS = new GridFS(jongo.getDatabase());
    }

    public String addVideo(InputStream videoStream) {
        GridFSInputFile file = gridFS.createFile(videoStream);
        file.save();
        return file.getId().toString();
    }

    public InputStream getVideo(String videoId) {
        GridFSDBFile file = gridFS.findOne(new ObjectId(videoId));
        return file == null ? null : file.getInputStream();
    }
}

Overview