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/");
// Good
clientWithBaseUrl.get("/bar");
clientWithoutBaseUrl.get("https://foo.com/");
// Bad
clientWithBaseUrl.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:

















