Content types
When we send a Response to the client we must specify the content type. In most cases the content type is html (text/html
) but are situations (for example a REST application/module)
when we want to return plain text (text/plain
) or json (application/json
) or xml (application/xml
) or yaml (application/x-yaml
) or csv(text/csv
).
To resolve these situations Pippo comes with a nice concept ContentTypeEngine.
Pippo comes bultin (direct or via modules) with the following content type engines:
- plain text (TextPlainEngine)
- xml (JaxbEngine, XstreamEngine, JacksonXmlEngine)
- json (GsonEngine, FastjsonEngine, JacksonJsonEngine)
- yaml (SnakeYamlEngine, JacksonYamlEngine)
- csv (CsvEngine)
If you want to develop a new engine of content type you can do it very easily. All you have to do is to implement ContentTypeEngine.
See below a possible implementation for XstreamEngine (an XmlEngine based on XStream):
public class XstreamEngine implements ContentTypeEngine {
@Override
public String getContentType() {
return HttpConstants.ContentType.APPLICATION_XML; // "application/xml"
}
@Override
public String toString(Object object) {
return new XStream().toXML(object);
}
@Override
public <T> T fromString(String content, Class<T> classOfT) {
return (T) new XStream().fromXML(content);
}
@Override
public void init(Application application) {
// do nothing
}
}
To register a content type engine in your application you have two options:
- programatically add the content type engine in
Application.onInit()
withApplication.registerContentTypeEngine(XstreamEngine.class)
- create an Initializer in your project that register the content type engine
For above XstreamEngine we can create an XstreamInitializer with this possible content:
public class XstreamInitializer implements Initializer {
@Override
public void init(Application application) {
application.registerContentTypeEngine(XstreamEngine.class);
}
@Override
public void destroy(Application application) {
// do nothing
}
}
Below is an example how to send an xml:
public class BasicApplication extends Application {
@Override
protected void onInit() {
// send xml as response
GET("/xml", routeContext -> {
Contact contact = createContact();
routeContext.xml().send(contact);
});
}
private Contact createContact() {
return new Contact()
.setId(12345)
.setName("John")
.setPhone("0733434435")
.setAddress("Sunflower Street, No. 6");
}
}
Another useful concept is Content Type Negotiation
. It can be used via Response.contentType()
or ResponseContext.negotiateContentType()
.
It attempts to set the Content-Type of the Response based on Request headers. The Accept header is preferred for negotiation but the Content-Type
header may also be used if an agreeable content type engine can not be determined.
If no Content-Type can not be negotiated then the response will not be modified. This behavior allows specification of a default Content-Type
using one of the methods such as xml()
or json()
.
See below an example related to content type negotiation:
public class BasicApplication extends Application {
@Override
protected void onInit() {
// send an object and negotiate the Response content-type, default to XML
GET("/negotiate", routeContext -> {
Contact contact = createContact();
routeContext.xml().negotiateContentType().send(contact);
});
}
}
In above example routeContext.xml().negotiateContentType().send(contact)
would set the default Content-Type as application/xml
and
then attempt to negotiate the client’s preferred type. If negotiation failed, then the default application/xml
would be sent and used to
serialize the outgoing object.