You're seeing the release note of an old version. Check out the latest release note.
v1.14.0
January 27, 2022
🌟 New features
-
You can now use Scala 3 for
armeria-scalaandarmeria-scalapb. #3614 #4036tipScala 3 modules are currently experimental. We're looking forward to your feedback.
-
You can now fluently convert an
HttpResponseinto a desired type usingWebClient. #4021WebClient client = WebClient.of("https://api.example.com");
CompletableFuture<ResponseEntity<MyObject>> response =
client.prepare()
.get("/v1/items/1")
.asJson(MyObject.class)
.execute(); -
You can now use
BlockingWebClientto wait for anHttpResponseto be completed. #4021BlockingWebClient client = BlockingWebClient.of("https://api.example.com");
ResponseEntity<MyObject> response =
client.prepare()
.get("/v1/items/1")
.asJson(MyObject.class)
.execute();tipNote that you should never use this client in an
EventLoopthread. Use it from a non-EventLoopthread such asBlockingTaskExecutor. -
You can now fluently build a gRPC client with various options using
GrpcClientBuilder. #3981 #3999 #3964 #3975GrpcClients
.builder(...)
.decorator(myDecorators)
.maxResponseMessageLength(MAX_MESSAGE_SIZE)
.jsonMarshallerFactory(descriptor -> {
...
})
.intercept(myInterceptors)
.build(MyStub.class); -
You can now fluently build an
HttpResponseby usingHttpResponseBuilder. #3398 #3941HttpResponse
.builder()
.ok()
.header(HttpHeaderNames.USER_AGENT, "Armeria")
.content(content)
.build(); -
You can now use
StreamMessage.mapAsync()to transform aStreamMessageusing an async operation. #3916 #3962StreamMessage<Integer> userIds = StreamMessage.of(...);
StreamMessage<UserInfo> userInfos = userIds.mapAsync(this::getUserInfo);
CompletableFuture<UserInfo> getUserInfo(int userId) {
...
} -
You can now use
HttpResponse.peekHeaders(),HttpMessage.peekData(),HttpMessage.peekTrailers()andStreamMessage.peekError()operators onHttpRequestandHttpResponse. #3097 #3988 #3949HttpRequest request =
HttpRequest.of(RequestHeaders.of(HttpMethod.POST, "/items"),
HttpData.ofUtf8("data1,data2"))
HttpHeaders.of("trailer", "foo"));
HttpRequest peeked =
request.peekData(data -> {
assert data.toStringUtf8().equals("data1,data2");
}).peekTrailers(trailers -> {
assert trailers.get("trailer").equals("foo");
});
HttpRequest failed =
HttpRequest.ofFailure(new IllegalStateException("Something went wrong."));
HttpRequest peeked = failed.peekError(cause -> {
assert cause instanceof IllegalStateException;
}); -
You can now generate an error response differently in
ServerErrorHandlerdepending on theRequestHeaders. #4037 -
You can now use
{*var}and:*varpath patterns to capture rest paths of a request. #3031 #3997Server
.builder()
.service("/api/{item}/route/{*contents}", (ctx, req) -> {
// If a request path is "/api/123/route/foo/bar/baz",
// '*contents' should be foo/bar/baz
assert ctx.pathParam("contents").equals("foo/bar/baz");
}); -
You can now use
ServiceRequestContext.queryParams()to get the decoded query parameters. #3955 #3960 -
You can now send query parameters using
QueryParamswithWebClient. #3915 #3921QueryParams params = QueryParams.of("foo", "bar");
WebClient client = ...;
// Sends 'GET /api/items/1?foo=bar'
client.get("/api/items/1", params);
// Sends 'POST /api/items?foo=bar' with body '...'
client.post("/api/items", params, content); -
You can now write a
StreamMessage<HttpData>into a file usingStreamMessages.writeTo(). #3870 #3874StreamMessage<HttpData> stream = ...;
Path destination = ...;
StreamMessages.writeTo(stream, destination); -
You can now force a state transition of a
CircuitBreakerby usingCircuitBreaker.enterState(). #4010 #4022CircuitBreaker circuitBreaker = CircuitBreaker.of(...);
circuitBreaker.enterState(CircuitState.FORCED_OPEN); -
You can now conveniently create a
RetryRuleandRetryRuleWithContentby specifying aBackoff. #3875 #2899 #3895RetryRule.failsafe(Backoff.fixed(1000));
RetryRuleWithContent.onException(Backoff.fixed(2000)); -
You can now dynamically change the maximum number of concurrent active requests of a
ConcurrencyLimitingClient. #3842 #3985ConcurrencyLimitingClient.newDecorator(new DynamicLimit());
class DynamicLimit implements IntSupplier {
@Override
public int getAsInt() {
// Dynamically returns the current limitation.
...
}
} -
You can now split an
HttpRequestintoRequestHeaders,StreamMessage<HttpData>and trailers usingHttpRequest.split(). #3924 #3953HttpRequest request = HttpRequest.of(...);
SplitHttpRequest splitRequest = request.split();
RequestHeaders headers = splitRequest.headers();
StreamMessage<HttpData> body = splitRequest.body();
CompletableFuture<HttpHeaders> trailers = splitRequest.trailers(); -
Added more well-known MIME type constants to
MediaType. #4040 -
You can now customize the
MediaTypeof a file when usingFileService. #4001 #4009FileService
.builder(resource)
.mediaTypeResolver((path, contentEncoding) -> {
if (path.endsWith(".proto")) {
return MediaType.PROTOBUF;
}
if (path.endsWith(".csv")) {
return MediaType.CSV_UTF_8;
}
// Pass to the default resolver.
return null;
})
.build(); -
You can now send requests to a test server by using
ServerExtension.webClient()orServerRule.webClient(). #3761 #3890@RegisterExtension
static ServerExtension server = new ServerExtension() {
@Override
protected void configure(ServerBuilder sb) {
...
}
};
@Test
void test() {
WebClient client = server.webClient(cb -> { // 👈👈👈
cb.decorator(LoggingClient.newDecorator());
});
client.get("/foo").aggregate().join();
} -
You can now export metrics as OpenMetrics format using
PrometheusExpositionService. #3926 #3928 -
You can now use
UnframedGrpcStatusMappingFunctionto customize how a gRPC status is mapped to anHttpStatuswhen using an unframed gRPC service. #3683 #3948UnframedGrpcStatusMappingFunction mappingFunction =
(ctx, grpcStatus, cause) -> {
if (grpcStatus.getCode() == DEADLINE_EXCEEDED) {
return INTERNAL_SERVER_ERROR;
}
// Pass to the default mapping function.
return null;
};
UnframedGrpcErrorHandler errorHandler =
UnframedGrpcErrorHandler.ofJson(mappingFunction);
GrpcService
.builder()
.unframedGrpcErrorHandler(errorHandler); -
You can now expose
WebOperations of Actuator to a port of internal services. #3919 #3946armeria:
...
internal-services:
# Actuator will be exposed to 18080 port.
include: actuator, health
port: 18080 -
Added
JettyServiceBuilder.tlsReverseDnsLookup()that makesJettyServiceperform a reverse DNS lookup for each TLS connection, which may be useful for servlets that assumeServletRequest.getRemoteHost()will return a remote host name rather than a remote IP address. -
Added
JettyServiceBuilder.httpConfiguration()that allows a user to set JettyHttpConfigurationin a type-safe manner.
📈 Improvements
- You can now distinguish services, messages and enums with the same name by their package names from
DocServiceUI. #3979 - Improved the memory footprint of
PrometheusExpositionServiceby removing large byte array allocations. #3929 - Meters created by
MoreMetersare now using more accurate percentiles. #4047
🛠️ Bug fixes
- You no longer see
ClassCastExceptionwhen duplicating anHttpRequestor anHttpResponse. #4030 #4032 - You no longer see
IllegalArgumentExceptionif an upper-bounded wildcard type with@Paramis used in annotated services. #4007 #4008 - You can now properly get
SameSiteattribute fromCookie.sameSite(). #3968 #3984 - You no longer see an
EmptyEndpointGroupExceptionwhen anEndpointGroupis successfully resolved with the initialEndpoints. #3978 HttpRequestBuilder.header()does not overwrite an old header value anymore. #3932 #3941- A new header value will be appended to the old value.
- You no longer see
413 Request Entity Too Largewhen a server receives a cleartext (h2c) upgrade request larger than 16384 bytes. #3859 #3913- The maximum allowed length of an upgrade request will respect
ServerBuilder.maxRequestLength()orVirtualHost.maxRequestLength().
- The maximum allowed length of an upgrade request will respect
- Fixed
Multipartdecoder to correctly publish chunks one by one when streaming a largeBodyPart. #3774 #3783 - You can now use
google.protobuf.{Struct, Value, ListValue, Any}messages from yourprotofiles when using gRPC-JSON transcoder. #3986 #3992 GrpcServicenow automatically disables gRPC-JSON serialization for Protobuf 2 services rather than throwing an exception. #4020 #4033FileServicenow keeps query parameters when redirecting to a directory. #4049 #4050- You no longer see
InvocationTargetExceptionwith a Kotlin method whose return type isNothingin an annotated service. #3961 #4005 - Actuator now correctly shows
LivenessandReadinessof a Kubernetes instance. #3031 #3997
🏚️ Deprecations
CircuitBreaker.canRequest()has been deprecated in favor ofCircuitBreaker.tryRequest(). #4012Cookie.builder()andCookie.of()have been deprecated in favor ofCookie.secureBuilder()andCookie.ofSecure(). #3788 #3939GrpcServiceBuilder.setMaxInboundMessageSizeBytes()andGrpcServiceBuilder.setMaxOutboundMessageSizeBytes()have been deprecated in favor ofGrpcServiceBuilder.maxRequestMessageLength()andGrpcServiceBuilder.maxResponseMessageLength(). #3999AbstractBlockingHttpVfs.get(Executor,String,Clock,String,HttpHeaders)has been deprecated in favor ofAbstractBlockingHttpVfs.get(Executor,String,Clock,String,HttpHeaders,MediaTypeResolver). #4009HttpVfs.get(Executor,String,Clock,String,HttpHeaders)has been deprecated in favor ofHttpVfs.get(Executor,String,Clock,String,HttpHeaders,MediaTypeResolver). #4009
☢️ Breaking changes
HealthChecker.of(Supplier,Duration)andHealthChecker.of(Supplier,Duration,EventExecutor)now returnsListenableHealthCheckerinstead ofHealthChecker. #4017ServerErrorHandler.renderStatus()now requires an additional parameterRequestHeaders. #4037- This allows a user to generate a different error response depending on the request header value.
⛓ Dependencies
- Brave 5.13.3 → 5.13.7
- Bouncy Castle 1.69 → 1.70
- Bucket4J 6.3.0 → 7.0.0
- Caffeine 2.9.2 → 2.9.3
- Dropwizard 2.0.25 → 2.0.28
- Dropwizard Metrics 4.2.4 → 4.2.7
- gRPC Java 1.41.1 → 1.43.2
- gRPC Kotlin 1.1.0 → 1.2.1
- Jackson 2.13.0 → 2.13.1
- java-jwt 3.18.2 → 3.18.3
- SLF4J 1.7.32 → 1.7.34
- jboss-logging 3.4.2 → 3.4.3
- Kafka 3.0.0 → 3.1.0
- Kotlin 1.5.32 → 1.6.10
- Logback 1.2.7 → 1.2.10
- Micrometer 1.7.6 → 1.8.2
- Netty 4.1.70 → 4.1.73
- io_uring 0.0.1 → 0.0.11
- Prometheus 0.12.0 → 0.14.1
- protobuf-jackson 1.2.0 → 2.0.0
- protobuf-java 3.17.3 → 3.19.2
- Reactor 3.4.12 → 3.4.14
- RESTEasy 4.7.3 → 5.0.2
- Scala 2.13.7 → 2.13.8, ⓧ → 3.1.1
- scala-collection-compat 2.5.0 → 2.6.0
- ScalaPB 0.11.6 → 0.11.8
- Spring 5.3.13 → 5.3.15
- Spring Boot 2.5.7 → 2.6.3
- Tomcat 9.0.55 → 9.0.56
🙇 Thank you
This release was possible thanks to the following contributors who shared their brilliant ideas and awesome pull requests:






























