Search code examples
google-chromerestlet

Document is empty error while returning get response in Chrome using restlet


I've just started out with the restlet framework. I've written simple server and resource classes to get started. Here's the code:

Resource:

import org.restlet.resource.Get; 
import org.restlet.resource.ServerResource; 

public class HelloWorldResource extends ServerResource { 
    @Get 
    public String represent(){ 
            return "Hello World"; 
    } 
}

Server:

import org.restlet.Server; 
import org.restlet.data.Protocol; 

public class HelloWorldServer { 
    public static void main(String[] args) throws Exception { 
            Server server = new Server(Protocol.HTTP, 8989, HelloWorldResource.class); 
            server.start(); 
    } 
} 

When I try to run the code in Chrome by hitting http://localhost:8989/ I get the following error: enter image description here

This error goes away when I enclose the resource return value in xml tags like so <tag>Hello World</tag> and the default XML template is displayed in Chrome with "Hello World" in the tags.

Using a ClientResource variable to access the resource via code works just fine without the tags.

Additionally, while running the same code in IE, it automatically downloads a JSON file with the message to my computer.

What is the reason behind this kind of behavior?

Thanks.


Solution

  • In fact, your issue is related to the content negotiation feature of HTTP (Conneg). This leverages two headers:

    • Content-Type: the format of the text payload of a request or a response. In your case, this header tells to the client the structure of the data you return.
    • Accept: the format of the text payload you expect in the response. This header is used within requests and is automatically set by the browser according to what it supports. The server is responsible of taking into account this header to return the supported content.

    See this article for more details:

    Restlet provides out of the box content negotiation. I mean you return a text, it will automatically set the Content-Type header in the response to text/plain:

    @Get 
    public String represent(){ 
      return "Hello World"; 
    }
    

    You have completely the hand if you want return another content type. Here is a sample:

    @Get 
    public Representation represent() { 
      return new StringRepresentation(
         "<tag>Hello World</tag>",
         MediaType.APPLICATION_XML); 
    }
    

    You can also define a parameter at the @Get level to take into account the provided Accept header:

    @Get('xml')
    public Representation represent() { 
      return new StringRepresentation(
         "<tag>Hello World</tag>",
         MediaType.APPLICATION_XML); 
    }
    
    @Get('json')
    public Representation represent() { 
      return new StringRepresentation(
         "{ \"message\": \"Hello World\" }",
         MediaType.APPLICATION_JSON); 
    }
    
    // By default - if nothing matches above
    @Get
    public Representation represent() { 
      return new StringRepresentation(
         "Hello World",
         MediaType.PLAIN_TEXT); 
    }
    

    Another thing is that Restlet allows to leverage beans directly at the level of server resource methods instead of String or Representation. This corresponds to the converter feature. To use it, you need to register a converter. For example, simply add the jar file (org.restlet.ext.jackson with dependencies) from the Jackson extension of Restlet. A converter based of Jackson will be automatically registered. This way text payload will be converter to bean and bean to text.

    Now you will be able to use something like that:

    @Get('json')
    public Message represent() { 
      Message message = new Message();
      message.setMessage("Hello world");
      return message; 
    }
    

    based on a Message class you create:

    public class Message {
      private String message;
    
      public String getMessage() { return this.message; }
      public void setMessage(String message) { this.message = message; }
    }