Assuming you already know what content types are and what thy are used for lets look at sending some with undertow. What is a content type?

Content Type Handlers

text/plain

// @WhereAreAllMyAnnotations??
// @DecoupledLogicFromRoutingIsNice!
public static void helloWorldText(HttpServerExchange exchange) {
    exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, "text/plain");
    exchange.getResponseSender().send("Hello World");
}
curl -v localhost:8080/helloWorldText
*   Trying ::1...
* connect to ::1 port 8080 failed: Connection refused
*   Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 8080 (#0)
> GET /helloWorldText HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.49.1
> Accept: */*
>
< HTTP/1.1 200 OK
< Connection: keep-alive
< Content-Type: text/plain
< Content-Length: 11
< Date: Tue, 10 Jan 2017 03:38:49 GMT
<
* Connection #0 to host localhost left intact
Hello World

text/html

public static void helloWorldHtml(HttpServerExchange exchange) {
    exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, "text/html");
    exchange.getResponseSender().send("<h1>Hello World</h1>");
}
curl -v localhost:8080/helloWorldHtml
*   Trying ::1...
* connect to ::1 port 8080 failed: Connection refused
*   Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 8080 (#0)
> GET /helloWorldHtml HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.49.1
> Accept: */*
>
< HTTP/1.1 200 OK
< Connection: keep-alive
< Content-Type: text/html
< Content-Length: 20
< Date: Tue, 10 Jan 2017 03:41:07 GMT
<
* Connection #0 to host localhost left intact
<h1>Hello World</h1>

application/octet-stream

public static void helloWorldFileDownload(HttpServerExchange exchange) {
    exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, "application/octet-stream");
    exchange.getResponseHeaders().put(Headers.CONTENT_DISPOSITION, "inline; filename=\"" + fileName + "\"");
    exchange.getResponseSender().send("Hello World");
}
curl -v localhost:8080/helloWorldFileDownload
*   Trying ::1...
* connect to ::1 port 8080 failed: Connection refused
*   Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 8080 (#0)
> GET /helloWorldFileDownload HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.49.1
> Accept: */*
>
< HTTP/1.1 200 OK
< Connection: keep-alive
< Content-Type: application/octet-stream
< Content-Length: 11
< Content-Disposition: inline; filename="helloworld.txt"
< Date: Tue, 10 Jan 2017 03:41:38 GMT
<
* Connection #0 to host localhost left intact
Hello World

application/json

public static void helloWorldJson(HttpServerExchange exchange) {
    exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, "application/json");
    exchange.getResponseSender().send("{\"message\": \"Hello World\"}");
}
curl -v localhost:8080/helloWorldJson
*   Trying ::1...
* connect to ::1 port 8080 failed: Connection refused
*   Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 8080 (#0)
> GET /helloWorldJson HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.49.1
> Accept: */*
>
< HTTP/1.1 200 OK
< Connection: keep-alive
< Content-Type: application/json
< Content-Length: 26
< Date: Tue, 10 Jan 2017 03:42:16 GMT
<
* Connection #0 to host localhost left intact
{"message": "Hello World"}

Content Type Routes

/*
 * Pretty clean am I right? Unless you REALLY REALLY love annotations
 * and the magic that comes with them. Don't forget about the copious
 * rabbit holes just trying to figure out what code executes because of
 * the annotation. This approach all code is just a few clicks away in
 * your IDE of choice. Your time is better spent writing code than pretending
 * to be a CSI cyber crimes specialist ripping apart some code for a clue to
 * whatever it does.
 */
public static final RoutingHandler ROUTES = new RoutingHandler()
    .get("/helloWorldText", ContentTypeHandlers::helloWorldText)
    .get("/helloWorldHtml", ContentTypeHandlers::helloWorldHtml)
    .get("/helloWorldFileDownload", ContentTypeHandlers::helloWorldFileDownload)
    .get("/helloWorldJson", ContentTypeHandlers::helloWorldJson)
    .get("/helloWorldJsonSender", ContentTypeHandlers::helloWorldJsonSender)
;

Content Type Server

public static void main(String[] args) {
    SimpleServer server = SimpleServer.simpleServer(ROUTES);
    server.start();
}

Not very difficult, do we really need frameworks to handle this for us? Boilerplate? sure, but a few convenience functions and it goes away. Lets go ahead and make it check out ContentTypeSenders.java and its implementation at Senders.java

Reduce the Boilerplate!

public static void helloWorldJsonSender(HttpServerExchange exchange) {
    Exchange.body().sendJson(exchange, "{\"message\": \"Hello World\"}");
}