You're seeing the release note of an old version. Check out the latest release note.
v1.9.0
June 23, 2021
🌟 New features
-
A new module
armeria-graphqlintegrates with GraphQL Java to let you serve GraphQL requests. #3318 #3373ServerBuilder sb = ...;sb.service("/graphql",GraphqlService.builder().schemaFile(schemaFiles).runtimeWiring(w -> ...).configureDataLoaderRegistry(registry -> ...)....build());tiparmeria-graphqlis currently experimental. We're looking forward to your feedback. -
You can now transform the objects of
HttpRequestandHttpResponseusing a function. #3606 #3624HttpRequest req1 = ...;HttpRequest req2 =req1.mapHeaders(headers -> headers.toBuilder().add("TraceId", "1").build()).mapData(data -> HttpData.ofUtf8(data.toStringUtf8() + '\n')).mapTrailers(trailers -> trailers.toBuilder().add("trailer-key", "val").build())HttpResponse res1 = ...;HttpResponse res2 =res1.mapHeaders(headers -> headers.toBuilder().add("SessionId", "123").build()).mapInformational(informational -> {return informational.withMutations(builder -> {builder.add(HttpHeaderNames.USER_AGENT, "Armeria");});}).mapData(data -> HttpData.ofUtf8(data.toStringUtf8().replaceAll("\n", "<br/>"))).mapTrailers(trailers -> trailers.toBuilder().add("result", "0").build()); -
You can now collect the all elements of a
StreamMessagewithStreamMessage.collect(). #3603StreamMessage<Integer> stream = StreamMessage.of(1, 2, 3);CompletableFuture<List<Integer>> collected = stream.collect();assert collected.join().equals(List.of(1, 2, 3)); -
You can exclude a
Routefrom anotherRoutewhen configuring a service. #2737 #3562ServerBuilder sb = ...;sb.route().pathPrefix("/api").exclude("prefix:/api/admin").exclude(Route.builder().pathPrefix("/api/v1").consumes(MediaType.JSON).build()).build(apiService);sb.routeDecorator().pathPrefix("/api").exclude("prefix:/api/admin").build(MetricCollectingService.newDecorator()); -
You can now update the service bindings without restarting a
ServerusingServer.reconfigure(). #3041 #3362 Note that there are some limitations on theServerreconfiguration. Please check out #3041 for details.Server server = ...;server.reconfigure(sb -> {sb.service("/dynamic", new LazyService());}); -
You can now use
RequestOptionsto configure various options at request level. #3593HttpRequest req = ...;WebClient client = ...;RequestOptions options =RequestOptions.builder().responseTimeout(Duration.ofSeconds(20)).writeTimeout(Duration.ofSeconds(5)).maxResponseLength(2048).attr(foo, "bar").build();// Specify RequestOptions when sending a request.client.execute(req, options);// You can also specify the options when building a request// using WebClientRequestPreparation.client.prepare().get("/some/path").responseTimeout(Duration.ofSeconds(20)).writeTimeout(Duration.ofSeconds(5)).maxResponseLength(2048).attr(foo, "bar").execute(); -
You can now fluently build a
BlockingTaskExecutorusingBlockingTaskExecutorBuilder. #3315 #3389BlockingTaskExecutor.builder().daemon(true).numThreads(500).threadNamePrefix("my-blocking-task-executor").build(); -
You can now easily get a boolean value from
QueryParamsandHttpHeaders. #3600HttpHeaders headers = HttpHeaders.of("checked", "true", "valid", "1");assert headers.getBoolean("checked");assert headers.getBoolean("valid");QueryParams params = QueryParams.of("checked", "false", "valid", "0");assert !params.getBoolean("checked");assert !params.getBoolean("valid"); -
You can now conveniently configure a loopback port with
ServerBuilder.localPort(). #3599 #3601Server.builder().localPort(8080).localPort(9090, SessionProtocol.HTTP, SessionProtocol.HTTPS); -
All Jackson modules in the class loader are registered automatically by default via Jackson's built-in SPI mechanism for your convenience.
- You can override this behavior by registering your
JacksonModuleProviderimplementation via Java SPI. #3594 #3625
- You can override this behavior by registering your
-
TCP user timeout option is now enabled by default when an idle timeout is enabled. #3509
TCP_KEEPIDLEandTCP_KEEPINTVLoptions are enabled when a PING interval is greater than 0.
-
You can now get the last value of a header or a query parameter using
HttpHeaders.getLast()andQueryParams.getLast(). #3438 #3568HttpHeaders headers =HttpHeaders.builder().add(HttpHeaderNames.X_FORWARDED_FOR,List.of("203.0.113.195", "150.172.238.178")).build();assert headers.getLast(HttpHeaderNames.X_FORWARDED_FOR).equals("150.172.238.178");QueryParams params =QueryParams.builder().add("items", List.of("1", "2", "3")).build();assert params.getLastInt("items").equals(3); -
ContentTooLargeExceptionnow provides you the following 3 properties about why the exception was raised. #3520, #3616- The maximum allowed content length
- The content length specified in the
content-lengthheader - The number of bytes transferred so far
-
You can now convert a
Multipartinto anHttpResponse. #3642 -
You can now warm up an
EventLoopGroupusingEventLoopGroups.warmUp(). #3363 #3610 -
You can now figure out the number of connections managed by a
ClientFactorywithClientFactory.numConnections(). #3596 #3613 -
You can now specify the number of event loop threads and blocking task threads more conveniently. #3597 #3602
Server.builder().workerGroup(3).blockingTaskExecutor(10)....build();ClientFactory.builder().workerGroup(3).build(); -
You can now clear the mocking state of a
MockWebServerExtensionusingMockWebServerExtension.reset(). #3629
📈 Improvements
- Various optimizations for
StreamMessageimplementations. #3585 #3584 - You can now use an optimized context-aware
CompletableFuturefor Java 12 and above. #2119 #3615 - Various multipart MIME types were added to
MediaType. #3642
🛠️ Bug fixes
ByteBufs are no longer leaked when using:- Spring WebFlux integration with compression #3608 #3617; or
StreamMessageDuplicator#3476 #3583
- You no longer see a
ResponseTimeoutExceptionwithCircuitBreakerClientwhen a large number of messages are received from a response. #3631 - You can now set the service name of an annotated service using
the
ServerBuilder.defaultServiceNaming(). #3589 - You no longer see a
ClosedStreamExceptionwhen anEndpointGroupis empty. #3381 #3636 - Late
Subscribers correctly run on the specified executor. #3623 #3632 - An exception raised in
THttpServiceis now properly peeled usingExceptions.peel(). #3588 - You no longer see an
UnsatisfiedLinkErrorwhen a Netty JAR without native libraries is included. #3485 #3607 - Additional headers are now correctly updated to
RequestOnlyLog.requestHeaders(). #3579 #3581 - A timeout is more precisely scheduled for a request or a response. #3570
- You no longer see a duplicate
Content-Typeheader when usingMultipart. #3642
⛓ Dependencies
- Bouncy Castle 1.68 → 1.69
- Dropwizard 2.0.21 → 2.0.23
- Dropwizard Metrics 4.1.21 → 4.2.2
- Eureka 1.10.13 → 1.10.15
- gRPC-Java 1.37.0 → 1.38.1
- gRPC-Kotlin 1.0.0 → 1.1.0
- JBoss logging 3.4.1 → 3.4.2
- Jetty 9.4.39 → 9.4.42
- Kotlin 1.5.0 → 1.5.10
- Kotlin Coroutines 1.4.3 → 1.5.0
- Netty 4.1.63 → 4.1.65
- netty-tcnative-boringssl-static 2.0.38 → 2.0.39
- Prometheus 0.10.0 → 0.11.0
- Reactor 3.4.6 → 3.4.7
- RESTEasy 4.6.0 → 4.6.1
- RxJava 3.0.12 → 3.0.13
- Scala
- 2.12.13 → 2.12.14
- 2.13.5 → 2.13.6
- ScalaPB runtime 0.11.2 → 0.11.3
- ScalaPB json4s 0.11.0 → 0.11.1
- SLF4J 1.7.30 → 1.7.31
- Spring 5.3.7 → 5.3.8
- Spring Boot 2.4.5 → 2.5.1
- Tomcat
- 8.5.64 → 8.5.68
- 9.0.44 → 9.0.46
- Thrift 0.14.1 → 0.14.2
🙇 Thank you
This release was possible thanks to the following contributors who shared their brilliant ideas and awesome pull requests:

















