n.mayank
n.mayank

Reputation: 11

How to disable Jersey POJOMappingFeature for just one method or controller class

I have the Jersey JSON POJOMappingFeature turned on in my web.xml as follows to convert POJOs to/from JSON:

<init-param>
        <param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
        <param-value>true</param-value>
</init-param>

I have a method in one of the controllers which takes care of file upload. It takes multi-part form data, extracts the file input field from the form, converts it to an InputStream and saves the file to disk:

@POST
@Path("/upload")
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Produces("application/json")
public FileMetaData uploadFiles(FormDataMultiPart formDataMultiPart) {
    return new FileUploadHandler(SERVER_FILE_UPLOAD_LOCATION).upload(formDataMultiPart);
}

public FileMetaData upload(FormDataMultiPart formDataMultiPart) {
    FormDataBodyPart formFile = formDataMultiPart.getField("files");
    ContentDisposition contentDisposition = formFile.getContentDisposition();
    return saveFile(formFile.getValueAs(InputStream.class), contentDisposition.getFileName(), formFile.getMediaType().toString());
}

This works well for all file formats except when i try to upload a JSON file, the formFile.getValueAs(InputStream.class) throws an error complaining that a String cannot be converted to InputStream. I assume this is because Jersey automatically converted the JSON file into a string object. So how can I prevent Jersey from doing that just for this method or controller? My requirement is such that I need to have the json file saved as a file itself.

I have tried searching a lot on this but all I end up with is documentation on how to enable POJOMapping but not to selectively disable it. Any help would be very highly appreciated!

UPDATE: My Custom MessageBodyReader looks like the follows:

public class JSONMessageBodyReader implements MessageBodyReader<Object> {

private static final Logger log = LoggerFactory.getLogger(JSONMessageBodyReader.class);

@Override
public boolean isReadable(Class<?> type, Type genericType,
                          Annotation[] annotations, MediaType mediaType) {
    // return true;
    return mediaType.isCompatible(MediaType.APPLICATION_JSON_TYPE)
            || mediaType.isCompatible(MediaType.APPLICATION_OCTET_STREAM_TYPE);
            || mediaType.isCompatible(MediaType.TEXT_HTML_TYPE);
}

@Override
public Object readFrom(Class<Object> type, Type genericType,
                       Annotation[] annotations, MediaType mediaType,
                       MultivaluedMap<String, String> httpHeaders, InputStream entityStream)
        throws IOException, WebApplicationException {
    if (log.isTraceEnabled()) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        byte[] chunk = new byte[256];
        int read = -1;
        while ((read = entityStream.read(chunk)) != -1) {
            baos.write(chunk, 0, read);
        }
        chunk = baos.toByteArray();
        String entity = new String(chunk);
        log.trace("the entity: " + entity);
        return ObjectMapperFactory.getInstance().readValue(chunk, 0, chunk.length, type);
    }

    return ObjectMapperFactory.getInstance().readValue(entityStream, type);
}

}

Upvotes: 0

Views: 610

Answers (1)

n.mayank
n.mayank

Reputation: 11

I finally ended up solving my requirement by processing the uploaded file using the lower-level HttpServletRequest instead of Jersey's FormDataParams, as follows:

@POST
@Path("/upload")
@Consumes("multipart/form-data")
@Produces("application/json")
public FileMetaData uploadFiles(@Context ServletContext servletContext, @Context HttpServletRequest request) {
    return fileUploadHandler.upload(request, servletContext);
}


public FileMetaData upload(HttpServletRequest request, ServletContext servletContext) {
    FileMetaData fileMetaData = null;
    boolean isMultipart = ServletFileUpload.isMultipartContent(request);
    if (isMultipart) {
        LOGGER.info("About to save file on the server : {}", this.SERVER_UPLOAD_DIRECTORY);

        DiskFileItemFactory diskFileItemFactory = new DiskFileItemFactory();
        File repository = (File) servletContext.getAttribute("javax.servlet.context.tempdir");
        diskFileItemFactory.setRepository(repository);
        ServletFileUpload servletFileUpload = new ServletFileUpload(diskFileItemFactory);
        try {
            List<FileItem> files = servletFileUpload.parseRequest(request);
            Iterator<FileItem> iter = files.iterator();
            while(iter.hasNext()) {
                FileItem fileItem = iter.next();
                String fileName = fileItem.getName();
                if (fileName != null) {
                    fileName = FilenameUtils.getName(fileName);
                }
                String fileUploadDirectory = this.SERVER_UPLOAD_DIRECTORY;
                File uploadDirectory = new File(fileUploadDirectory);
                if(!uploadDirectory.exists()) {
                    uploadDirectory.mkdir();
                    LOGGER.info("creating directory {}", uploadDirectory.getAbsolutePath());
                }
                String fileUploadPath = fileUploadDirectory + File.separator + fileName;
                File fileToStore = new File(fileUploadPath);
                LOGGER.info("saved file {} on server", fileName);

                fileItem.write(fileToStore);
                long fileSize = fileToStore.length();
                String size = (fileSize > 1024) ? (fileSize/1024) + "Kb" : fileSize + "b";
                fileMetaData = new FileMetaData(fileName, size, true);
            }
        } catch (Exception e) {
            LOGGER.warn("error occurred while saving file to server : {}", e.getStackTrace());
            e.printStackTrace();
        }
    }

    else {
        LOGGER.info("No files to upload in request");
    }

    return fileMetaData;
}

This solution works perfectly for me, even though I felt it's a sort of a hack around my original problem. It would make me happy if this solution helps someone else too. But someone has to offer a pure Jersey way to solve this problem without involving the HttpServletRequest I would be more than glad to try it out. Thanks!

Upvotes: 1

Related Questions