Skip to content

Mime

Media types are the web's notion for file extensions. They're present in requests and responses as Content-Type directives. Methanol's MediaType facilitates the representation and manipulation of media types.

MediaType

You can create a MediaType from its individual components or parse one from a Content-Type string.

var applicationJsonUtf8 = MediaType.of("application", "json", Map.of("charset", "UTF-8")); 

assertEquals("application", applicationJsonUtf8.type());
assertEquals("json", applicationJsonUtf8.subtype());
assertEquals("utf-8", applicationJsonUtf8.parameters().get("charset"));
assertEquals(Optional.of(StandardCharsets.UTF_8), applicationJsonUtf8.charset());
var applicationJsonUtf8 = MediaType.parse("application/json; charset=UTF-8");

assertEquals("application", applicationJsonUtf8.type());
assertEquals("json", applicationJsonUtf8.subtype());
assertEquals("utf-8", applicationJsonUtf8.parameters().get("charset"));
assertEquals(Optional.of(StandardCharsets.UTF_8), applicationJsonUtf8.charset());

Media Ranges

A MediaType also defines a media range to which one or more media types belong, including itself.

var anyTextType = MediaType.parse("text/*");
var textHtml = MediaType.parse("text/html");
var applicationJson = MediaType.parse("application/json");

assertTrue(anyTextType.hasWildcard());
assertTrue(anyTextType.includes(textHtml));
assertFalse(anyTextType.includes(applicationJson));
assertTrue(anyTextType.isCompatibleWith(textHtml));
assertTrue(textHtml.isCompatibleWith(anyTextType));

Tip

MediaType has static definitions for the most popular media types & ranges. None of them, however, defines a charset parameter. You can use MediaType::withCharset to derive media types with charsets from the statically defined ones.

static final MediaType APPLICATION_JSON_UTF8 = 
    MediaType.APPLICATION_JSON.withCharset(StandardCharsets.UTF_8);

MimeBodyPublisher

MimeBodyPublisher is a mixin-style interface that associates a MediaType with a BodyPublisher. It's recognized by Methanol and multipart bodies in that it gets the appropriate Content-Type header implicitly added.

You can adapt an arbitrary BodyPublisher into a MimeBodyPublisher. Here's a factory method that creates MimeBodyPublihers for files. The file's media type is probed from the system, falling back to application/octet-stream if that doesn't work.

static MimeBodyPublisher ofMimeFile(Path file) throws FileNotFoundException {
  MediaType mediaType = null;
  try {
    var contentType = Files.probeContentType(file);
    if (contentType != null) {
      mediaType = MediaType.parse(contentType);
    }
  } catch (IOException ignored) {
  }

  return MoreBodyPublishers.ofMediaType(
      BodyPublishers.ofFile(file),
      requireNonNullElse(mediaType, MediaType.APPLICATION_OCTET_STREAM));
}

final Methanol client = Methanol.create();

<T> HttpResponse<T> post(String url, Path file, BodyHandler<T> handler)
    throws IOException, InterruptedException {
  // Request's Content-Type is implicitly added
  return client.send(MutableRequest.POST(url, ofMimeFile(file)), handler);
}