0.80.0 release notes
19th February 2019
New features
A user now can see the content of HTTP request/response in logs. #1574
ServerBuilder sb = new ServerBuilder(); // Enables previewing the content with the maximum length of 100 for textual contents. sb.contentPreview(100); // A user can use their customized previewer factory. sb.contentPreviewerFactory((ctx, headers) -> { return ContentPreviewer.ofBinary(100, byteBuf -> { byte[] contents = new byte[Math.min(byteBuf.readableBytes(), 100)]; byteBuf.readBytes(contents); return BaseEncoding.base16().encode(contents); }); });
Added
ClientRequestContextBuilder
andServiceRequestContextBuilder
. #1548- A user can create a mock of
RequestContext
. - A user can emulate an incoming request and feed it into his or her processing pipeline.
@Test public void testService() throws Exception { // Given HttpRequest req = HttpRequest.of(HttpMethod.POST, "/greet", MediaType.JSON_UTF_8, "{ \"name\": \"foo\" }"); ServiceRequestContext sctx = ServiceRequestContext.of(req); // When HttpResponse res = service.serve(sctx, req); // Then AggregatedHttpMessage aggregatedRes = res.aggregate().get(); assertEquals(200, aggregatedRes.status().code()); }
- A user can create a mock of
A user can use
@CorsDecorator
in annotated services. #1547sb.annotatedService("/cors6", new Object() { @Get("/any/get") @CorsDecorator(origins = "*", exposedHeaders = { "expose_header_1", "expose_header_2" }, allowedRequestHeaders = { "allow_request_1", "allow_request_2" }, allowedRequestMethods = HttpMethod.GET, maxAge = 3600, preflightRequestHeaders = { @AdditionalHeader(name = "x-preflight-cors", value = "Hello CORS") }) public HttpResponse anyoneGet() { return HttpResponse.of(HttpStatus.OK); } }
Added
ClientFactoryBuilder.domainNameResolverCustomizer()
so that a user can customize the resolver easily. #1553ClientFactory f = new ClientFactoryBuilder() .domainNameResolverCustomizer(resolverBuilder -> { resolverBuilder.maxQueriesPerResolve(10); resolverBuilder.traceEnabled(false); }) .build();
A user can define a custom annotation which attaches other annotations for simplicity. #1560
// Define a custom annotation: @ProducesJson @LoggingDecorator @interface MyApiSpecification {} // Apply it to the annotated HTTP service: @Get("/api") @MyApiSpecification // You can use one annotation which holds other other annotations. public Something getSomething() {}
Added
@AdditionalHeader
and@AdditionalTrailer
to insert headers easily in annotated services. #1555Added a way to add multiple gRPC services with a single method call. #1563
// Before GrpcService s = new GrpcServiceBuilder().addService(a) .addService(b) .build(); // After GrpcService s = new GrpcServiceBuilder().addServices(a, b).build();
Added more shortcut methods for convenience. #1576
HttpRequest req = ...; AggregatedHttpMessage aggregated = ...; MediaType contentType; String content; // Before contentType = req.headers().contentType(); contentType = aggregated.headers().contentType(); content = aggregated.content().toStringUtf8(); // After contentType = req.contentType(); contentType = aggregated.contentType(); content = aggregated.contentUtf8();
RequestObject
is shown inDocService
. #1557Added
verboseSocketExceptions
flag so that a user can ignore harmless socket-related error message. #1577Added automatic directory listing generation to
HttpFileService
. #1573Added
armeria-spring-boot-actuator
dependency. #1578- Works without Spring Web or Webflux.
Added metrics related to timeouts. #1589
Added
responseCauseSanitizer
toLoggingDecoratorBuilder
. #1594- A user can sanitize the stack trace of
RequestLog.responseCause()
or avoid logging the stack trace completely.
ServerBuilder sb = ... final Function<Throwable, Throwable> responseCauseSanitizer = cause -> { if (cause instanceof AnticipatedException) { return null; // Do not log when AnticipatedException is raised. } return cause; }; sb.decorator(new LoggingServiceBuilder().requestLogLevel(LogLevel.INFO) .successfulResponseLogLevel(LogLevel.INFO) .responseCauseSanitizer(responseCauseSanitizer) .newDecorator());
- A user can sanitize the stack trace of
A user can easily send Server-Sent Events. #1551
public class MyAnnotatedService { @Get("/publisher") @ProducesEventStream public Publisher<ServerSentEvent<?>> publisher() { return Flux.just(ServerSentEvent.ofData("foo"), ServerSentEvent.ofData("bar"), ServerSentEvent.ofData("baz"), ServerSentEvent.ofData("qux")); } }
Improvements
- User-friendly message when
400 Bad Request
happens. #1575 - Enabled DNS query traces by default. #1553
- Added
armeria-retry-count
header whenRetryingClient
is used. #1593
Bug fixes
- Fixed a bug where
httpStatus
tag is not set properly. #1559 - Do not set
Content-length
header when HTTP trailers exist. #1566 - Fixed a bug where max request length is not set correctly in
GrpcService
when the value is0
orLong.MAX_VALUE
. #1549 - Fixed a but where gRPC JSON marshaller is initialized even when unnecessary. #1558
- Fixed a bug where gRPC callbacks are not executed in order. #1600
Breaking Change
- The
HttpHeaders
inAggregatedHttpMessage
is immutable.- You should call
headers.toMutable()
to set or remove a header.
- You should call
Deprecations
RequestContext.isTimedOut()
has been deprecated. #1589- Use
ServiceRequestContext.isTimedOut()
instead.
- Use
Dependencies
- Bouncy Castle 1.60 -> 1.61
- Brave 5.6.0 -> 5.6.1
- java-jwt 3.5.0 -> 3.7.0
- Micrometer 1.1.2 -> 1.1.3
- Netty 4.1.32 -> 4.1.33
- Project Reactor 3.2.5 -> 3.2.6
- protobuf-jackson 0.3.0 -> 0.3.1
- RxJava 2.2.5 -> 2.2.6
- Thrift 0.11.0 -> 0.12.0
- Tomcat 9.0.14 -> 9.0.16, 8.5.37 -> 8.5.38
- spring-boot-starter-actuator has been removed from the transitive dependencies.