0.92.0 release notes

23rd September 2019

New features

  • You can now easily get the request URI using RequestHeaders.uri() and HttpRequest.uri(). #2092
    RequestHeaders headers = RequestHeaders.of(HttpMethod.GET, "/foo",
                                               HttpHeaderNames.SCHEME, "https",
                                               HttpHeaderNames.AUTHORITY, "example.com"));
    assert headers.uri().equals(URI.create("https://example.com/foo"));
    assert HttpRequest.of(header).uri() == headers.uri();
  • You can now decorate the Runnable of the Thread created using ThreadFactoryBuilder. #2047 #2067
    ThreadFactories.builder(...)
                   .eventLoop(true)
                   .daemon(true)
                   .priority(...)
                   .taskFunction(task -> {
                       // Specify your logic here so it's executed before the Runnable.
                       task.run();
                       // Specify your logic here so it's executed after the Runnable.
                   })
                   .build();
  • You can now configure Server using Consumer<ServerBuilder> as well as ArmeriaServerConfigurator when integrating with Spring Boot. #2070
    @Bean
    public Consumer<ServerBuilder> customizer() {
        return sb -> sb.port(...)
                       ...
                       .service(...);
    }
  • You can now set example requests using AnnotatedServiceRegistrationBean. #1855 #2026
    @Bean
    public AnnotatedServiceRegistrationBean okService() {
        return new AnnotatedServiceRegistrationBean()
                .setServiceName("myAnnotatedService")
                .setPathPrefix("/my_service")
                .setService(new MyAnnotatedService())
                .setExampleRequests(Lists.of(
                        AnnotatedExampleRequest.of("myMethod", "{\"foo\":\"bar\"}")));
    }
  • You can be aware of whether the response content is empty from an HTTP status code. #2058
    HttpStatus status = ...
    if (!status.isContentAlwaysEmpty()) {
        // We may have a body!
    }
  • You can use SettableHealthIndicator for health check responses when using Spring boot autoconfigure. #2088

Improvements

  • You will see the doc service automatically scrolls down to the debug form if the URL contains a request. #1682 #2045
  • The performance for parsing a struct context in Thrift is improved, thanks to the Stack-Walking API in Java 9. #1686 #2055
  • You will see the int values of Enum members if they have in doc service. #1966 #2015
  • RequestContext instead of RequestLog is used for trace parsing and sampling. #2038

Bug fixes

  • You can now get the gRPC web trailers in the client. #2030 #2076
  • The actuator now responds with the correct Spring boot content type. #2061
  • The blocking stub in gRPC now can read messages. #2065 #2066
  • The listeners for EndpointGroup are notified after the first health check even when all endpoints are unhealthy. #2074 #2075
  • The subscriber who subscribes to the Response from a WebClient gets notified when it's complete. #2080 #2087
  • IllegalStateException that indicates the log should have at least one child is no longer raised when retrying. #2082 #2083
  • DefaultEventLoopScheduler respects maxNumEventLoopsPerHttpHttp1Endpoint set from ClientFactoryBuilder. #2086

Deprecation

  • The EventLoopThreadFactory has been deprecated in favor of ThreadFactories. #2067
    ThreadFactory factory = ThreadFactories.builder("myThread")
                                           .eventLoop(true)
                                           .build();

Breaking changes

  • Specifying an :authority header in a request has no effect anymore. The current Endpoint always determines the authority. #2092

    // This does NOT work anymore.
    final HttpClient client = HttpClient.of("https://127.0.0.1:8080/");
    client.execute(RequestHeaders.of(HttpMethod.GET, "/",
                                     HttpHeaderNames.AUTHORITY, "foo.com"));
    // This works.
    final HttpClient client =
            HttpClient.of(SessionProtocol.HTTPS,
                          Endpoint.of("foo.com", 8080).withIpAddr("127.0.0.1"));
    client.get("/");
    • Instead, you can now use ClientOption.HTTP_HEADERS or {Client,Service}RequestContext.additional{Request,Response}{Headers,Trailers}() to override the existing headers, including :authority. #2092

      // This works.
      final HttpHeaders customHeaders =
              HttpHeaders.of(HttpHeaderNames.AUTHORITY, "foo.com");
      final HttpClient client =
              HttpClient.of("http://127.0.0.1:8080/",
                            ClientOption.HTTP_HEADERS.newValue(customHeaders));
      client.get("/");
      
      // This also works.
      final HttpClient client = HttpClient.of("http://127.0.0.1:8080/");
      try (SafeCloseable ignored = Clients.withHttpHeader(
                   HttpHeaderNames.AUTHORITY, "foo.com")) {
          client.get("/");
      }
  • ExceptionHandlerFunction.handleExeption() accepts ServiceRequestContext instead of RequestContext. #2060

    • You don't have to downcast anymore. :)
  • GrpcServiceRegistrationBean.ExampleRequest has been removed. Use GrpcExampleRequest.

Dependencies

  • Micrometer 1.2.0 -> 1.2.1
  • Netty 4.1.39.Final -> 4.1.41.Final
  • Tomcat 9.0.24 -> 9.0.26
    • Tomcat8 8.5.43 -> 8.5.45

Thank you