Skip to content

Commit 9c8bf48

Browse files
committed
2 parents 72ca067 + ced9206 commit 9c8bf48

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

83 files changed

+2756
-2179
lines changed

frameworks/FSharp/oxpecker/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,5 @@ This includes tests for plaintext, json, fortunes, single query, mutliple querie
1919

2020
* [Oxpecker](https://github.com/Lanayx/Oxpecker)
2121
* [Npgsql](https://github.com/npgsql/npgsql)
22-
* [System.Text.Json](https://github.com/dotnet/runtime/tree/main/src/libraries/System.Text.Json)
22+
* [SpanJson](https://github.com/Tornhoof/SpanJson)
2323
* ASP.NET Core

frameworks/FSharp/oxpecker/src/App/App.fsproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
<ItemGroup>
1616
<PackageReference Update="FSharp.Core" Version="8.0.400" />
1717
<PackageReference Include="Oxpecker" Version="0.14.1" />
18+
<PackageReference Include="Oxpecker.ViewEngine" Version="0.14.0" />
1819
<PackageReference Include="Npgsql" Version="8.0.3" />
20+
<PackageReference Include="SpanJson" Version="4.2.0" />
1921
</ItemGroup>
2022
</Project>

frameworks/FSharp/oxpecker/src/App/Program.fs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ namespace App
22

33
open System
44
open Oxpecker
5+
open System.Runtime.InteropServices
56

67
[<RequireQualifiedAccess>]
78
module HtmlViews =
@@ -26,21 +27,20 @@ module HtmlViews =
2627
) |> RenderHelpers.prerender
2728

2829
let fortunes (fortunesData: ResizeArray<Fortune>) =
29-
RenderHelpers.combine head tail (
30-
__() {
31-
for fortune in fortunesData do
32-
tr() {
33-
td() { raw <| string fortune.id }
34-
td() { fortune.message }
35-
}
30+
let fragment = __()
31+
for fortune in CollectionsMarshal.AsSpan fortunesData do
32+
tr() {
33+
td() { raw <| string fortune.id }
34+
td() { fortune.message }
3635
}
37-
)
36+
|> fragment.AddChild
37+
RenderHelpers.combine head tail fragment
3838

3939
[<RequireQualifiedAccess>]
4040
module HttpHandlers =
4141
open System.Text
4242
open Microsoft.AspNetCore.Http
43-
open System.Text.Json
43+
open SpanJson
4444

4545
let private extra =
4646
{
@@ -98,9 +98,9 @@ module HttpHandlers =
9898
ctx.WriteBytes(result)
9999

100100
let jsonSimple value : EndpointHandler =
101-
let options = JsonSerializerOptions(JsonSerializerDefaults.Web)
102101
fun ctx ->
103-
ctx.Response.WriteAsJsonAsync(value, options)
102+
ctx.SetContentType("application/json")
103+
JsonSerializer.Generic.Utf8.SerializeAsync<_>(value, stream = ctx.Response.Body).AsTask()
104104

105105
let endpoints =
106106
[|

frameworks/Java/spring-webflux/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
<parent>
1414
<groupId>org.springframework.boot</groupId>
1515
<artifactId>spring-boot-starter-parent</artifactId>
16-
<version>3.3.1</version>
16+
<version>3.3.3</version>
1717
</parent>
1818

1919
<properties>

frameworks/Java/spring-webflux/src/main/java/benchmark/App.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,30 @@
11
package benchmark;
22

3+
import benchmark.web.ServerFilter;
4+
35
import org.springframework.boot.SpringApplication;
46
import org.springframework.boot.autoconfigure.SpringBootApplication;
7+
import org.springframework.context.annotation.Bean;
8+
import org.springframework.http.server.reactive.HttpHandler;
59
import org.springframework.scheduling.annotation.EnableScheduling;
10+
import org.springframework.web.reactive.function.server.HandlerStrategies;
11+
import org.springframework.web.reactive.function.server.RouterFunction;
12+
import org.springframework.web.reactive.function.server.RouterFunctions;
13+
import org.springframework.web.reactive.function.server.ServerResponse;
14+
import org.springframework.web.reactive.result.view.ViewResolver;
15+
import org.springframework.web.server.WebHandler;
16+
import org.springframework.web.server.adapter.WebHttpHandlerBuilder;
617

718
@SpringBootApplication
819
@EnableScheduling
920
public class App {
1021

22+
@Bean
23+
public HttpHandler httpHandler(RouterFunction<ServerResponse> route, ServerFilter serverFilter, ViewResolver viewResolver) {
24+
WebHandler webHandler = RouterFunctions.toWebHandler(route, HandlerStrategies.builder().viewResolver(viewResolver).build());
25+
return WebHttpHandlerBuilder.webHandler(webHandler).filter(serverFilter).build();
26+
}
27+
1128
public static void main(String[] args) {
1229
SpringApplication.run(App.class, args);
1330
}

frameworks/Java/spring-webflux/src/main/java/benchmark/web/WebfluxHandler.java renamed to frameworks/Java/spring-webflux/src/main/java/benchmark/web/DbHandler.java

Lines changed: 7 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,9 @@
22

33
import java.util.Collections;
44
import java.util.List;
5-
import java.util.Optional;
65
import java.util.concurrent.ThreadLocalRandom;
76

87
import benchmark.model.Fortune;
9-
import benchmark.model.Message;
108
import benchmark.model.World;
119
import benchmark.repository.DbRepository;
1210
import reactor.core.publisher.Flux;
@@ -21,26 +19,14 @@
2119
import static java.util.Comparator.comparing;
2220

2321
@Component
24-
public class WebfluxHandler {
22+
public class DbHandler {
2523

2624
private final DbRepository dbRepository;
2725

28-
public WebfluxHandler(DbRepository dbRepository) {
26+
public DbHandler(DbRepository dbRepository) {
2927
this.dbRepository = dbRepository;
3028
}
3129

32-
public Mono<ServerResponse> plaintext(ServerRequest request) {
33-
return ServerResponse.ok()
34-
.contentType(MediaType.TEXT_PLAIN)
35-
.bodyValue("Hello, World!");
36-
}
37-
38-
public Mono<ServerResponse> json(ServerRequest request) {
39-
return ServerResponse.ok()
40-
.contentType(MediaType.APPLICATION_JSON)
41-
.bodyValue(new Message("Hello, World!"));
42-
}
43-
4430
public Mono<ServerResponse> db(ServerRequest request) {
4531
int id = randomWorldNumber();
4632
Mono<World> world = dbRepository.getWorld(id)
@@ -52,7 +38,7 @@ public Mono<ServerResponse> db(ServerRequest request) {
5238
}
5339

5440
public Mono<ServerResponse> queries(ServerRequest request) {
55-
int queries = getQueries(request);
41+
int queries = parseQueryCount(request.queryParams().getFirst("queries"));
5642

5743
Mono<List<World>> worlds = Flux.range(0, queries)
5844
.flatMap(i -> dbRepository.getWorld(randomWorldNumber()))
@@ -64,21 +50,21 @@ public Mono<ServerResponse> queries(ServerRequest request) {
6450
});
6551
}
6652

67-
private static int parseQueryCount(Optional<String> maybeTextValue) {
68-
if (!maybeTextValue.isPresent()) {
53+
private static int parseQueryCount(String maybeTextValue) {
54+
if (maybeTextValue == null) {
6955
return 1;
7056
}
7157
int parsedValue;
7258
try {
73-
parsedValue = Integer.parseInt(maybeTextValue.get());
59+
parsedValue = Integer.parseInt(maybeTextValue);
7460
} catch (NumberFormatException e) {
7561
return 1;
7662
}
7763
return Math.min(500, Math.max(1, parsedValue));
7864
}
7965

8066
public Mono<ServerResponse> updates(ServerRequest request) {
81-
int queries = getQueries(request);
67+
int queries = parseQueryCount(request.queryParams().getFirst("queries"));
8268

8369
Mono<List<World>> worlds = Flux.range(0, queries)
8470
.flatMap(i -> dbRepository.findAndUpdateWorld(randomWorldNumber(), randomWorldNumber()))
@@ -101,10 +87,6 @@ public Mono<ServerResponse> fortunes(ServerRequest request) {
10187
.render("fortunes", Collections.singletonMap("fortunes", result));
10288
}
10389

104-
private static int getQueries(ServerRequest request) {
105-
return parseQueryCount(request.queryParam("queries"));
106-
}
107-
10890
private static int randomWorldNumber() {
10991
return 1 + ThreadLocalRandom.current().nextInt(10000);
11092
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package benchmark.web;
2+
3+
import java.util.Map;
4+
5+
import com.fasterxml.jackson.core.JsonProcessingException;
6+
import com.fasterxml.jackson.databind.ObjectMapper;
7+
import com.fasterxml.jackson.databind.ObjectWriter;
8+
import reactor.core.publisher.Mono;
9+
10+
import org.springframework.core.io.buffer.DataBuffer;
11+
import org.springframework.core.io.buffer.DataBufferFactory;
12+
import org.springframework.http.HttpHeaders;
13+
import org.springframework.http.MediaType;
14+
import org.springframework.stereotype.Component;
15+
import org.springframework.web.reactive.function.server.HandlerFunction;
16+
import org.springframework.web.reactive.function.server.ServerRequest;
17+
import org.springframework.web.reactive.function.server.ServerResponse;
18+
19+
@Component
20+
public class JsonHandler implements HandlerFunction<ServerResponse> {
21+
22+
private final ObjectWriter writer;
23+
24+
public JsonHandler(ObjectMapper objectMapper) {
25+
this.writer = objectMapper.writerFor(Map.class);
26+
}
27+
28+
@Override
29+
public Mono<ServerResponse> handle(ServerRequest request) {
30+
return ServerResponse.ok()
31+
.body((message, context) -> {
32+
DataBuffer buffer = serialize(request, Map.of("message", "Hello, world!"));
33+
HttpHeaders headers = message.getHeaders();
34+
headers.setContentLength(buffer.readableByteCount());
35+
headers.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
36+
return message.writeWith(Mono.just(buffer));
37+
});
38+
}
39+
40+
private DataBuffer serialize(ServerRequest request, Object object) {
41+
try {
42+
byte[] bytes = this.writer.writeValueAsBytes(object);
43+
return bufferFactory(request).wrap(bytes);
44+
}
45+
catch (JsonProcessingException ex) {
46+
throw new RuntimeException(ex);
47+
}
48+
}
49+
50+
private static DataBufferFactory bufferFactory(ServerRequest request) {
51+
return request.exchange().getResponse().bufferFactory();
52+
}
53+
54+
}

frameworks/Java/spring-webflux/src/main/java/benchmark/ServerFilter.java renamed to frameworks/Java/spring-webflux/src/main/java/benchmark/web/ServerFilter.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package benchmark.web;
22

3-
import io.netty.handler.codec.http.HttpHeaderNames;
43
import org.springframework.http.HttpHeaders;
54
import org.springframework.scheduling.annotation.Scheduled;
65
import org.springframework.stereotype.Component;
@@ -28,8 +27,8 @@ public void updateDate() {
2827
@Override
2928
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
3029
HttpHeaders headers = exchange.getResponse().getHeaders();
31-
headers.add(HttpHeaderNames.SERVER.toString(), SERVER_NAME);
32-
headers.add(HttpHeaderNames.DATE.toString(), this.date);
30+
headers.add(HttpHeaders.SERVER, SERVER_NAME);
31+
headers.add(HttpHeaders.DATE, this.date);
3332
return chain.filter(exchange);
3433
}
3534
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package benchmark.web;
2+
3+
import java.nio.charset.StandardCharsets;
4+
5+
import reactor.core.publisher.Mono;
6+
7+
import org.springframework.core.io.buffer.DataBufferFactory;
8+
import org.springframework.http.HttpHeaders;
9+
import org.springframework.http.MediaType;
10+
import org.springframework.stereotype.Component;
11+
import org.springframework.web.reactive.function.server.HandlerFunction;
12+
import org.springframework.web.reactive.function.server.ServerRequest;
13+
import org.springframework.web.reactive.function.server.ServerResponse;
14+
15+
@Component
16+
public class TextHandler implements HandlerFunction<ServerResponse> {
17+
18+
private static final byte[] TEXT_BODY = "Hello, World!".getBytes(StandardCharsets.UTF_8);
19+
20+
private static final String TEXT_BODY_LENGTH = String.valueOf(TEXT_BODY.length);
21+
22+
@Override
23+
public Mono<ServerResponse> handle(ServerRequest request) {
24+
return ServerResponse.ok()
25+
.body((message, context) -> {
26+
HttpHeaders headers = message.getHeaders();
27+
headers.add(HttpHeaders.CONTENT_LENGTH, TEXT_BODY_LENGTH);
28+
headers.add(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN_VALUE);
29+
return message.writeWith(Mono.just(bufferFactory(request).wrap(TEXT_BODY)));
30+
});
31+
}
32+
33+
private static DataBufferFactory bufferFactory(ServerRequest request) {
34+
return request.exchange().getResponse().bufferFactory();
35+
}
36+
37+
}
Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,32 @@
11
package benchmark.web;
22

3+
import reactor.core.publisher.Mono;
4+
35
import org.springframework.context.annotation.Bean;
46
import org.springframework.context.annotation.Configuration;
7+
import org.springframework.web.reactive.function.server.HandlerFunction;
58
import org.springframework.web.reactive.function.server.RouterFunction;
6-
import org.springframework.web.reactive.function.server.RouterFunctions;
79
import org.springframework.web.reactive.function.server.ServerResponse;
810

911
@Configuration
1012
public class WebfluxRouter {
1113

1214
@Bean
13-
public RouterFunction<ServerResponse> route(WebfluxHandler handler) {
14-
return RouterFunctions.route()
15-
.GET("/plaintext", handler::plaintext)
16-
.GET("/json", handler::json)
17-
.GET("/db", handler::db)
18-
.GET("/queries", handler::queries)
19-
.GET("/updates", handler::updates)
20-
.GET("/fortunes", handler::fortunes)
21-
.build();
15+
public RouterFunction<ServerResponse> route(
16+
TextHandler textHandler, JsonHandler jsonHandler, DbHandler dbHandler) {
17+
18+
return request -> {
19+
HandlerFunction<ServerResponse> fn = switch (request.uri().getRawPath()) {
20+
case "/plaintext" -> textHandler;
21+
case "/json" -> jsonHandler;
22+
case "/db" -> dbHandler::db;
23+
case "/queries" -> dbHandler::queries;
24+
case "/updates" -> dbHandler::updates;
25+
case "/fortunes" -> dbHandler::fortunes;
26+
default -> r -> ServerResponse.notFound().build();
27+
};
28+
return Mono.just(fn);
29+
};
2230
}
31+
2332
}

0 commit comments

Comments
 (0)