You're seeing the release note of an old version. Check out the latest release note.
v0.99.7
June 22, 2020
🌟 New features
-
You can now specify the maximum lifespan of server-side connections using
ServerBuilder.maxConnectionAge(). This is useful when you have to deal with a load balancer without HTTP/2 support. #2747 #2796Server server =Server.builder().maxConnectionAge(Duration.ofMinutes(1))....build(); -
You can now record the name of the service that handled a request into
RequestOnlyLog.serviceName(). #2768 #2780 #2809 #2820-
By using
ServiceBindingBuilder.defaultServiceName():Server server =Server.builder().route().path("/service").defaultServiceName("my-service").build(new MyService()).build(); -
By using
@ServiceName:@ServiceName("my-service")public class MyAnnotatedService {@Get("/get")public String get() { ... }@Post("/set")@ServiceName("my-post-service")public String post(@Param String value) { ... }} -
Programmatically:
Server server =Server.builder().service("/service", (ctx, req) -> {ctx.logBuilder().serviceName("my-service");}).build(); -
Armeria will use the FQCN of the service class if you did not specify a service name.
-
-
You can now use
@Nullableannotation to specify an optional parameter or request object in annotated services. Previously, only the parameters with@Defaultannotation orOptionaltype were accepted. #2773public class MyAnnotatedService {// null will be injected into 'value' instead of returning// '400 Bad Request' when 'value' is missing.@Get("/get")public String get(@Param @Nullable String value) { ... }} -
You can now use the classes in the
java.timepackage in annotated services. #2760 #2783 #2792 #2799public class MyAnnotatedService {@Get("/sleep/{duration}")public void sleep(@Param Duration duration) { ... }} -
You can now determine whether a request was successful or not from HTTP trailers in
CircuitBreakerClientandRetryingClientusingonResponseTrailers()method. This can be useful when you work with gRPC, whose status code is encoded in thegrpc-statustrailer. #2816CircuitBreaker cb = CircuitBreaker.of("my-service");CircuitBreakerRule cbr =CircuitBreakerRule.builder().onResponseTrailers(trailers -> {return trailers.getInt("grpc-status", -1) != 0;}).thenFailure().build();MyServiceStub myService =Clients.builder("gproto+h2c://example.com/").decorator(CircuitBreakerClient.newDecorator(cb, cbr)).build(MyServiceStub.class); -
RequestLogsanitizers now acceptRequestContextas an additional input, so that the sanitizers can behave differently depending on the current path, etc. #2803Server server =Server.builder().decorator(LoggingService.builder().headersSanitizer((ctx, headers) -> {if (ctx.path().startsWith("/secret/")) {return "<secret>";} else {return headers;}}).newDecorator())....build(); -
Armeria now supports service discovery and registration for Curator Service Discovery and Finagle ServerSets. #2673 #2749 #2791
CuratorFramework curator = ...;// Client side://// Curator Service Discovery:EndpointGroup curatorEndpointGroup =ZooKeeperEndpointGroup.of(curator, "/discovery/curator",ZooKeeperDiscoverySpec.curator("my-service"));//// Finagle ServerSets:EndpointGroup serverSetsEndpointGroup =ZooKeeperEndpointGroup.of(curator, "/discovery/serversets"ZooKeeperDiscoverySpec.serverSets());// Server-side:Server server = ...;//// Curator Service Discovery:server.addListener(ZooKeeperUpdatingListener.of(curator, "/discovery/curator",ZooKeeperRegistrationSpec.curator("my-service")));//// Finagle ServerSets:server.addListener(ZooKeeperUpdatingListener.of(curator, "/discovery/serversets",ZooKeeperRegistrationSpec.serverSets())); -
You can now build
OAuth1aTokenmore conveniently using the builder API. #2770OAuth1aToken token =OAuth1aToken.builder().realm("...").consumerKey("...").token("...")....build(); -
The Spring Boot integration now hides all services under
/internal/for non-management ports whenmanagement.server.portproperty is set. #2408 #2502 -
The Spring Boot integration now supports the new graceful shutdown properties introduced in Spring Boot 2.3. #2784 #2802
-
Added a new API for handling reference counted or pooled objects such as
PooledHttpDatain a relatively safer way. #2448- See
PooledHttpData,PooledWebClient,PooledHttpRequestandPooledHttpResponsefor more information.
- See
📈 Improvements
- Cleaned up minor issues reported by errorprone. #2772
- Made some exception messages more user-friendly. #2751
🛠️ Bug fixes
- It's now allowed to specify an absolute URL only when a
WebClientwas created without a base URL. #2757WebClient clientWithoutBaseUrl = WebClient.of();WebClient clientWithBaseUrl = WebClient.of("https://example.com/");// GoodclientWithBaseUrl.get("/bar");clientWithoutBaseUrl.get("https://foo.com/");// BadclientWithBaseUrl.get("https://foo.com/");clientWithoutBaseUrl.get("/bar"); - Boolean parameter conversion became more strict in annotated services. #2767 #2774
- Only
true,false,1and0are accepted. Other values will cause a400 Bad Requestresponse.
- Only
DocServiceweb UI now shows the 'request body' field forDELETEandPATCHmethods in the debug form. #2756 #2819JacksonRequestConverterFunctionnow handles the case where the target type has a type parameter, e.g.List<Long>. #2769 #2779- Fixed a bug where the current
ServiceRequestContextis not pushed when invokingResponseConverterFunction.convertResponse(). #2789 RequestContextExportingAppendernow handles the<exports />tag correctly. #2781- Fixed a bug where some Reactive Streams
Subscriberimplementations violate the specification. #2815 - You no longer get sporadic
WriteTimeoutExceptionfrom proxied connections. #2801 #2805 - You no longer get a
CancelledSubscriptionExceptionunnecessarily when usingPublisherBasedStreamMessage. #2797 - You no longer get sporadic
EncoderExceptions from HTTP/1 connections. #2765 - It's now disallowed to specify the following headers in gRPC
Metadata. #2718:statusgrpc-messagegrpc-statusarmeria.grpc.ThrowableProto-bin
🏚️ Deprecations
AbstractUnwrappable.delegate()has been deprecated in favor ofUnwrappable.unwrap().
☢️ Breaking changes
- You can specify an absolute URL only when a
WebClientwas created without a base URL. It was previously allowed to specify an absolute URL even when created with a base URL. #2757 - The method signature of
RequestConverterFunction.convertRequest()has been changed to support parameterized types. #2779 - The default
MeterIdPrefixFunctionreturned byMeterIdPrefixFunction.ofDefault()now generates the meter IDs with different tags. #2780- The
routetag has been replaced with theservicetag.
- The
RetrofitMeterIdPrefixFunctionBuilderhas been removed and superseded byRequestOnlyLog.serviceName(). #2780- ZooKeeper-based service discovery: #2749 #2791
- You now must specify
ZooKeeperRegistrationSpecorZooKeeperDiscoverySpecwhen creatingZooKeeperUpdatingListenerorZooKeeperEndpointGroup. NodeValueCodechas been removed.ZooKeeperEndpointGroupBuilder.codec()andZooKeeperUpdatingListenerBuilder.codec()have been removed.
- You now must specify
ByteBufHttpDatahas been replaced withPooledHttpData. #2448HttpRequest.aggregateWithPooledObjects()andHttpResponse.aggregateWithPooledObjecthave been replaced withPooledHttpRequestandPooledHttpResponse. #2448SubscriptionOption.WITH_POOLED_OBJECTShas been removed. #2448
⛓ Dependencies
- Bouncy Castle 1.65 → 1.65.01
- Dropwizard 2.0.9 → 2.0.10
- gRPC 1.29.0 → 1.30.1
- Jetty 9.4.29 → 9.4.30
- Reactor 3.3.5 → 3.3.6
- Spring Boot 2.3.0 → 2.3.1, 2.1.14 → 2.1.15
- Tomcat 9.0.35 → 9.0.36, 8.5.55 → 8.5.56
- Example dependencies
- Dagger 2.27 → 2.28
- grpc-kotlin-stub 0.1.2 → 0.1.3
🙇 Thank you
This release was possible thanks to the following contributors who shared their brilliant ideas and awesome pull requests:

















