Search code examples
javarequestjax-rsresponse

Retrieving String from JAX-RS Response


In short terms, I simplified the problem a lot. I am calling this code, and the response is received with status 200 (OK):

Receiver.java:

Response response = componentInstanceService.getResource(componentResourceType);

However, I don't know how can I retrieve the String contained in the body from this method:

Sender.java:

  @Override
    public Response getResource(ComponentResourceType resourceType) {
        String path = getPath();
        return Response.ok(this.getClass().getResourceAsStream(path)).build();
    }

Please note that the communication between classes is working fine, as long as the Response is OK, however, how can I retrieve the String that Response contains?

This is what I would like to do roughly:

Receiver:

String result = componentInstanceService.getResource(componentResourceType);

Solution

  • The documentation for Response makes this pretty clear:

    static Response.ResponseBuilder ok(java.lang.Object entity)

    Create a new ResponseBuilder that contains a representation.

    And:

    abstract java.lang.Object getEntity()

    Return the response entity.

    In other words, the object you passed to Response.ok is the entity. You can retrieve it with the Response’s getEntity() method.

    Obviously, you will need to cast it:

    Response response = componentInstanceService.getResource(componentResourceType);
    InputStream dataSource = (InputStream) response.getEntity();
    

    Then you can read the stream as text. You haven’t mentioned the charset of your text files, so I’ll assume it’s UTF-8:

    String result;
    try (Scanner scanner = new Scanner(dataSource, StandardCharsets.UTF_8)) {
        result = scanner.useDelimiter("\\z").next();
    }
    

    Update:

    I suspected this might happen. You are returning a raw InputStream, which has no information about what type of data it is.

    Change Sender.java to return a DataSource:

    @Override
    public DataSource getResource(ComponentResourceType resourceType) {
        String path = getPath();
        return new URLDataSource(this.getClass().getResource(path));
    }
    

    This way, the JAX-RS service will not only return HTTP 200 OK, but will also return a Content-Type header corresponding to the intuited type of your file.

    You should then be able to invoke the method with:

    DataSource dataSource = componentInstanceService.getResource(componentResourceType);
    
    String result;
    try (Scanner scanner = new Scanner(dataSource.getInputStream(), StandardCharsets.UTF_8)) {
        result = scanner.useDelimiter("\\z").next();
    }
    

    There actually is a more robust way to read a DataSource. You can wrap it in a DataHandler:

    DataSource dataSource = componentInstanceService.getResource(componentResourceType);
    DataHandler handler = new DataHandler(dataSource);
    
    DataFlavor flavor = DataFlavor.selectBestTextFlavor(
        handler.getTransferDataFlavors());
    
    if (flavor == null) {
        // This should never happen with text files.
        throw new IllegalArgumentException(
            "Data has no flavors capable of supplying text.");
    }
    
    String result;
    try (Reader reader = flavor.getReaderForText(handler)) {
        StringBuilder s = new StringBuilder();
        int c;
        while ((c = reader.read()) >= 0) {
            s.append((char) c);
        }
        result = s.toString();
    } catch (UnsupportedFlavorException e) {
        // Since we started with a flavor provided by the DataHandler,
        // we should never get here.
        throw new RuntimeException(e);
    }