Ver código fonte

Fix and add more benchmarks for Micronaut (#7622)

* Fix and more benchmarks for Micronaut

* Improvements

* Improvements

* Correct R2DBC settings

* Fix vertx graalvm compile

* Use latest GraalVM

* Disable Netty's resource leak detector

* Remove Micronaut Data R2DBC for now
Denis Stepanov 2 anos atrás
pai
commit
9ca2744772
87 arquivos alterados com 2355 adições e 460 exclusões
  1. 1 15
      frameworks/Java/micronaut/README.md
  2. 187 3
      frameworks/Java/micronaut/benchmark_config.json
  3. 0 88
      frameworks/Java/micronaut/build.gradle
  4. 13 0
      frameworks/Java/micronaut/buildSrc/build.gradle
  5. 42 0
      frameworks/Java/micronaut/buildSrc/src/main/groovy/io.micronaut.benchmark.module.gradle
  6. 14 0
      frameworks/Java/micronaut/common-test/build.gradle
  7. 101 0
      frameworks/Java/micronaut/common-test/src/main/java/benchmark/DatabaseTest.java
  8. 26 0
      frameworks/Java/micronaut/common-test/src/main/java/benchmark/JsonSerializationTest.java
  9. 26 0
      frameworks/Java/micronaut/common-test/src/main/java/benchmark/PlainTextTest.java
  10. 21 0
      frameworks/Java/micronaut/common-test/src/main/resources/application-common-test.yml
  11. 13 0
      frameworks/Java/micronaut/common-test/src/main/resources/fortunes.html
  12. 47 0
      frameworks/Java/micronaut/common/build.gradle
  13. 3 2
      frameworks/Java/micronaut/common/src/main/java/benchmark/Application.java
  14. 57 0
      frameworks/Java/micronaut/common/src/main/java/benchmark/controller/AbstractBenchmarkController.java
  15. 89 0
      frameworks/Java/micronaut/common/src/main/java/benchmark/controller/BenchmarkController.java
  16. 2 0
      frameworks/Java/micronaut/common/src/main/java/benchmark/controller/JsonSerializationController.java
  17. 1 0
      frameworks/Java/micronaut/common/src/main/java/benchmark/controller/PlainTextController.java
  18. 93 0
      frameworks/Java/micronaut/common/src/main/java/benchmark/controller/ReactiveBenchmarkController.java
  19. 43 0
      frameworks/Java/micronaut/common/src/main/java/benchmark/filter/ServerHeaderFilter.java
  20. 6 3
      frameworks/Java/micronaut/common/src/main/java/benchmark/model/Fortune.java
  21. 8 3
      frameworks/Java/micronaut/common/src/main/java/benchmark/model/World.java
  22. 14 0
      frameworks/Java/micronaut/common/src/main/java/benchmark/repository/FortuneRepository.java
  23. 15 0
      frameworks/Java/micronaut/common/src/main/java/benchmark/repository/ReactiveFortuneRepository.java
  24. 22 0
      frameworks/Java/micronaut/common/src/main/java/benchmark/repository/ReactiveWorldRepository.java
  25. 26 0
      frameworks/Java/micronaut/common/src/main/java/benchmark/repository/WorldRepository.java
  26. 33 0
      frameworks/Java/micronaut/common/src/main/resources/application-benchmark.yml
  27. 37 0
      frameworks/Java/micronaut/common/src/main/resources/application-common.yml
  28. 0 1
      frameworks/Java/micronaut/common/src/main/resources/logback.xml
  29. 8 0
      frameworks/Java/micronaut/common/src/main/resources/views/fortunes.rocker.html
  30. 147 3
      frameworks/Java/micronaut/config.toml
  31. 1 0
      frameworks/Java/micronaut/gradle.properties
  32. BIN
      frameworks/Java/micronaut/gradle/wrapper/gradle-wrapper.jar
  33. 1 1
      frameworks/Java/micronaut/gradle/wrapper/gradle-wrapper.properties
  34. 153 104
      frameworks/Java/micronaut/gradlew
  35. 14 0
      frameworks/Java/micronaut/micronaut-data-jdbc-graalvm.dockerfile
  36. 12 0
      frameworks/Java/micronaut/micronaut-data-jdbc.dockerfile
  37. 10 0
      frameworks/Java/micronaut/micronaut-data-jdbc/build.gradle
  38. 23 0
      frameworks/Java/micronaut/micronaut-data-jdbc/src/main/java/benchmark/JdbcFortuneRepository.java
  39. 30 0
      frameworks/Java/micronaut/micronaut-data-jdbc/src/main/java/benchmark/JdbcWorldRepository.java
  40. 5 0
      frameworks/Java/micronaut/micronaut-data-jdbc/src/main/resources/application.yml
  41. 3 0
      frameworks/Java/micronaut/micronaut-data-jdbc/src/test/resources/application-test.yml
  42. 14 0
      frameworks/Java/micronaut/micronaut-data-mongodb-graalvm.dockerfile
  43. 12 0
      frameworks/Java/micronaut/micronaut-data-mongodb.dockerfile
  44. 9 0
      frameworks/Java/micronaut/micronaut-data-mongodb/build.gradle
  45. 22 0
      frameworks/Java/micronaut/micronaut-data-mongodb/src/main/java/benchmark/MongoFortuneRepository.java
  46. 27 0
      frameworks/Java/micronaut/micronaut-data-mongodb/src/main/java/benchmark/MongoWorldRepository.java
  47. 5 0
      frameworks/Java/micronaut/micronaut-data-mongodb/src/main/resources/application.yml
  48. 5 0
      frameworks/Java/micronaut/micronaut-data-mongodb/src/test/resources/application-test.yml
  49. 14 0
      frameworks/Java/micronaut/micronaut-data-r2dbc-graalvm.dockerfile
  50. 12 0
      frameworks/Java/micronaut/micronaut-data-r2dbc.dockerfile
  51. 9 0
      frameworks/Java/micronaut/micronaut-data-r2dbc/build.gradle
  52. 32 0
      frameworks/Java/micronaut/micronaut-data-r2dbc/src/main/java/benchmark/R2dbcFortuneRepository.java
  53. 32 0
      frameworks/Java/micronaut/micronaut-data-r2dbc/src/main/java/benchmark/R2dbcWorldRepository.java
  54. 26 0
      frameworks/Java/micronaut/micronaut-data-r2dbc/src/main/resources/META-INF/native-image/io.micronaut.benchmark/io.micronaut.benchmark.data.r2dbc/reflect-config.json
  55. 5 0
      frameworks/Java/micronaut/micronaut-data-r2dbc/src/test/resources/application-test.yml
  56. 14 0
      frameworks/Java/micronaut/micronaut-jdbc-graalvm.dockerfile
  57. 12 0
      frameworks/Java/micronaut/micronaut-jdbc.dockerfile
  58. 16 0
      frameworks/Java/micronaut/micronaut-jdbc/build.gradle
  59. 62 0
      frameworks/Java/micronaut/micronaut-jdbc/src/main/java/benchmark/JdbcFortuneRepository.java
  60. 99 0
      frameworks/Java/micronaut/micronaut-jdbc/src/main/java/benchmark/JdbcWorldRepository.java
  61. 5 0
      frameworks/Java/micronaut/micronaut-jdbc/src/main/resources/application.yml
  62. 3 0
      frameworks/Java/micronaut/micronaut-jdbc/src/test/resources/application-test.yml
  63. 0 13
      frameworks/Java/micronaut/micronaut-native.dockerfile
  64. 14 0
      frameworks/Java/micronaut/micronaut-r2dbc-graalvm.dockerfile
  65. 12 0
      frameworks/Java/micronaut/micronaut-r2dbc.dockerfile
  66. 15 0
      frameworks/Java/micronaut/micronaut-r2dbc/build.gradle
  67. 66 0
      frameworks/Java/micronaut/micronaut-r2dbc/src/main/java/benchmark/R2dbcFortuneRepository.java
  68. 106 0
      frameworks/Java/micronaut/micronaut-r2dbc/src/main/java/benchmark/R2dbcWorldRepository.java
  69. 26 0
      frameworks/Java/micronaut/micronaut-r2dbc/src/main/resources/META-INF/native-image/io.micronaut.benchmark/io.micronaut.benchmark.r2dbc/reflect-config.json
  70. 5 0
      frameworks/Java/micronaut/micronaut-r2dbc/src/test/resources/application-test.yml
  71. 14 0
      frameworks/Java/micronaut/micronaut-vertx-pg-client-graalvm.dockerfile
  72. 22 0
      frameworks/Java/micronaut/micronaut-vertx-pg-client/build.gradle
  73. 94 0
      frameworks/Java/micronaut/micronaut-vertx-pg-client/src/main/java/benchmark/AbstractVertxSqlClientRepository.java
  74. 58 0
      frameworks/Java/micronaut/micronaut-vertx-pg-client/src/main/java/benchmark/PgClientFactory.java
  75. 37 0
      frameworks/Java/micronaut/micronaut-vertx-pg-client/src/main/java/benchmark/VertxPgFortuneRepository.java
  76. 64 0
      frameworks/Java/micronaut/micronaut-vertx-pg-client/src/main/java/benchmark/VertxPgWorldRepository.java
  77. 5 0
      frameworks/Java/micronaut/micronaut-vertx-pg-client/src/main/resources/application.yml
  78. 8 12
      frameworks/Java/micronaut/micronaut.dockerfile
  79. 17 0
      frameworks/Java/micronaut/run_benchmark.sh
  80. 10 1
      frameworks/Java/micronaut/settings.gradle
  81. 0 79
      frameworks/Java/micronaut/src/main/java/benchmark/controller/EntityController.java
  82. 0 14
      frameworks/Java/micronaut/src/main/java/benchmark/repository/EntityRepository.java
  83. 0 69
      frameworks/Java/micronaut/src/main/java/benchmark/repository/PgClientEntityRepository.java
  84. 0 9
      frameworks/Java/micronaut/src/main/resources/application-benchmark-local.yml
  85. 0 9
      frameworks/Java/micronaut/src/main/resources/application-benchmark.yml
  86. 0 6
      frameworks/Java/micronaut/src/main/resources/application.yml
  87. 0 25
      frameworks/Java/micronaut/src/main/resources/views/fortunes.rocker.html

+ 1 - 15
frameworks/Java/micronaut/README.md

@@ -1,18 +1,4 @@
-# [Micronaut](http://micronaut.io) Benchmarking Test (3.1.1)
-
-### Test Type Implementation Source Code
-
-* [JSON](src/main/java/benchmark/JsonSerialization.java)
-* [PLAINTEXT](src/main/java/benchmark/PlainText.java)
-* [DB](src/main/java/benchmark/Database.java)
-* [QUERY](src/main/java/benchmark/Database.java)
-* [UPDATE](src/main/java/benchmark/Database.java)
-* [FORTUNES](src/main/java/benchmark/Database.java)
-
-## Important Libraries
-The tests were run with:
-* [OpenJDK Java 11](http://jdk.java.net/11/)
-* [GraalVM CE 21.3.0 (Java 11)](https://www.graalvm.org)
+# [Micronaut](http://micronaut.io)
 
 ## Test URLs
 ### JSON

+ 187 - 3
frameworks/Java/micronaut/benchmark_config.json

@@ -21,11 +21,11 @@
         "webserver": "None",
         "os": "Linux",
         "database_os": "Linux",
-        "display_name": "Micronaut",
+        "display_name": "Micronaut Vertx PG Client",
         "notes": "",
         "versus": "None"
       },
-      "native": {
+      "vertx-pg-client-graalvm": {
         "json_url": "/json",
         "plaintext_url": "/plaintext",
         "db_url": "/db",
@@ -44,7 +44,191 @@
         "webserver": "None",
         "os": "Linux",
         "database_os": "Linux",
-        "display_name": "micronaut-graalvm",
+        "display_name": "Micronaut Vertx PG Client GraalVM",
+        "notes": "",
+        "versus": "None"
+      },
+      "jdbc": {
+        "json_url": "/json",
+        "plaintext_url": "/plaintext",
+        "db_url": "/db",
+        "query_url": "/queries?queries=",
+        "fortune_url": "/fortunes",
+        "update_url": "/updates?queries=",
+        "port": 8080,
+        "approach": "Realistic",
+        "classification": "Micro",
+        "database": "Postgres",
+        "framework": "Micronaut",
+        "language": "Java",
+        "flavor": "None",
+        "orm": "raw",
+        "platform": "Netty",
+        "webserver": "None",
+        "os": "Linux",
+        "database_os": "Linux",
+        "display_name": "Micronaut JDBC",
+        "notes": "",
+        "versus": "None"
+      },
+      "jdbc-graalvm": {
+        "json_url": "/json",
+        "plaintext_url": "/plaintext",
+        "db_url": "/db",
+        "query_url": "/queries?queries=",
+        "fortune_url": "/fortunes",
+        "update_url": "/updates?queries=",
+        "port": 8080,
+        "approach": "Realistic",
+        "classification": "Micro",
+        "database": "Postgres",
+        "framework": "Micronaut",
+        "language": "Java",
+        "flavor": "None",
+        "orm": "raw",
+        "platform": "Netty",
+        "webserver": "None",
+        "os": "Linux",
+        "database_os": "Linux",
+        "display_name": "Micronaut JDBC GraalVM",
+        "notes": "",
+        "versus": "None"
+      },
+      "r2dbc": {
+        "json_url": "/json",
+        "plaintext_url": "/plaintext",
+        "db_url": "/db",
+        "query_url": "/queries?queries=",
+        "fortune_url": "/fortunes",
+        "update_url": "/updates?queries=",
+        "port": 8080,
+        "approach": "Realistic",
+        "classification": "Micro",
+        "database": "Postgres",
+        "framework": "Micronaut",
+        "language": "Java",
+        "flavor": "None",
+        "orm": "raw",
+        "platform": "Netty",
+        "webserver": "None",
+        "os": "Linux",
+        "database_os": "Linux",
+        "display_name": "Micronaut R2DBC",
+        "notes": "",
+        "versus": "None"
+      },
+      "r2dbc-graalvm": {
+        "json_url": "/json",
+        "plaintext_url": "/plaintext",
+        "db_url": "/db",
+        "query_url": "/queries?queries=",
+        "fortune_url": "/fortunes",
+        "update_url": "/updates?queries=",
+        "port": 8080,
+        "approach": "Realistic",
+        "classification": "Micro",
+        "database": "Postgres",
+        "framework": "Micronaut",
+        "language": "Java",
+        "flavor": "None",
+        "orm": "raw",
+        "platform": "Netty",
+        "webserver": "None",
+        "os": "Linux",
+        "database_os": "Linux",
+        "display_name": "Micronaut R2DBC GraalVM",
+        "notes": "",
+        "versus": "None"
+      },
+      "data-jdbc": {
+        "json_url": "/json",
+        "plaintext_url": "/plaintext",
+        "db_url": "/db",
+        "query_url": "/queries?queries=",
+        "fortune_url": "/fortunes",
+        "update_url": "/updates?queries=",
+        "port": 8080,
+        "approach": "Realistic",
+        "classification": "Micro",
+        "database": "Postgres",
+        "framework": "Micronaut",
+        "language": "Java",
+        "flavor": "None",
+        "orm": "raw",
+        "platform": "Netty",
+        "webserver": "None",
+        "os": "Linux",
+        "database_os": "Linux",
+        "display_name": "Micronaut Data JDBC",
+        "notes": "",
+        "versus": "None"
+      },
+      "data-jdbc-graalvm": {
+        "json_url": "/json",
+        "plaintext_url": "/plaintext",
+        "db_url": "/db",
+        "query_url": "/queries?queries=",
+        "fortune_url": "/fortunes",
+        "update_url": "/updates?queries=",
+        "port": 8080,
+        "approach": "Realistic",
+        "classification": "Micro",
+        "database": "Postgres",
+        "framework": "Micronaut",
+        "language": "Java",
+        "flavor": "None",
+        "orm": "raw",
+        "platform": "Netty",
+        "webserver": "None",
+        "os": "Linux",
+        "database_os": "Linux",
+        "display_name": "Micronaut Data JDBC GraalVM",
+        "notes": "",
+        "versus": "None"
+      },
+      "data-mongodb": {
+        "json_url": "/json",
+        "plaintext_url": "/plaintext",
+        "db_url": "/db",
+        "query_url": "/queries?queries=",
+        "fortune_url": "/fortunes",
+        "update_url": "/updates?queries=",
+        "port": 8080,
+        "approach": "Realistic",
+        "classification": "Micro",
+        "database": "MongoDB",
+        "framework": "Micronaut",
+        "language": "Java",
+        "flavor": "None",
+        "orm": "raw",
+        "platform": "Netty",
+        "webserver": "None",
+        "os": "Linux",
+        "database_os": "Linux",
+        "display_name": "Micronaut Data MongoDB",
+        "notes": "",
+        "versus": "None"
+      },
+      "data-mongodb-graalvm": {
+        "json_url": "/json",
+        "plaintext_url": "/plaintext",
+        "db_url": "/db",
+        "query_url": "/queries?queries=",
+        "fortune_url": "/fortunes",
+        "update_url": "/updates?queries=",
+        "port": 8080,
+        "approach": "Realistic",
+        "classification": "Micro",
+        "database": "MongoDB",
+        "framework": "Micronaut",
+        "language": "Java",
+        "flavor": "None",
+        "orm": "raw",
+        "platform": "Netty",
+        "webserver": "None",
+        "os": "Linux",
+        "database_os": "Linux",
+        "display_name": "Micronaut Data MongoDB GraalVM",
         "notes": "",
         "versus": "None"
       }

+ 0 - 88
frameworks/Java/micronaut/build.gradle

@@ -1,88 +0,0 @@
-plugins {
-    id 'java'
-    id "io.micronaut.application" version "2.0.6"
-    id "com.fizzed.rocker" version "1.3.0"
-}
-
-group 'org.example'
-version '1.0-SNAPSHOT'
-
-repositories {
-    mavenLocal()
-    mavenCentral()
-}
-
-micronaut {
-    version '3.1.1'
-    processing {
-        incremental true
-    }
-}
-
-nativeImage {
-    args "--initialize-at-build-time=" +
-            "views," +
-            "io.vertx.core.logging.LoggerFactory," +
-            "io.vertx.core.logging.SLF4JLogDelegateFactory," +
-            "io.vertx.core.logging.SLF4JLogDelegate," +
-            "io.vertx.pgclient.impl.codec.DataTypeCodec"
-}
-
-sourceSets {
-    main {
-        rocker {
-            srcDir('src/main/resources')
-        }
-    }
-}
-
-rocker {
-    skip false
-    // Base directory for generated java sources, actual target is sub directory
-    // with the name of the source set. The value is passed through project.file().
-    outputBaseDirectory = "$buildDir/generated/rocker"
-    // Base directory for the directory where the hot reload feature
-    // will (re)compile classes to at runtime (and where `rocker-compiler.conf`
-    // is generated, which is used by RockerRuntime.getInstance().setReloading(true)).
-    // The actual target is a sub directory with the name of the source set.
-    // The value is passed through project.file().
-    classBaseDirectory = "$buildDir/classes"
-    failOnError true
-    skipTouch true
-    // must not be empty when skipTouch is equal to false
-    touchFile ""
-    javaVersion '11'
-    optimize true
-}
-
-mainClassName = 'benchmark.Application'
-
-ext {
-    set('vertxVersion', '4.1.5')
-    set('micronautVersion', '3.1.1')
-    set('javaxAnnotationApi', '1.3.2')
-    set('rockerVersion', '1.3.0')
-}
-
-dependencies {
-    implementation("io.micronaut:micronaut-inject:${micronautVersion}")
-    implementation("io.micronaut:micronaut-management:${micronautVersion}")
-    implementation("io.micronaut:micronaut-http-server-netty:${micronautVersion}")
-    implementation("io.micronaut.rxjava3:micronaut-rxjava3")
-    implementation("io.micronaut.sql:micronaut-vertx-pg-client")
-    implementation("io.micronaut.sql:micronaut-jdbc-hikari:4.0.2")
-    implementation("io.micronaut.views:micronaut-views-rocker")
-    implementation("com.fizzed:rocker-runtime:${rockerVersion}")
-    implementation("io.vertx:vertx-core:${vertxVersion}")
-    implementation("io.vertx:vertx-rx-java2:${vertxVersion}")
-    implementation("io.vertx:vertx-rx-java3:${vertxVersion}")
-    implementation("io.vertx:vertx-pg-client:${vertxVersion}")
-
-    runtimeOnly("ch.qos.logback:logback-classic")
-    testImplementation("io.micronaut.test:micronaut-test-junit5")
-    testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine")
-}
-
-test {
-    useJUnitPlatform()
-}

+ 13 - 0
frameworks/Java/micronaut/buildSrc/build.gradle

@@ -0,0 +1,13 @@
+plugins {
+    id 'groovy-gradle-plugin'
+}
+
+repositories {
+    gradlePluginPortal()
+    mavenCentral()
+}
+
+dependencies {
+    implementation "io.micronaut.gradle:micronaut-gradle-plugin:3.6.2"
+    implementation "gradle.plugin.com.github.johnrengelman:shadow:7.1.2"
+}

+ 42 - 0
frameworks/Java/micronaut/buildSrc/src/main/groovy/io.micronaut.benchmark.module.gradle

@@ -0,0 +1,42 @@
+plugins {
+    id 'java'
+    id "io.micronaut.application"
+    id 'io.micronaut.test-resources'
+    id 'com.github.johnrengelman.shadow'
+}
+
+repositories {
+    mavenCentral()
+}
+
+micronaut {
+    runtime "netty"
+    testRuntime "junit5"
+    testResources {
+        enabled = true
+    }
+}
+
+configurations {
+    externalTests
+}
+
+dependencies {
+    implementation project(":common")
+    implementation project(":common-test")
+    externalTests project(":common-test")
+}
+
+graalvmNative.binaries.all {
+    buildArgs.add("--initialize-at-build-time=views")
+}
+
+test {
+    // This is needed to share tests
+    testClassesDirs += zipTree(configurations.externalTests.files.iterator().next())
+    useJUnitPlatform()
+}
+
+application {
+    mainClass.set("benchmark.Application")
+}

+ 14 - 0
frameworks/Java/micronaut/common-test/build.gradle

@@ -0,0 +1,14 @@
+plugins {
+    id "java-library"
+     id "io.micronaut.library"
+}
+
+repositories {
+    mavenCentral()
+}
+
+dependencies {
+    api("io.micronaut:micronaut-http-client")
+    api("io.micronaut.test:micronaut-test-junit5")
+    api("org.junit.jupiter:junit-jupiter-engine")
+}

+ 101 - 0
frameworks/Java/micronaut/common-test/src/main/java/benchmark/DatabaseTest.java

@@ -0,0 +1,101 @@
+package benchmark;
+
+import io.micronaut.core.io.IOUtils;
+import io.micronaut.core.type.Argument;
+import io.micronaut.core.util.StringUtils;
+import io.micronaut.http.HttpRequest;
+import io.micronaut.http.HttpResponse;
+import io.micronaut.http.client.HttpClient;
+import io.micronaut.http.client.annotation.Client;
+import io.micronaut.test.extensions.junit5.annotation.MicronautTest;
+import jakarta.inject.Inject;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestInstance;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.StringReader;
+import java.util.List;
+import java.util.Map;
+
+@MicronautTest(transactional = false, environments = {"common", "common-test"})
+@TestInstance(TestInstance.Lifecycle.PER_CLASS)
+public class DatabaseTest {
+
+    @Inject
+    @Client("/")
+    HttpClient httpClient;
+
+    @BeforeAll
+    public void prepareData() {
+        httpClient.toBlocking().exchange("/prepare-data-for-test");
+    }
+
+    @Test
+    public void singleDatabaseQuery() {
+        HttpResponse<Map<String, Object>> response = httpClient.toBlocking().exchange(HttpRequest.GET("/db"), Argument.mapOf(String.class, Object.class));
+        Map<String, Object> world = response.body();
+        Assertions.assertNotNull(world);
+        Assertions.assertTrue(world.containsKey("id"));
+        Assertions.assertTrue(world.containsKey("randomNumber"));
+        Assertions.assertEquals("Micronaut", response.header("Server"));
+        Assertions.assertEquals("application/json", response.header("Content-Type"));
+        Assertions.assertTrue(StringUtils.isNotEmpty(response.header("Date")));
+        Assertions.assertTrue(StringUtils.isNotEmpty(response.header("Content-Length")));
+    }
+
+    @Test
+    public void multipleDatabaseQuery() {
+        HttpResponse<List<Map<String, Object>>> response = httpClient.toBlocking().exchange(HttpRequest.GET("/queries?queries=10"), Argument.listOf(Argument.mapOf(String.class, Object.class)));
+        List<Map<String, Object>> worlds = response.body();
+        Assertions.assertNotNull(worlds);
+        Assertions.assertEquals(worlds.size(), 10);
+        for (Map<String, Object> world : worlds) {
+            Assertions.assertTrue(world.containsKey("id"));
+            Assertions.assertTrue(world.containsKey("randomNumber"));
+        }
+        Assertions.assertEquals("Micronaut", response.header("Server"));
+        Assertions.assertEquals("application/json", response.header("Content-Type"));
+        Assertions.assertTrue(StringUtils.isNotEmpty(response.header("Date")));
+        Assertions.assertTrue(StringUtils.isNotEmpty(response.header("Content-Length")));
+    }
+
+    @Test
+    public void fortunes() {
+        HttpResponse<String> response = httpClient.toBlocking().exchange(HttpRequest.GET("/fortunes"), String.class);
+        Assertions.assertEquals(getFortunesHtmlString(), response.body());
+        Assertions.assertEquals("Micronaut", response.header("Server"));
+        Assertions.assertEquals("text/html;charset=utf-8", response.header("Content-Type"));
+        Assertions.assertTrue(StringUtils.isNotEmpty(response.header("Date")));
+        Assertions.assertTrue(StringUtils.isNotEmpty(response.header("Content-Length")));
+    }
+
+    @Test
+    public void databaseUpdates() {
+        HttpResponse<List<Map<String, Object>>> response = httpClient.toBlocking().exchange(HttpRequest.GET("/updates?queries=10"), Argument.listOf(Argument.mapOf(String.class, Object.class)));
+        List<Map<String, Object>> worlds = response.body();
+        Assertions.assertNotNull(worlds);
+        Assertions.assertEquals(worlds.size(), 10);
+        for (Map<String, Object> world : worlds) {
+            Assertions.assertTrue(world.containsKey("id"));
+            Assertions.assertTrue(world.containsKey("randomNumber"));
+        }
+        Assertions.assertEquals("Micronaut", response.header("Server"));
+        Assertions.assertEquals("application/json", response.header("Content-Type"));
+        Assertions.assertTrue(StringUtils.isNotEmpty(response.header("Date")));
+        Assertions.assertTrue(StringUtils.isNotEmpty(response.header("Content-Length")));
+    }
+
+    private String getFortunesHtmlString() {
+        try (InputStream resourceAsStream = getClass().getResourceAsStream("/fortunes.html")) {
+            return IOUtils.readText(new BufferedReader(new InputStreamReader(resourceAsStream)));
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+}

+ 26 - 0
frameworks/Java/micronaut/common-test/src/main/java/benchmark/JsonSerializationTest.java

@@ -0,0 +1,26 @@
+package benchmark;
+
+import io.micronaut.http.HttpResponse;
+import io.micronaut.http.client.HttpClient;
+import io.micronaut.http.client.annotation.Client;
+import io.micronaut.test.extensions.junit5.annotation.MicronautTest;
+import jakarta.inject.Inject;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+@MicronautTest(transactional = false, environments = {"common", "common-test"})
+public class JsonSerializationTest {
+
+    @Inject
+    @Client("/")
+    HttpClient httpClient;
+
+    @Test
+    public void test() {
+        HttpResponse<String> response = httpClient.toBlocking().exchange("/json", String.class);
+        Assertions.assertEquals("{\"message\":\"Hello, World!\"}", response.body());
+        Assertions.assertEquals("Micronaut", response.header("Server"));
+        Assertions.assertFalse(response.header("Date").isEmpty());
+    }
+
+}

+ 26 - 0
frameworks/Java/micronaut/common-test/src/main/java/benchmark/PlainTextTest.java

@@ -0,0 +1,26 @@
+package benchmark;
+
+import io.micronaut.http.HttpResponse;
+import io.micronaut.http.client.HttpClient;
+import io.micronaut.http.client.annotation.Client;
+import io.micronaut.test.extensions.junit5.annotation.MicronautTest;
+import jakarta.inject.Inject;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+@MicronautTest(transactional = false, environments = {"common", "common-test"})
+public class PlainTextTest {
+
+    @Inject
+    @Client("/")
+    HttpClient httpClient;
+
+    @Test
+    public void test() {
+        HttpResponse<String> response = httpClient.toBlocking().exchange("/plaintext", String.class);
+        Assertions.assertEquals("Hello, World!", response.body());
+        Assertions.assertEquals("Micronaut", response.header("Server"));
+        Assertions.assertFalse(response.header("Date").isEmpty());
+    }
+
+}

+ 21 - 0
frameworks/Java/micronaut/common-test/src/main/resources/application-common-test.yml

@@ -0,0 +1,21 @@
+micronaut:
+  http:
+    client:
+      read-timeout: 60s
+
+datasources:
+  default:
+#    url: jdbc:postgresql://localhost:5432/test?loggerLevel=OFF&disableColumnSanitiser=true&assumeMinServerVersion=12&sslmode=disable
+#    username: test
+#    password: test
+    schema-generate: CREATE_DROP
+
+r2dbc:
+  datasources:
+    default:
+#      url: r2dbc:pool://localhost:5432/test?loggerLevel=OFF&disableColumnSanitiser=true&assumeMinServerVersion=12&sslmode=disable
+#      username: test
+#      password: test
+      schema-generate: CREATE_DROP
+
+

+ 13 - 0
frameworks/Java/micronaut/common-test/src/main/resources/fortunes.html

@@ -0,0 +1,13 @@
+<!DOCTYPE html><html><head><title>Fortunes</title></head><body><table><tr><th>id</th><th>message</th></tr>
+    <tr><td>0</td><td>Additional fortune added at request time.</td></tr>
+    <tr><td>1</td><td>message0</td></tr>
+    <tr><td>2</td><td>message1</td></tr>
+    <tr><td>3</td><td>message2</td></tr>
+    <tr><td>4</td><td>message3</td></tr>
+    <tr><td>5</td><td>message4</td></tr>
+    <tr><td>6</td><td>message5</td></tr>
+    <tr><td>7</td><td>message6</td></tr>
+    <tr><td>8</td><td>message7</td></tr>
+    <tr><td>9</td><td>message8</td></tr>
+    <tr><td>10</td><td>message9</td></tr>
+</table></body></html>

+ 47 - 0
frameworks/Java/micronaut/common/build.gradle

@@ -0,0 +1,47 @@
+plugins {
+    id 'java'
+    id "io.micronaut.library"
+    id "nu.studer.rocker" version "3.0.4"
+}
+
+group 'io.micronaut.benchmark'
+version '1.0'
+
+repositories {
+    mavenCentral()
+}
+
+micronaut {
+    runtime "netty"
+    testRuntime "junit5"
+}
+
+rocker {
+    configurations {
+        main {
+            templateDir = file('src/main/resources')
+            outputDir = file('build/generated/rocker')
+            optimize = true
+        }
+    }
+}
+
+dependencies {
+    annotationProcessor("io.micronaut.data:micronaut-data-document-processor")
+
+    api("io.micronaut:micronaut-inject")
+    api("io.micronaut:micronaut-http-server-netty")
+    api("io.micronaut.reactor:micronaut-reactor")
+
+    implementation("io.micronaut.data:micronaut-data-model") {
+        transitive = false
+    }
+
+    implementation("com.fizzed:rocker-runtime")
+
+    runtimeOnly("ch.qos.logback:logback-classic")
+}
+
+test {
+    useJUnitPlatform()
+}

+ 3 - 2
frameworks/Java/micronaut/src/main/java/benchmark/Application.java → frameworks/Java/micronaut/common/src/main/java/benchmark/Application.java

@@ -3,8 +3,9 @@ package benchmark;
 import io.micronaut.runtime.Micronaut;
 
 public class Application {
+
     public static void main(String[] args) {
-        Micronaut.build(args)
-                .run(Application.class);
+        Micronaut.build(args).environments("common").classes(Application.class).start();
     }
+
 }

+ 57 - 0
frameworks/Java/micronaut/common/src/main/java/benchmark/controller/AbstractBenchmarkController.java

@@ -0,0 +1,57 @@
+package benchmark.controller;
+
+import benchmark.model.Fortune;
+import benchmark.model.World;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.ThreadLocalRandom;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+
+public class AbstractBenchmarkController {
+
+    protected final Integer[] boxed = IntStream.range(1, 10001).boxed().toArray(Integer[]::new);
+
+    protected List<Fortune> createFortunes() {
+        List<Integer> fortuneMessages = IntStream.range(0, 10).boxed().collect(Collectors.toList());
+        List<Fortune> fortunes = new ArrayList<>(fortuneMessages.size());
+        for (Integer number : fortuneMessages) {
+            fortunes.add(new Fortune(number + 1, "message" + number));
+        }
+        Collections.shuffle(fortunes);
+        return fortunes;
+    }
+
+    protected List<World> createWords() {
+        List<Integer> ids = new ArrayList<>(List.of(boxed));
+        Collections.shuffle(ids);
+        List<World> worlds = new ArrayList<>(ids.size());
+        for (Integer id : ids) {
+            worlds.add(new World(id, randomWorldNumber()));
+        }
+        return worlds;
+    }
+
+    protected Integer randomId() {
+        return boxed[ThreadLocalRandom.current().nextInt(10000)];
+    }
+
+    protected Integer randomWorldNumber() {
+        return boxed[ThreadLocalRandom.current().nextInt(10000)];
+    }
+
+    protected Integer parseQueryCount(String textValue) {
+        if (textValue == null) {
+            return 1;
+        }
+        int parsedValue;
+        try {
+            parsedValue = Integer.parseInt(textValue);
+        } catch (NumberFormatException e) {
+            return 1;
+        }
+        return Math.min(500, Math.max(1, parsedValue));
+    }
+}

+ 89 - 0
frameworks/Java/micronaut/common/src/main/java/benchmark/controller/BenchmarkController.java

@@ -0,0 +1,89 @@
+package benchmark.controller;
+
+import benchmark.model.Fortune;
+import benchmark.model.World;
+import benchmark.repository.FortuneRepository;
+import benchmark.repository.WorldRepository;
+import io.micronaut.context.annotation.Requires;
+import io.micronaut.http.HttpResponse;
+import io.micronaut.http.annotation.Controller;
+import io.micronaut.http.annotation.Get;
+import io.micronaut.http.annotation.QueryValue;
+import io.micronaut.scheduling.TaskExecutors;
+import io.micronaut.scheduling.annotation.ExecuteOn;
+import views.fortunes;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.concurrent.ThreadLocalRandom;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+
+import static java.util.Comparator.comparing;
+
+@ExecuteOn(TaskExecutors.IO)
+@Requires(missingBeans = ReactiveBenchmarkController.class)
+@Controller
+public class BenchmarkController extends AbstractBenchmarkController {
+
+    private final WorldRepository worldRepository;
+    private final FortuneRepository fortuneRepository;
+
+    public BenchmarkController(WorldRepository worldRepository,
+                               FortuneRepository fortuneRepository) {
+        this.worldRepository = worldRepository;
+        this.fortuneRepository = fortuneRepository;
+    }
+
+    @Get("/prepare-data-for-test")
+    public void prepareDataForTest() {
+        worldRepository.initDb(createWords());
+        fortuneRepository.initDb(createFortunes());
+    }
+
+    // https://github.com/TechEmpower/FrameworkBenchmarks/wiki/Project-Information-Framework-Tests-Overview#single-database-query
+    @Get("/db")
+    public World db() {
+        return worldRepository.findById(randomId());
+    }
+
+    // https://github.com/TechEmpower/FrameworkBenchmarks/wiki/Project-Information-Framework-Tests-Overview#multiple-database-queries
+    @Get("/queries")
+    public List<World> queries(@QueryValue String queries) {
+        int count = parseQueryCount(queries);
+        List<Integer> ids = new ArrayList<>(count);
+        for (int i = 0; i < count; i++) {
+            ids.add(randomId());
+        }
+        return worldRepository.findByIds(ids);
+    }
+
+    // https://github.com/TechEmpower/FrameworkBenchmarks/wiki/Project-Information-Framework-Tests-Overview#fortunes
+    @Get(value = "/fortunes", produces = "text/html;charset=utf-8")
+    public HttpResponse<String> fortune() {
+        Collection<Fortune> all = fortuneRepository.findAll();
+        List<Fortune> fortunesList = new ArrayList<>(all.size() + 1);
+        fortunesList.add(new Fortune(0, "Additional fortune added at request time."));
+        fortunesList.addAll(all);
+        fortunesList.sort(comparing(Fortune::getMessage));
+        String body = fortunes.template(fortunesList).render().toString();
+        return HttpResponse.ok(body).contentType("text/html;charset=utf-8");
+    }
+
+    // https://github.com/TechEmpower/FrameworkBenchmarks/wiki/Project-Information-Framework-Tests-Overview#database-updates
+    @Get("/updates")
+    public List<World> updates(@QueryValue String queries) {
+        List<World> worldList = queries(queries);
+        for (World world : worldList) {
+            world.setRandomNumber(randomWorldNumber());
+        }
+        worldList.sort(Comparator.comparingInt(World::getId)); // Avoid deadlock
+        worldRepository.updateAll(worldList);
+        return worldList;
+    }
+    
+}

+ 2 - 0
frameworks/Java/micronaut/src/main/java/benchmark/controller/JsonSerializationController.java → frameworks/Java/micronaut/common/src/main/java/benchmark/controller/JsonSerializationController.java

@@ -9,10 +9,12 @@ import java.util.Map;
 @Controller("/json")
 public class JsonSerializationController {
 
+    // https://github.com/TechEmpower/FrameworkBenchmarks/wiki/Project-Information-Framework-Tests-Overview#json-serialization
     @Get
     public Map<String, String> getJson() {
         final Map<String, String> map = new HashMap<>();
         map.put("message", "Hello, World!");
         return map;
     }
+
 }

+ 1 - 0
frameworks/Java/micronaut/src/main/java/benchmark/controller/PlainTextController.java → frameworks/Java/micronaut/common/src/main/java/benchmark/controller/PlainTextController.java

@@ -6,6 +6,7 @@ import io.micronaut.http.annotation.Get;
 
 @Controller("/plaintext")
 public class PlainTextController {
+
     private static final String TEXT = "Hello, World!";
 
     @Get(value = "/", produces = MediaType.TEXT_PLAIN)

+ 93 - 0
frameworks/Java/micronaut/common/src/main/java/benchmark/controller/ReactiveBenchmarkController.java

@@ -0,0 +1,93 @@
+package benchmark.controller;
+
+import benchmark.model.Fortune;
+import benchmark.model.World;
+import benchmark.repository.ReactiveFortuneRepository;
+import benchmark.repository.ReactiveWorldRepository;
+import io.micronaut.context.annotation.Requires;
+import io.micronaut.core.async.annotation.SingleResult;
+import io.micronaut.http.HttpResponse;
+import io.micronaut.http.MutableHttpResponse;
+import io.micronaut.http.annotation.Controller;
+import io.micronaut.http.annotation.Get;
+import io.micronaut.http.annotation.QueryValue;
+import org.reactivestreams.Publisher;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+import views.fortunes;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.concurrent.ThreadLocalRandom;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+
+import static java.util.Comparator.comparing;
+
+@Requires(beans = {ReactiveFortuneRepository.class, ReactiveWorldRepository.class})
+@Controller
+public class ReactiveBenchmarkController extends AbstractBenchmarkController {
+
+    private final ReactiveWorldRepository worldRepository;
+    private final ReactiveFortuneRepository fortuneRepository;
+
+    public ReactiveBenchmarkController(ReactiveWorldRepository worldRepository,
+                                       ReactiveFortuneRepository fortuneRepository) {
+        this.worldRepository = worldRepository;
+        this.fortuneRepository = fortuneRepository;
+    }
+
+    @Get("/prepare-data-for-test")
+    public Mono<Void> prepareDataForTest() {
+        return Mono.from(worldRepository.initDb(createWords())).then(Mono.from(fortuneRepository.initDb(createFortunes())));
+    }
+
+    // https://github.com/TechEmpower/FrameworkBenchmarks/wiki/Project-Information-Framework-Tests-Overview#single-database-query
+    @Get("/db")
+    @SingleResult
+    public Publisher<World> db() {
+        return worldRepository.findById(randomId());
+    }
+
+    // https://github.com/TechEmpower/FrameworkBenchmarks/wiki/Project-Information-Framework-Tests-Overview#multiple-database-queries
+    @Get("/queries")
+    @SingleResult
+    public Publisher<List<World>> queries(@QueryValue String queries) {
+        int count = parseQueryCount(queries);
+        List<Integer> ids = new ArrayList<>(count);
+        for (int i = 0; i < count; i++) {
+            ids.add(randomId());
+        }
+        return worldRepository.findByIds(ids);
+    }
+
+    // https://github.com/TechEmpower/FrameworkBenchmarks/wiki/Project-Information-Framework-Tests-Overview#fortunes
+    @Get(value = "/fortunes", produces = "text/html;charset=utf-8")
+    @SingleResult
+    public Mono<HttpResponse<String>> fortune() {
+        return Mono.from(fortuneRepository.findAll()).map(fortuneList -> {
+            List<Fortune> all = new ArrayList<>(fortuneList.size() + 1);
+            all.add(new Fortune(0, "Additional fortune added at request time."));
+            all.addAll(fortuneList);
+            all.sort(comparing(Fortune::getMessage));
+            String body = fortunes.template(all).render().toString();
+            return HttpResponse.ok(body).contentType("text/html;charset=utf-8");
+        });
+    }
+
+    // https://github.com/TechEmpower/FrameworkBenchmarks/wiki/Project-Information-Framework-Tests-Overview#database-updates
+    @Get("/updates")
+    @SingleResult
+    public Publisher<List<World>> updates(@QueryValue String queries) {
+        return Flux.from(queries(queries)).flatMap(worlds -> {
+            for (World world : worlds) {
+                world.setRandomNumber(randomWorldNumber());
+            }
+            worlds.sort(Comparator.comparingInt(World::getId)); // Avoid deadlock
+            return Mono.from(worldRepository.updateAll(worlds)).thenReturn(worlds);
+        });
+    }
+
+}

+ 43 - 0
frameworks/Java/micronaut/common/src/main/java/benchmark/filter/ServerHeaderFilter.java

@@ -0,0 +1,43 @@
+package benchmark.filter;
+
+import io.micronaut.core.async.publisher.Publishers;
+import io.micronaut.http.HttpRequest;
+import io.micronaut.http.MutableHttpResponse;
+import io.micronaut.http.annotation.Filter;
+import io.micronaut.http.filter.HttpServerFilter;
+import io.micronaut.http.filter.ServerFilterChain;
+import io.micronaut.scheduling.annotation.Scheduled;
+import org.reactivestreams.Publisher;
+
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.function.Function;
+
+@Filter(Filter.MATCH_ALL_PATTERN)
+public class ServerHeaderFilter implements HttpServerFilter {
+
+    private volatile Function<MutableHttpResponse<?>, MutableHttpResponse<?>> addHeader;
+
+    ServerHeaderFilter() {
+        setDateHeader();
+    }
+
+    @Scheduled(fixedRate = "1s")
+    public void setDateHeader() {
+        addHeader = new Function<>() {
+
+            private final String dateHeader = DateTimeFormatter.RFC_1123_DATE_TIME.format(ZonedDateTime.now());
+
+            @Override
+            public MutableHttpResponse<?> apply(MutableHttpResponse<?> mutableHttpResponse) {
+                return mutableHttpResponse.header("Date", dateHeader);
+            }
+        };
+    }
+
+    @Override
+    public Publisher<MutableHttpResponse<?>> doFilter(HttpRequest<?> request, ServerFilterChain chain) {
+        return Publishers.map(chain.proceed(request), addHeader);
+    }
+
+}

+ 6 - 3
frameworks/Java/micronaut/src/main/java/benchmark/entity/Fortune.java → frameworks/Java/micronaut/common/src/main/java/benchmark/model/Fortune.java

@@ -1,11 +1,14 @@
-package benchmark.entity;
+package benchmark.model;
 
-import io.micronaut.core.annotation.Introspected;
+import io.micronaut.data.annotation.Id;
+import io.micronaut.data.annotation.MappedEntity;
 
 import java.util.Objects;
 
-@Introspected
+// Disable escape to have case-insensitive Postgres columns and table name and set lowercase name for MongoDB
+@MappedEntity(value = "fortune", escape = false)
 public class Fortune {
+    @Id
     private int id;
     private String message;
 

+ 8 - 3
frameworks/Java/micronaut/src/main/java/benchmark/entity/World.java → frameworks/Java/micronaut/common/src/main/java/benchmark/model/World.java

@@ -1,12 +1,17 @@
-package benchmark.entity;
+package benchmark.model;
 
-import io.micronaut.core.annotation.Introspected;
+import io.micronaut.data.annotation.Id;
+import io.micronaut.data.annotation.MappedEntity;
+import io.micronaut.data.annotation.MappedProperty;
 
 import java.util.Objects;
 
-@Introspected
+// Disable escape to have case-insensitive Postgres columns and table name and set lowercase name for MongoDB
+@MappedEntity(value = "world", escape = false)
 public class World {
+    @Id
     private int id;
+    @MappedProperty("randomNumber")
     private int randomNumber;
 
     public World() {

+ 14 - 0
frameworks/Java/micronaut/common/src/main/java/benchmark/repository/FortuneRepository.java

@@ -0,0 +1,14 @@
+package benchmark.repository;
+
+import benchmark.model.Fortune;
+import org.reactivestreams.Publisher;
+
+import java.util.Collection;
+
+public interface FortuneRepository {
+
+    void initDb(Collection<Fortune> fortunes);
+
+    Collection<Fortune> findAll();
+
+}

+ 15 - 0
frameworks/Java/micronaut/common/src/main/java/benchmark/repository/ReactiveFortuneRepository.java

@@ -0,0 +1,15 @@
+package benchmark.repository;
+
+import benchmark.model.Fortune;
+import org.reactivestreams.Publisher;
+
+import java.util.Collection;
+import java.util.List;
+
+public interface ReactiveFortuneRepository {
+
+    Publisher<Void> initDb(Collection<Fortune> fortunes);
+
+    Publisher<List<Fortune>> findAll();
+
+}

+ 22 - 0
frameworks/Java/micronaut/common/src/main/java/benchmark/repository/ReactiveWorldRepository.java

@@ -0,0 +1,22 @@
+package benchmark.repository;
+
+import benchmark.model.World;
+import org.reactivestreams.Publisher;
+import reactor.core.publisher.Flux;
+
+import java.util.Collection;
+import java.util.List;
+
+public interface ReactiveWorldRepository {
+
+    Publisher<Void> initDb(Collection<World> worlds);
+
+    Publisher<World> findById(Integer id);
+
+    default Publisher<List<World>> findByIds(List<Integer> ids) {
+        return Flux.fromIterable(ids).flatMap(this::findById).collectList();
+    }
+
+    Publisher<Void> updateAll(Collection<World> worlds);
+
+}

+ 26 - 0
frameworks/Java/micronaut/common/src/main/java/benchmark/repository/WorldRepository.java

@@ -0,0 +1,26 @@
+package benchmark.repository;
+
+import benchmark.model.World;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+public interface WorldRepository {
+
+    void initDb(Collection<World> worlds);
+
+    World findById(Integer id);
+
+    default List<World> findByIds(List<Integer> ids) {
+        // Batch cannot be used by rules
+        List<World> worlds = new ArrayList<>(ids.size());
+        for (Integer number : ids) {
+            worlds.add(findById(number));
+        }
+        return worlds;
+    }
+
+    void updateAll(Collection<World> worlds);
+
+}

+ 33 - 0
frameworks/Java/micronaut/common/src/main/resources/application-benchmark.yml

@@ -0,0 +1,33 @@
+micronaut:
+  application:
+    name: micronaut-benchmark
+  server:
+    port: 8080
+    server-header: Micronaut
+    date-header: false
+  http:
+    client:
+      read-timeout: 60s
+
+netty:
+  default:
+    allocator:
+      max-order: 3
+
+datasources:
+  default:
+    url: jdbc:postgresql://tfb-database:5432/hello_world?loggerLevel=OFF&disableColumnSanitiser=true&assumeMinServerVersion=12&sslmode=disable
+    username: benchmarkdbuser
+    password: benchmarkdbpass
+
+r2dbc:
+  datasources:
+    default:
+      url: r2dbc:pool://tfb-database:5432/hello_world?loggerLevel=OFF&disableColumnSanitiser=true&assumeMinServerVersion=12&sslmode=disable
+      username: benchmarkdbuser
+      password: benchmarkdbpass
+      options:
+        protocol: postgres
+
+mongodb:
+  uri: mongodb://tfb-database:27017/hello_world

+ 37 - 0
frameworks/Java/micronaut/common/src/main/resources/application-common.yml

@@ -0,0 +1,37 @@
+micronaut:
+  application:
+    name: micronaut-benchmark
+  server:
+    port: 8080
+    server-header: Micronaut
+    date-header: false
+
+netty:
+  resource-leak-detector-level: DISABLED
+  default:
+    allocator:
+      max-order: 3
+
+datasources:
+  default:
+    driverClassName: org.postgresql.Driver
+    db-type: postgresql
+    dialect: POSTGRES
+    maximum-pool-size: 48
+    transaction-per-operation: false
+    allow-connection-per-operation: true
+
+r2dbc:
+  datasources:
+    default:
+      db-type: postgresql
+      dialect: POSTGRES
+      options:
+        protocol: postgres
+        initialSize: 48
+        maxSize: 48
+
+mongodb:
+  package-names:
+    benchmark
+  uuid-representation: STANDARD

+ 0 - 1
frameworks/Java/micronaut/src/main/resources/logback.xml → frameworks/Java/micronaut/common/src/main/resources/logback.xml

@@ -12,5 +12,4 @@
         <appender-ref ref="STDOUT" />
     </root>
 
-    <!--<logger name="io.micronaut.http.server" level="debug"/>-->
 </configuration>

+ 8 - 0
frameworks/Java/micronaut/common/src/main/resources/views/fortunes.rocker.html

@@ -0,0 +1,8 @@
+@import java.util.*
+@import benchmark.model.*
+@args(List fortunes)
+<!DOCTYPE html><html><head><title>Fortunes</title></head><body><table><tr><th>id</th><th>message</th></tr>
+    @for ((ForIterator i, Fortune fortune) : fortunes) {
+    <tr><td>@fortune.getId()</td><td>@fortune.getMessage()</td></tr>
+    }
+</table></body></html>

+ 147 - 3
frameworks/Java/micronaut/config.toml

@@ -12,14 +12,14 @@ approach = "Realistic"
 classification = "Micro"
 database = "Postgres"
 database_os = "Linux"
-display_name = "micronaut"
+display_name = "micronaut-vertx-pg-client"
 os = "Linux"
 orm = "raw"
 platform = "Netty"
 webserver = "None"
 versus = "None"
 
-[native]
+[jdbc]
 urls.plaintext = "/plaintext"
 urls.json = "/json"
 urls.db = "/db"
@@ -30,9 +30,153 @@ approach = "Realistic"
 classification = "Micro"
 database = "Postgres"
 database_os = "Linux"
-display_name = "micronaut-graalvm"
+display_name = "micronaut-jdbc"
 os = "Linux"
 orm = "raw"
 platform = "Netty"
 webserver = "None"
 versus = "micronaut"
+
+[r2dbc]
+urls.plaintext = "/plaintext"
+urls.json = "/json"
+urls.db = "/db"
+urls.query = "/queries?queries="
+urls.update = "/updates?queries="
+urls.fortune = "/fortunes"
+approach = "Realistic"
+classification = "Micro"
+database = "Postgres"
+database_os = "Linux"
+display_name = "micronaut-r2dbc"
+os = "Linux"
+orm = "raw"
+platform = "Netty"
+webserver = "None"
+versus = "micronaut"
+
+[data-jdbc]
+urls.plaintext = "/plaintext"
+urls.json = "/json"
+urls.db = "/db"
+urls.query = "/queries?queries="
+urls.update = "/updates?queries="
+urls.fortune = "/fortunes"
+approach = "Realistic"
+classification = "Micro"
+database = "Postgres"
+database_os = "Linux"
+display_name = "micronaut-data-jdbc"
+os = "Linux"
+orm = "raw"
+platform = "Netty"
+webserver = "None"
+versus = "micronaut-jdbc"
+
+[vertx-pg-client-graalvm]
+urls.plaintext = "/plaintext"
+urls.json = "/json"
+urls.db = "/db"
+urls.query = "/queries?queries="
+urls.update = "/updates?queries="
+urls.fortune = "/fortunes"
+approach = "Realistic"
+classification = "Micro"
+database = "Postgres"
+database_os = "Linux"
+display_name = "micronaut-vertx-pg-client-graalvm"
+os = "Linux"
+orm = "raw"
+platform = "Netty"
+webserver = "None"
+versus = "micronaut"
+
+[jdbc-graalvm]
+urls.plaintext = "/plaintext"
+urls.json = "/json"
+urls.db = "/db"
+urls.query = "/queries?queries="
+urls.update = "/updates?queries="
+urls.fortune = "/fortunes"
+approach = "Realistic"
+classification = "Micro"
+database = "Postgres"
+database_os = "Linux"
+display_name = "micronaut-jdbc-graalvm"
+os = "Linux"
+orm = "raw"
+platform = "Netty"
+webserver = "None"
+versus = "micronaut-jdbc"
+
+[r2dbc-graalvm]
+urls.plaintext = "/plaintext"
+urls.json = "/json"
+urls.db = "/db"
+urls.query = "/queries?queries="
+urls.update = "/updates?queries="
+urls.fortune = "/fortunes"
+approach = "Realistic"
+classification = "Micro"
+database = "Postgres"
+database_os = "Linux"
+display_name = "micronaut-r2dbc-graalvm"
+os = "Linux"
+orm = "raw"
+platform = "Netty"
+webserver = "None"
+versus = "micronaut-r2dbc"
+
+[data-jdbc-graalvm]
+urls.plaintext = "/plaintext"
+urls.json = "/json"
+urls.db = "/db"
+urls.query = "/queries?queries="
+urls.update = "/updates?queries="
+urls.fortune = "/fortunes"
+approach = "Realistic"
+classification = "Micro"
+database = "Postgres"
+database_os = "Linux"
+display_name = "micronaut-data-jdbc-graalvm"
+os = "Linux"
+orm = "raw"
+platform = "Netty"
+webserver = "None"
+versus = "micronaut-data-jdbc"
+
+[data-mongodb]
+urls.plaintext = "/plaintext"
+urls.json = "/json"
+urls.db = "/db"
+urls.query = "/queries?queries="
+urls.update = "/updates?queries="
+urls.fortune = "/fortunes"
+approach = "Realistic"
+classification = "Micro"
+database = "MongoDB"
+database_os = "Linux"
+display_name = "micronaut-data-mongodb"
+os = "Linux"
+orm = "raw"
+platform = "Netty"
+webserver = "None"
+versus = "micronaut"
+
+[data-mongodb-graalvm]
+urls.plaintext = "/plaintext"
+urls.json = "/json"
+urls.db = "/db"
+urls.query = "/queries?queries="
+urls.update = "/updates?queries="
+urls.fortune = "/fortunes"
+approach = "Realistic"
+classification = "Micro"
+database = "MongoDB"
+database_os = "Linux"
+display_name = "micronaut-data-mongodb-graalvm"
+os = "Linux"
+orm = "raw"
+platform = "Netty"
+webserver = "None"
+versus = "micronaut-data-mongodb"

+ 1 - 0
frameworks/Java/micronaut/gradle.properties

@@ -0,0 +1 @@
+micronautVersion = 3.7.2

BIN
frameworks/Java/micronaut/gradle/wrapper/gradle-wrapper.jar


+ 1 - 1
frameworks/Java/micronaut/gradle/wrapper/gradle-wrapper.properties

@@ -1,5 +1,5 @@
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-6.9.1-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists

+ 153 - 104
frameworks/Java/micronaut/gradlew

@@ -1,7 +1,7 @@
-#!/usr/bin/env sh
+#!/bin/sh
 
 #
-# Copyright 2015 the original author or authors.
+# Copyright © 2015-2021 the original authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -17,67 +17,101 @@
 #
 
 ##############################################################################
-##
-##  Gradle start up script for UN*X
-##
+#
+#   Gradle start up script for POSIX generated by Gradle.
+#
+#   Important for running:
+#
+#   (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
+#       noncompliant, but you have some other compliant shell such as ksh or
+#       bash, then to run this script, type that shell name before the whole
+#       command line, like:
+#
+#           ksh Gradle
+#
+#       Busybox and similar reduced shells will NOT work, because this script
+#       requires all of these POSIX shell features:
+#         * functions;
+#         * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
+#           «${var#prefix}», «${var%suffix}», and «$( cmd )»;
+#         * compound commands having a testable exit status, especially «case»;
+#         * various built-in commands including «command», «set», and «ulimit».
+#
+#   Important for patching:
+#
+#   (2) This script targets any POSIX shell, so it avoids extensions provided
+#       by Bash, Ksh, etc; in particular arrays are avoided.
+#
+#       The "traditional" practice of packing multiple parameters into a
+#       space-separated string is a well documented source of bugs and security
+#       problems, so this is (mostly) avoided, by progressively accumulating
+#       options in "$@", and eventually passing that to Java.
+#
+#       Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
+#       and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
+#       see the in-line comments for details.
+#
+#       There are tweaks for specific operating systems such as AIX, CygWin,
+#       Darwin, MinGW, and NonStop.
+#
+#   (3) This script is generated from the Groovy template
+#       https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+#       within the Gradle project.
+#
+#       You can find Gradle at https://github.com/gradle/gradle/.
+#
 ##############################################################################
 
 # Attempt to set APP_HOME
+
 # Resolve links: $0 may be a link
-PRG="$0"
-# Need this for relative symlinks.
-while [ -h "$PRG" ] ; do
-    ls=`ls -ld "$PRG"`
-    link=`expr "$ls" : '.*-> \(.*\)$'`
-    if expr "$link" : '/.*' > /dev/null; then
-        PRG="$link"
-    else
-        PRG=`dirname "$PRG"`"/$link"
-    fi
+app_path=$0
+
+# Need this for daisy-chained symlinks.
+while
+    APP_HOME=${app_path%"${app_path##*/}"}  # leaves a trailing /; empty if no leading path
+    [ -h "$app_path" ]
+do
+    ls=$( ls -ld "$app_path" )
+    link=${ls#*' -> '}
+    case $link in             #(
+      /*)   app_path=$link ;; #(
+      *)    app_path=$APP_HOME$link ;;
+    esac
 done
-SAVED="`pwd`"
-cd "`dirname \"$PRG\"`/" >/dev/null
-APP_HOME="`pwd -P`"
-cd "$SAVED" >/dev/null
+
+APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
 
 APP_NAME="Gradle"
-APP_BASE_NAME=`basename "$0"`
+APP_BASE_NAME=${0##*/}
 
 # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
 DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
 
 # Use the maximum available, or set MAX_FD != -1 to use that value.
-MAX_FD="maximum"
+MAX_FD=maximum
 
 warn () {
     echo "$*"
-}
+} >&2
 
 die () {
     echo
     echo "$*"
     echo
     exit 1
-}
+} >&2
 
 # OS specific support (must be 'true' or 'false').
 cygwin=false
 msys=false
 darwin=false
 nonstop=false
-case "`uname`" in
-  CYGWIN* )
-    cygwin=true
-    ;;
-  Darwin* )
-    darwin=true
-    ;;
-  MSYS* | MINGW* )
-    msys=true
-    ;;
-  NONSTOP* )
-    nonstop=true
-    ;;
+case "$( uname )" in                #(
+  CYGWIN* )         cygwin=true  ;; #(
+  Darwin* )         darwin=true  ;; #(
+  MSYS* | MINGW* )  msys=true    ;; #(
+  NONSTOP* )        nonstop=true ;;
 esac
 
 CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
@@ -87,9 +121,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
 if [ -n "$JAVA_HOME" ] ; then
     if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
         # IBM's JDK on AIX uses strange locations for the executables
-        JAVACMD="$JAVA_HOME/jre/sh/java"
+        JAVACMD=$JAVA_HOME/jre/sh/java
     else
-        JAVACMD="$JAVA_HOME/bin/java"
+        JAVACMD=$JAVA_HOME/bin/java
     fi
     if [ ! -x "$JAVACMD" ] ; then
         die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
@@ -98,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the
 location of your Java installation."
     fi
 else
-    JAVACMD="java"
+    JAVACMD=java
     which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
 
 Please set the JAVA_HOME variable in your environment to match the
@@ -106,80 +140,95 @@ location of your Java installation."
 fi
 
 # Increase the maximum file descriptors if we can.
-if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
-    MAX_FD_LIMIT=`ulimit -H -n`
-    if [ $? -eq 0 ] ; then
-        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
-            MAX_FD="$MAX_FD_LIMIT"
-        fi
-        ulimit -n $MAX_FD
-        if [ $? -ne 0 ] ; then
-            warn "Could not set maximum file descriptor limit: $MAX_FD"
-        fi
-    else
-        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
-    fi
+if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
+    case $MAX_FD in #(
+      max*)
+        MAX_FD=$( ulimit -H -n ) ||
+            warn "Could not query maximum file descriptor limit"
+    esac
+    case $MAX_FD in  #(
+      '' | soft) :;; #(
+      *)
+        ulimit -n "$MAX_FD" ||
+            warn "Could not set maximum file descriptor limit to $MAX_FD"
+    esac
 fi
 
-# For Darwin, add options to specify how the application appears in the dock
-if $darwin; then
-    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
-fi
+# Collect all arguments for the java command, stacking in reverse order:
+#   * args from the command line
+#   * the main class name
+#   * -classpath
+#   * -D...appname settings
+#   * --module-path (only if needed)
+#   * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
 
 # For Cygwin or MSYS, switch paths to Windows format before running java
-if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
-    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
-    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
-
-    JAVACMD=`cygpath --unix "$JAVACMD"`
-
-    # We build the pattern for arguments to be converted via cygpath
-    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
-    SEP=""
-    for dir in $ROOTDIRSRAW ; do
-        ROOTDIRS="$ROOTDIRS$SEP$dir"
-        SEP="|"
-    done
-    OURCYGPATTERN="(^($ROOTDIRS))"
-    # Add a user-defined pattern to the cygpath arguments
-    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
-        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
-    fi
+if "$cygwin" || "$msys" ; then
+    APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
+    CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
+
+    JAVACMD=$( cygpath --unix "$JAVACMD" )
+
     # Now convert the arguments - kludge to limit ourselves to /bin/sh
-    i=0
-    for arg in "$@" ; do
-        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
-        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option
-
-        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
-            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
-        else
-            eval `echo args$i`="\"$arg\""
+    for arg do
+        if
+            case $arg in                                #(
+              -*)   false ;;                            # don't mess with options #(
+              /?*)  t=${arg#/} t=/${t%%/*}              # looks like a POSIX filepath
+                    [ -e "$t" ] ;;                      #(
+              *)    false ;;
+            esac
+        then
+            arg=$( cygpath --path --ignore --mixed "$arg" )
         fi
-        i=`expr $i + 1`
+        # Roll the args list around exactly as many times as the number of
+        # args, so each arg winds up back in the position where it started, but
+        # possibly modified.
+        #
+        # NB: a `for` loop captures its iteration list before it begins, so
+        # changing the positional parameters here affects neither the number of
+        # iterations, nor the values presented in `arg`.
+        shift                   # remove old arg
+        set -- "$@" "$arg"      # push replacement arg
     done
-    case $i in
-        0) set -- ;;
-        1) set -- "$args0" ;;
-        2) set -- "$args0" "$args1" ;;
-        3) set -- "$args0" "$args1" "$args2" ;;
-        4) set -- "$args0" "$args1" "$args2" "$args3" ;;
-        5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
-        6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
-        7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
-        8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
-        9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
-    esac
 fi
 
-# Escape application args
-save () {
-    for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
-    echo " "
-}
-APP_ARGS=`save "$@"`
+# Collect all arguments for the java command;
+#   * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
+#     shell script including quotes and variable substitutions, so put them in
+#     double quotes to make sure that they get re-expanded; and
+#   * put everything else in single quotes, so that it's not re-expanded.
+
+set -- \
+        "-Dorg.gradle.appname=$APP_BASE_NAME" \
+        -classpath "$CLASSPATH" \
+        org.gradle.wrapper.GradleWrapperMain \
+        "$@"
+
+# Use "xargs" to parse quoted args.
+#
+# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
+#
+# In Bash we could simply go:
+#
+#   readarray ARGS < <( xargs -n1 <<<"$var" ) &&
+#   set -- "${ARGS[@]}" "$@"
+#
+# but POSIX shell has neither arrays nor command substitution, so instead we
+# post-process each arg (as a line of input to sed) to backslash-escape any
+# character that might be a shell metacharacter, then use eval to reverse
+# that process (while maintaining the separation between arguments), and wrap
+# the whole thing up as a single "set" statement.
+#
+# This will of course break if any of these variables contains a newline or
+# an unmatched quote.
+#
 
-# Collect all arguments for the java command, following the shell quoting and substitution rules
-eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+eval "set -- $(
+        printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
+        xargs -n1 |
+        sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
+        tr '\n' ' '
+    )" '"$@"'
 
 exec "$JAVACMD" "$@"

+ 14 - 0
frameworks/Java/micronaut/micronaut-data-jdbc-graalvm.dockerfile

@@ -0,0 +1,14 @@
+FROM ghcr.io/graalvm/graalvm-ce:ol7-java17-22.3.0 as build
+COPY . /home/gradle/src
+WORKDIR /home/gradle/src
+RUN ./gradlew  --no-daemon
+RUN ./gradlew micronaut-data-jdbc:nativeBuild -x test --no-daemon
+
+FROM frolvlad/alpine-glibc:alpine-3.12
+RUN apk --no-cache update && apk add libstdc++
+WORKDIR /micronaut
+COPY --from=build /home/gradle/src/micronaut-data-jdbc/build/native/nativeCompile/micronaut-data-jdbc micronaut
+
+EXPOSE 8080
+ENV MICRONAUT_ENVIRONMENTS=benchmark
+ENTRYPOINT "./micronaut"

+ 12 - 0
frameworks/Java/micronaut/micronaut-data-jdbc.dockerfile

@@ -0,0 +1,12 @@
+FROM gradle:7.5.1-jdk18 as build
+COPY --chown=gradle:gradle . /home/gradle/src
+WORKDIR /home/gradle/src
+RUN gradle micronaut-data-jdbc:build -x test --no-daemon
+
+FROM openjdk:19
+WORKDIR /micronaut
+COPY --from=build /home/gradle/src/micronaut-data-jdbc/build/libs/micronaut-data-jdbc-all.jar micronaut.jar
+COPY run_benchmark.sh run_benchmark.sh
+
+EXPOSE 8080
+ENTRYPOINT "./run_benchmark.sh"

+ 10 - 0
frameworks/Java/micronaut/micronaut-data-jdbc/build.gradle

@@ -0,0 +1,10 @@
+plugins {
+    id 'io.micronaut.benchmark.module'
+}
+
+dependencies {
+    implementation("io.micronaut.data:micronaut-data-jdbc")
+    implementation("io.micronaut.sql:micronaut-jdbc-hikari")
+    implementation("io.micronaut:micronaut-jackson-databind")
+    implementation("org.postgresql:postgresql")
+}

+ 23 - 0
frameworks/Java/micronaut/micronaut-data-jdbc/src/main/java/benchmark/JdbcFortuneRepository.java

@@ -0,0 +1,23 @@
+package benchmark;
+
+import benchmark.model.Fortune;
+import benchmark.repository.FortuneRepository;
+import io.micronaut.data.jdbc.annotation.JdbcRepository;
+import io.micronaut.data.model.query.builder.sql.Dialect;
+import io.micronaut.data.repository.GenericRepository;
+
+import java.util.Collection;
+
+@JdbcRepository(dialect = Dialect.POSTGRES)
+public interface JdbcFortuneRepository extends GenericRepository<Fortune, Integer>, FortuneRepository {
+
+    default void initDb(Collection<Fortune> fortunes) {
+        deleteAll();
+        saveAll(fortunes);
+    }
+
+    void saveAll(Collection<Fortune> fortunes);
+
+    void deleteAll();
+
+}

+ 30 - 0
frameworks/Java/micronaut/micronaut-data-jdbc/src/main/java/benchmark/JdbcWorldRepository.java

@@ -0,0 +1,30 @@
+package benchmark;
+
+import benchmark.model.World;
+import benchmark.repository.WorldRepository;
+import io.micronaut.data.jdbc.annotation.JdbcRepository;
+import io.micronaut.data.model.query.builder.sql.Dialect;
+import io.micronaut.data.repository.GenericRepository;
+import io.micronaut.transaction.annotation.ReadOnly;
+
+import java.util.Collection;
+import java.util.List;
+
+@JdbcRepository(dialect = Dialect.POSTGRES)
+public interface JdbcWorldRepository extends GenericRepository<World, Integer>, WorldRepository {
+
+    default void initDb(Collection<World> worlds) {
+        deleteAll();
+        saveAll(worlds);
+    }
+
+    void saveAll(Collection<World> worlds);
+
+    @Override
+    default List<World> findByIds(List<Integer> ids) {
+        return WorldRepository.super.findByIds(ids);
+    }
+
+    void deleteAll();
+
+}

+ 5 - 0
frameworks/Java/micronaut/micronaut-data-jdbc/src/main/resources/application.yml

@@ -0,0 +1,5 @@
+micronaut:
+  netty:
+    event-loops:
+      default:
+        prefer-native-transport: true

+ 3 - 0
frameworks/Java/micronaut/micronaut-data-jdbc/src/test/resources/application-test.yml

@@ -0,0 +1,3 @@
+datasources:
+  default:
+    schema-generate: CREATE_DROP

+ 14 - 0
frameworks/Java/micronaut/micronaut-data-mongodb-graalvm.dockerfile

@@ -0,0 +1,14 @@
+FROM ghcr.io/graalvm/graalvm-ce:ol7-java17-22.3.0 as build
+COPY . /home/gradle/src
+WORKDIR /home/gradle/src
+RUN ./gradlew  --no-daemon
+RUN ./gradlew micronaut-data-mongodb:nativeBuild -x test --no-daemon
+
+FROM frolvlad/alpine-glibc:alpine-3.12
+RUN apk --no-cache update && apk add libstdc++
+WORKDIR /micronaut
+COPY --from=build /home/gradle/src/micronaut-data-mongodb/build/native/nativeCompile/micronaut-data-mongodb micronaut
+
+EXPOSE 8080
+ENV MICRONAUT_ENVIRONMENTS=benchmark
+ENTRYPOINT "./micronaut"

+ 12 - 0
frameworks/Java/micronaut/micronaut-data-mongodb.dockerfile

@@ -0,0 +1,12 @@
+FROM gradle:7.5.1-jdk18 as build
+COPY --chown=gradle:gradle . /home/gradle/src
+WORKDIR /home/gradle/src
+RUN gradle micronaut-data-mongodb:build -x test --no-daemon
+
+FROM openjdk:19
+WORKDIR /micronaut
+COPY --from=build /home/gradle/src/micronaut-data-mongodb/build/libs/micronaut-data-mongodb-all.jar micronaut.jar
+COPY run_benchmark.sh run_benchmark.sh
+
+EXPOSE 8080
+ENTRYPOINT "./run_benchmark.sh"

+ 9 - 0
frameworks/Java/micronaut/micronaut-data-mongodb/build.gradle

@@ -0,0 +1,9 @@
+plugins {
+    id 'io.micronaut.benchmark.module'
+}
+
+dependencies {
+    annotationProcessor("io.micronaut.data:micronaut-data-document-processor")
+    implementation("io.micronaut.data:micronaut-data-mongodb:3.8.1")
+    runtimeOnly("io.micronaut.mongodb:micronaut-mongo-sync")
+}

+ 22 - 0
frameworks/Java/micronaut/micronaut-data-mongodb/src/main/java/benchmark/MongoFortuneRepository.java

@@ -0,0 +1,22 @@
+package benchmark;
+
+import benchmark.model.Fortune;
+import benchmark.repository.FortuneRepository;
+import io.micronaut.data.mongodb.annotation.MongoRepository;
+import io.micronaut.data.repository.GenericRepository;
+
+import java.util.Collection;
+
+@MongoRepository
+public interface MongoFortuneRepository extends GenericRepository<Fortune, Integer>, FortuneRepository {
+
+    default void initDb(Collection<Fortune> fortunes) {
+        deleteAll();
+        saveAll(fortunes);
+    }
+
+    void saveAll(Collection<Fortune> fortunes);
+
+    void deleteAll();
+
+}

+ 27 - 0
frameworks/Java/micronaut/micronaut-data-mongodb/src/main/java/benchmark/MongoWorldRepository.java

@@ -0,0 +1,27 @@
+package benchmark;
+
+import benchmark.model.World;
+import benchmark.repository.WorldRepository;
+import io.micronaut.data.mongodb.annotation.MongoRepository;
+import io.micronaut.data.repository.GenericRepository;
+
+import java.util.Collection;
+import java.util.List;
+
+@MongoRepository
+public interface MongoWorldRepository extends GenericRepository<World, Integer>, WorldRepository {
+
+    default void initDb(Collection<World> worlds) {
+        deleteAll();
+        saveAll(worlds);
+    }
+
+    void saveAll(Collection<World> worlds);
+
+    void deleteAll();
+
+    @Override
+    default List<World> findByIds(List<Integer> ids) {
+        return WorldRepository.super.findByIds(ids);
+    }
+}

+ 5 - 0
frameworks/Java/micronaut/micronaut-data-mongodb/src/main/resources/application.yml

@@ -0,0 +1,5 @@
+micronaut:
+  netty:
+    event-loops:
+      default:
+        prefer-native-transport: true

+ 5 - 0
frameworks/Java/micronaut/micronaut-data-mongodb/src/test/resources/application-test.yml

@@ -0,0 +1,5 @@
+r2dbc:
+  datasources:
+    default:
+      schema-generate: CREATE_DROP
+      dialect: POSTGRES

+ 14 - 0
frameworks/Java/micronaut/micronaut-data-r2dbc-graalvm.dockerfile

@@ -0,0 +1,14 @@
+FROM ghcr.io/graalvm/graalvm-ce:ol7-java17-22.3.0 as build
+COPY . /home/gradle/src
+WORKDIR /home/gradle/src
+RUN ./gradlew  --no-daemon
+RUN ./gradlew micronaut-data-r2dbc:nativeBuild -x test --no-daemon
+
+FROM frolvlad/alpine-glibc:alpine-3.12
+RUN apk --no-cache update && apk add libstdc++
+WORKDIR /micronaut
+COPY --from=build /home/gradle/src/micronaut-data-r2dbc/build/native/nativeCompile/micronaut-data-r2dbc micronaut
+
+EXPOSE 8080
+ENV MICRONAUT_ENVIRONMENTS=benchmark
+ENTRYPOINT "./micronaut"

+ 12 - 0
frameworks/Java/micronaut/micronaut-data-r2dbc.dockerfile

@@ -0,0 +1,12 @@
+FROM gradle:7.5.1-jdk18 as build
+COPY --chown=gradle:gradle . /home/gradle/src
+WORKDIR /home/gradle/src
+RUN gradle micronaut-data-r2dbc:build -x test --no-daemon
+
+FROM openjdk:19
+WORKDIR /micronaut
+COPY --from=build /home/gradle/src/micronaut-data-r2dbc/build/libs/micronaut-data-r2dbc-all.jar micronaut.jar
+COPY run_benchmark.sh run_benchmark.sh
+
+EXPOSE 8080
+ENTRYPOINT "./run_benchmark.sh"

+ 9 - 0
frameworks/Java/micronaut/micronaut-data-r2dbc/build.gradle

@@ -0,0 +1,9 @@
+plugins {
+    id 'io.micronaut.benchmark.module'
+}
+
+dependencies {
+    implementation("io.micronaut.data:micronaut-data-r2dbc")
+    runtimeOnly("org.postgresql:r2dbc-postgresql")
+    implementation("io.r2dbc:r2dbc-pool")
+}

+ 32 - 0
frameworks/Java/micronaut/micronaut-data-r2dbc/src/main/java/benchmark/R2dbcFortuneRepository.java

@@ -0,0 +1,32 @@
+package benchmark;
+
+import benchmark.model.Fortune;
+import benchmark.repository.ReactiveFortuneRepository;
+import io.micronaut.data.model.query.builder.sql.Dialect;
+import io.micronaut.data.r2dbc.annotation.R2dbcRepository;
+import io.micronaut.data.repository.GenericRepository;
+import org.reactivestreams.Publisher;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+
+import java.util.Collection;
+import java.util.List;
+
+@R2dbcRepository(dialect = Dialect.POSTGRES)
+public interface R2dbcFortuneRepository extends GenericRepository<Fortune, Integer>, ReactiveFortuneRepository {
+
+    default Publisher<Void> initDb(Collection<Fortune> fortunes) {
+        return deleteAll().then(saveAll(fortunes));
+    }
+
+    Mono<Void> saveAll(Collection<Fortune> fortunes);
+
+    Mono<Void> deleteAll();
+
+    @Override
+    default Publisher<List<Fortune>> findAll() {
+        return Flux.from(queryAll()).collectList();
+    }
+
+    Publisher<Fortune> queryAll();
+}

+ 32 - 0
frameworks/Java/micronaut/micronaut-data-r2dbc/src/main/java/benchmark/R2dbcWorldRepository.java

@@ -0,0 +1,32 @@
+package benchmark;
+
+import benchmark.model.World;
+import benchmark.repository.ReactiveWorldRepository;
+import io.micronaut.data.model.query.builder.sql.Dialect;
+import io.micronaut.data.r2dbc.annotation.R2dbcRepository;
+import io.micronaut.data.repository.GenericRepository;
+import io.micronaut.transaction.annotation.ReadOnly;
+import org.reactivestreams.Publisher;
+import reactor.core.publisher.Mono;
+
+import javax.transaction.Transactional;
+import java.util.Collection;
+import java.util.List;
+
+@R2dbcRepository(dialect = Dialect.POSTGRES)
+public interface R2dbcWorldRepository extends GenericRepository<World, Integer>, ReactiveWorldRepository {
+
+    default Mono<Void> initDb(Collection<World> worlds) {
+        return deleteAll().then(saveAll(worlds));
+    }
+
+    @Override
+    default Publisher<List<World>> findByIds(List<Integer> ids) {
+        return ReactiveWorldRepository.super.findByIds(ids);
+    }
+
+    Mono<Void> saveAll(Collection<World> worlds);
+
+    Mono<Void> deleteAll();
+
+}

+ 26 - 0
frameworks/Java/micronaut/micronaut-data-r2dbc/src/main/resources/META-INF/native-image/io.micronaut.benchmark/io.micronaut.benchmark.data.r2dbc/reflect-config.json

@@ -0,0 +1,26 @@
+[
+  {
+    "name": "java.time.Instant[]",
+    "allPublicMethods": true,
+    "allDeclaredConstructors": true
+  },
+  {
+    "name": "java.time.ZonedDateTime[]",
+    "allPublicMethods": true,
+    "allDeclaredConstructors": true
+  },
+  {
+    "name": "java.net.URL[]",
+    "allPublicMethods": true,
+    "allDeclaredConstructors": true
+  },
+  {
+    "name": "java.util.Date[]",
+    "allPublicMethods": true,
+    "allDeclaredConstructors": true
+  },
+  {
+    "name": "java.net.URI[]",
+    "unsafeAllocated": true
+  }
+]

+ 5 - 0
frameworks/Java/micronaut/micronaut-data-r2dbc/src/test/resources/application-test.yml

@@ -0,0 +1,5 @@
+r2dbc:
+  datasources:
+    default:
+      schema-generate: CREATE_DROP
+      dialect: POSTGRES

+ 14 - 0
frameworks/Java/micronaut/micronaut-jdbc-graalvm.dockerfile

@@ -0,0 +1,14 @@
+FROM ghcr.io/graalvm/graalvm-ce:ol7-java17-22.3.0 as build
+COPY . /home/gradle/src
+WORKDIR /home/gradle/src
+RUN ./gradlew  --no-daemon
+RUN ./gradlew micronaut-jdbc:nativeBuild -x test --no-daemon
+
+FROM frolvlad/alpine-glibc:alpine-3.12
+RUN apk --no-cache update && apk add libstdc++
+WORKDIR /micronaut
+COPY --from=build /home/gradle/src/micronaut-jdbc/build/native/nativeCompile/micronaut-jdbc micronaut
+
+EXPOSE 8080
+ENV MICRONAUT_ENVIRONMENTS=benchmark
+ENTRYPOINT "./micronaut"

+ 12 - 0
frameworks/Java/micronaut/micronaut-jdbc.dockerfile

@@ -0,0 +1,12 @@
+FROM gradle:7.5.1-jdk18 as build
+COPY --chown=gradle:gradle . /home/gradle/src
+WORKDIR /home/gradle/src
+RUN gradle micronaut-jdbc:build -x test --no-daemon
+
+FROM openjdk:19
+WORKDIR /micronaut
+COPY --from=build /home/gradle/src/micronaut-jdbc/build/libs/micronaut-jdbc-all.jar micronaut.jar
+COPY run_benchmark.sh run_benchmark.sh
+
+EXPOSE 8080
+ENTRYPOINT "./run_benchmark.sh"

+ 16 - 0
frameworks/Java/micronaut/micronaut-jdbc/build.gradle

@@ -0,0 +1,16 @@
+plugins {
+    id 'io.micronaut.benchmark.module'
+}
+
+micronaut {
+    testResources {
+        additionalModules.add(JDBC_POSTGRESQL)
+    }
+}
+
+dependencies {
+    implementation("io.micronaut.sql:micronaut-jdbc")
+    implementation("io.micronaut.sql:micronaut-jdbc-hikari")
+    implementation("io.micronaut:micronaut-jackson-databind")
+    implementation("org.postgresql:postgresql")
+}

+ 62 - 0
frameworks/Java/micronaut/micronaut-jdbc/src/main/java/benchmark/JdbcFortuneRepository.java

@@ -0,0 +1,62 @@
+package benchmark;
+
+import benchmark.model.Fortune;
+import benchmark.model.World;
+import benchmark.repository.FortuneRepository;
+import jakarta.inject.Singleton;
+
+import javax.sql.DataSource;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+@Singleton
+public class JdbcFortuneRepository implements FortuneRepository {
+
+    private final DataSource dataSource;
+
+    public JdbcFortuneRepository(DataSource dataSource) {
+        this.dataSource = dataSource;
+    }
+
+    @Override
+    public void initDb(Collection<Fortune> fortunes) {
+        try (Connection connection = dataSource.getConnection()) {
+            connection.createStatement().execute("DROP TABLE IF EXISTS Fortune;");
+            connection.createStatement().execute("CREATE TABLE Fortune (id INTEGER NOT NULL,message VARCHAR(255) NOT NULL);");
+            try (PreparedStatement statement = connection.prepareStatement("INSERT INTO fortune VALUES (?, ?);")) {
+                for (Fortune fortune : fortunes) {
+                    statement.setInt(1, fortune.getId());
+                    statement.setString(2, fortune.getMessage());
+                    statement.addBatch();
+                }
+                statement.executeBatch();
+            }
+        } catch (SQLException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Override
+    public Collection<Fortune> findAll() {
+        try (Connection connection = dataSource.getConnection()) {
+            try (PreparedStatement statement = connection.prepareStatement("SELECT id, message FROM fortune",
+                    ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY)) {
+                List<Fortune> fortunes = new ArrayList<>();
+                try (ResultSet resultSet = statement.executeQuery()) {
+                    while (resultSet.next()) {
+                        fortunes.add(new Fortune(resultSet.getInt(1), resultSet.getString(2)));
+                    }
+                }
+                return fortunes;
+            }
+        } catch (SQLException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+}

+ 99 - 0
frameworks/Java/micronaut/micronaut-jdbc/src/main/java/benchmark/JdbcWorldRepository.java

@@ -0,0 +1,99 @@
+package benchmark;
+
+import benchmark.model.World;
+import benchmark.repository.WorldRepository;
+import jakarta.inject.Singleton;
+
+import javax.sql.DataSource;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+@Singleton
+public class JdbcWorldRepository implements WorldRepository {
+
+    private final DataSource dataSource;
+
+    public JdbcWorldRepository(DataSource dataSource) {
+        this.dataSource = dataSource;
+    }
+
+    @Override
+    public void initDb(Collection<World> worlds) {
+        try (Connection connection = dataSource.getConnection()) {
+            connection.createStatement().execute("DROP TABLE IF EXISTS World;");
+            connection.createStatement().execute("CREATE TABLE World (id INTEGER NOT NULL,randomNumber INTEGER NOT NULL);");
+            try (PreparedStatement statement = connection.prepareStatement("INSERT INTO world VALUES (?, ?);")) {
+                for (World world : worlds) {
+                    statement.setInt(1, world.getId());
+                    statement.setInt(2, world.getRandomNumber());
+                    statement.addBatch();
+                }
+                statement.executeBatch();
+            }
+        } catch (SQLException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Override
+    public World findById(Integer id) {
+        try (Connection connection = dataSource.getConnection()) {
+            try (PreparedStatement statement = connection.prepareStatement("SELECT * FROM world WHERE id = ?")) {
+                statement.setInt(1, id);
+                try (ResultSet resultSet = statement.executeQuery()) {
+                    if (resultSet.next()) {
+                        return new World(resultSet.getInt(1), resultSet.getInt(2));
+                    }
+                    throw new IllegalStateException("World with id: " + id + " not found!");
+                }
+            }
+        } catch (SQLException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Override
+    public List<World> findByIds(List<Integer> ids) {
+        List<World> worlds = new ArrayList<>(ids.size());
+        try (Connection connection = dataSource.getConnection()) {
+            try (PreparedStatement statement = connection.prepareStatement("SELECT * FROM world WHERE id = ?",
+                    ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY)) {
+                for (Integer randomNumber : ids) {
+                    statement.setInt(1, randomNumber);
+                    try (ResultSet resultSet = statement.executeQuery()) {
+                        if (resultSet.next()) {
+                            worlds.add(new World(resultSet.getInt(1), resultSet.getInt(2)));
+                            continue;
+                        }
+                        throw new IllegalStateException("World with id: " + randomNumber + " not found!");
+                    }
+                }
+            }
+        } catch (SQLException e) {
+            throw new RuntimeException(e);
+        }
+        return worlds;
+    }
+
+    @Override
+    public void updateAll(Collection<World> worlds) {
+        try (Connection connection = dataSource.getConnection()) {
+            try (PreparedStatement statement = connection.prepareStatement("UPDATE world SET randomnumber = ? WHERE id = ?")) {
+                for (World world : worlds) {
+                    statement.setInt(1, world.getRandomNumber());
+                    statement.setInt(2, world.getId());
+                    statement.addBatch();
+                }
+                statement.executeBatch();
+            }
+        } catch (SQLException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+}

+ 5 - 0
frameworks/Java/micronaut/micronaut-jdbc/src/main/resources/application.yml

@@ -0,0 +1,5 @@
+micronaut:
+  netty:
+    event-loops:
+      default:
+        prefer-native-transport: true

+ 3 - 0
frameworks/Java/micronaut/micronaut-jdbc/src/test/resources/application-test.yml

@@ -0,0 +1,3 @@
+datasources:
+  default:
+    schema-generate: CREATE_DROP

+ 0 - 13
frameworks/Java/micronaut/micronaut-native.dockerfile

@@ -1,13 +0,0 @@
-FROM ghcr.io/graalvm/graalvm-ce:java11-21.3.0
-RUN gu install native-image
-WORKDIR /micronaut
-COPY build.gradle build.gradle
-COPY settings.gradle settings.gradle
-COPY gradlew gradlew
-COPY gradle gradle
-COPY src src
-RUN sh ./gradlew build nativeImage --no-daemon
-
-EXPOSE 8080
-
-CMD ["/micronaut/build/native-image/application", "-Dmicronaut.environments=benchmark", "-Dlog-root-level=OFF"]

+ 14 - 0
frameworks/Java/micronaut/micronaut-r2dbc-graalvm.dockerfile

@@ -0,0 +1,14 @@
+FROM ghcr.io/graalvm/graalvm-ce:ol7-java17-22.3.0 as build
+COPY . /home/gradle/src
+WORKDIR /home/gradle/src
+RUN ./gradlew  --no-daemon
+RUN ./gradlew micronaut-r2dbc:nativeBuild -x test --no-daemon
+
+FROM frolvlad/alpine-glibc:alpine-3.12
+RUN apk --no-cache update && apk add libstdc++
+WORKDIR /micronaut
+COPY --from=build /home/gradle/src/micronaut-r2dbc/build/native/nativeCompile/micronaut-r2dbc micronaut
+
+EXPOSE 8080
+ENV MICRONAUT_ENVIRONMENTS=benchmark
+ENTRYPOINT "./micronaut"

+ 12 - 0
frameworks/Java/micronaut/micronaut-r2dbc.dockerfile

@@ -0,0 +1,12 @@
+FROM gradle:7.5.1-jdk18 as build
+COPY --chown=gradle:gradle . /home/gradle/src
+WORKDIR /home/gradle/src
+RUN gradle micronaut-r2dbc:build -x test --no-daemon
+
+FROM openjdk:19
+WORKDIR /micronaut
+COPY --from=build /home/gradle/src/micronaut-r2dbc/build/libs/micronaut-r2dbc-all.jar micronaut.jar
+COPY run_benchmark.sh run_benchmark.sh
+
+EXPOSE 8080
+ENTRYPOINT "./run_benchmark.sh"

+ 15 - 0
frameworks/Java/micronaut/micronaut-r2dbc/build.gradle

@@ -0,0 +1,15 @@
+plugins {
+    id 'io.micronaut.benchmark.module'
+}
+
+micronaut {
+    testResources {
+        additionalModules.add(R2DBC_POSTGRESQL)
+    }
+}
+
+dependencies {
+    implementation("io.micronaut.r2dbc:micronaut-r2dbc-core")
+    runtimeOnly("org.postgresql:r2dbc-postgresql")
+    implementation("io.r2dbc:r2dbc-pool")
+}

+ 66 - 0
frameworks/Java/micronaut/micronaut-r2dbc/src/main/java/benchmark/R2dbcFortuneRepository.java

@@ -0,0 +1,66 @@
+package benchmark;
+
+import benchmark.model.Fortune;
+import benchmark.repository.ReactiveFortuneRepository;
+import io.r2dbc.spi.Connection;
+import io.r2dbc.spi.ConnectionFactory;
+import io.r2dbc.spi.Result;
+import io.r2dbc.spi.Statement;
+import jakarta.inject.Singleton;
+import org.reactivestreams.Publisher;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+
+import java.util.Collection;
+import java.util.List;
+
+@Singleton
+public class R2dbcFortuneRepository implements ReactiveFortuneRepository {
+
+    private final ConnectionFactory connectionFactory;
+
+    public R2dbcFortuneRepository(ConnectionFactory connectionFactory) {
+        this.connectionFactory = connectionFactory;
+    }
+
+    @Override
+    public Publisher<Void> initDb(Collection<Fortune> fortunes) {
+        return Mono.from(connectionFactory.create())
+                .flatMap(connection -> createTable(connection).then(createFutures(connection, fortunes)).then(Mono.from(connection.close())));
+    }
+
+    private static Mono<Void> createTable(io.r2dbc.spi.Connection connection) {
+        return execute(connection, "DROP TABLE IF EXISTS Fortune;")
+                .then(execute(connection, "CREATE TABLE Fortune (id INTEGER NOT NULL,message VARCHAR(255));"));
+    }
+
+    private static Mono<Void> execute(io.r2dbc.spi.Connection connection, String sql) {
+        return Flux.from(connection.createStatement(sql).execute())
+                .flatMap(Result::getRowsUpdated).then();
+    }
+
+    private static Mono<Void> createFutures(io.r2dbc.spi.Connection connection, Collection<Fortune> fortunes) {
+        Statement statement = connection.createStatement("INSERT INTO fortune VALUES ($1, $2);");
+        boolean first = true;
+        for (Fortune fortune : fortunes) {
+            if (!first) {
+                statement.add();
+            } else {
+                first = false;
+            }
+            statement.bind(0, fortune.getId());
+            statement.bind(1, fortune.getMessage());
+        }
+        return Flux.from(statement.execute()).flatMap(Result::getRowsUpdated).then();
+    }
+
+    @Override
+    public Publisher<List<Fortune>> findAll() {
+        return Flux.usingWhen(connectionFactory.create(),
+                connection -> Flux.from(connection.createStatement("SELECT id, message FROM fortune").execute())
+                        .flatMap(result -> result.map((row, rowMetadata) -> new Fortune(row.get(0, Integer.class), row.get(1, String.class))))
+                        .collectList(),
+                Connection::close);
+    }
+
+}

+ 106 - 0
frameworks/Java/micronaut/micronaut-r2dbc/src/main/java/benchmark/R2dbcWorldRepository.java

@@ -0,0 +1,106 @@
+package benchmark;
+
+import benchmark.model.World;
+import benchmark.repository.ReactiveWorldRepository;
+import io.r2dbc.spi.Connection;
+import io.r2dbc.spi.ConnectionFactory;
+import io.r2dbc.spi.Result;
+import io.r2dbc.spi.Statement;
+import jakarta.inject.Singleton;
+import org.reactivestreams.Publisher;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+
+import java.util.Collection;
+import java.util.List;
+
+@Singleton
+public class R2dbcWorldRepository implements ReactiveWorldRepository {
+
+    private final ConnectionFactory connectionFactory;
+
+    public R2dbcWorldRepository(ConnectionFactory connectionFactory) {
+        this.connectionFactory = connectionFactory;
+    }
+
+    @Override
+    public Publisher<Void> initDb(Collection<World> worlds) {
+        return Mono.from(connectionFactory.create())
+                .flatMap(connection -> createTable(connection).then(createWorlds(connection, worlds)).then(Mono.from(connection.close())));
+    }
+
+    private static Mono<Void> createTable(io.r2dbc.spi.Connection connection) {
+        return execute(connection, "DROP TABLE IF EXISTS World;")
+                .then(execute(connection, "CREATE TABLE World (id INTEGER NOT NULL,randomNumber INTEGER NOT NULL);"));
+    }
+
+    private static Mono<Void> execute(io.r2dbc.spi.Connection connection, String sql) {
+        return Flux.from(connection.createStatement(sql).execute())
+                .flatMap(Result::getRowsUpdated).then();
+    }
+
+    private static Mono<Void> createWorlds(io.r2dbc.spi.Connection connection, Collection<World> worlds) {
+        Statement statement = connection.createStatement("INSERT INTO world VALUES ($1, $2);");
+        boolean first = true;
+        for (World world : worlds) {
+            if (!first) {
+                statement.add();
+            } else {
+                first = false;
+            }
+            statement.bind(0, world.getId());
+            statement.bind(1, world.getRandomNumber());
+        }
+        return Flux.from(statement.execute()).flatMap(Result::getRowsUpdated).then();
+    }
+
+    @Override
+    public Publisher<World> findById(Integer id) {
+        return Mono.usingWhen(connectionFactory.create(),
+                connection -> Mono.from(connection.createStatement("SELECT * FROM world WHERE id = $1").bind(0, id).execute())
+                        .flatMap(result -> Mono.from(result.map((row, rowMetadata) -> new World(row.get(0, Integer.class), row.get(1, Integer.class))))),
+                Connection::close);
+    }
+
+    @Override
+    public Publisher<List<World>> findByIds(List<Integer> ids) {
+        return Mono.usingWhen(connectionFactory.create(),
+                connection -> {
+                    Statement statement = connection.createStatement("SELECT * FROM world WHERE id = $1");
+                    boolean first = true;
+                    for (Integer id : ids) {
+                        if (!first) {
+                            statement.add();
+                        } else {
+                            first = false;
+                        }
+                        statement.bind(0, id);
+                    }
+                    return Flux.from(statement.execute())
+                            .flatMap(result -> Flux.from(result.map((row, rowMetadata) -> new World(row.get(0, Integer.class), row.get(1, Integer.class)))))
+                            .collectList();
+                },
+                Connection::close);
+    }
+
+    @Override
+    public Publisher<Void> updateAll(Collection<World> worlds) {
+        return Mono.usingWhen(connectionFactory.create(),
+                connection -> {
+                    Statement statement = connection.createStatement("UPDATE world SET randomnumber = $2 WHERE id = $1");
+                    boolean first = true;
+                    for (World world : worlds) {
+                        if (!first) {
+                            statement.add();
+                        } else {
+                            first = false;
+                        }
+                        statement.bind(0, world.getId());
+                        statement.bind(1, world.getRandomNumber());
+                    }
+                    return Flux.from(statement.execute()).flatMap(Result::getRowsUpdated).then();
+                },
+                Connection::close).then();
+    }
+
+}

+ 26 - 0
frameworks/Java/micronaut/micronaut-r2dbc/src/main/resources/META-INF/native-image/io.micronaut.benchmark/io.micronaut.benchmark.r2dbc/reflect-config.json

@@ -0,0 +1,26 @@
+[
+  {
+    "name": "java.time.Instant[]",
+    "allPublicMethods": true,
+    "allDeclaredConstructors": true
+  },
+  {
+    "name": "java.time.ZonedDateTime[]",
+    "allPublicMethods": true,
+    "allDeclaredConstructors": true
+  },
+  {
+    "name": "java.net.URL[]",
+    "allPublicMethods": true,
+    "allDeclaredConstructors": true
+  },
+  {
+    "name": "java.util.Date[]",
+    "allPublicMethods": true,
+    "allDeclaredConstructors": true
+  },
+  {
+    "name": "java.net.URI[]",
+    "unsafeAllocated": true
+  }
+]

+ 5 - 0
frameworks/Java/micronaut/micronaut-r2dbc/src/test/resources/application-test.yml

@@ -0,0 +1,5 @@
+r2dbc:
+  datasources:
+    default:
+      schema-generate: CREATE_DROP
+      dialect: POSTGRES

+ 14 - 0
frameworks/Java/micronaut/micronaut-vertx-pg-client-graalvm.dockerfile

@@ -0,0 +1,14 @@
+FROM ghcr.io/graalvm/graalvm-ce:ol7-java17-22.3.0 as build
+COPY . /home/gradle/src
+WORKDIR /home/gradle/src
+RUN ./gradlew  --no-daemon
+RUN ./gradlew micronaut-vertx-pg-client:nativeBuild -x test --no-daemon
+
+FROM frolvlad/alpine-glibc:alpine-3.12
+RUN apk --no-cache update && apk add libstdc++
+WORKDIR /micronaut
+COPY --from=build /home/gradle/src/micronaut-vertx-pg-client/build/native/nativeCompile/micronaut-vertx-pg-client micronaut
+
+EXPOSE 8080
+ENV MICRONAUT_ENVIRONMENTS=benchmark
+ENTRYPOINT "./micronaut"

+ 22 - 0
frameworks/Java/micronaut/micronaut-vertx-pg-client/build.gradle

@@ -0,0 +1,22 @@
+plugins {
+    id 'io.micronaut.benchmark.module'
+}
+
+graalvmNative.binaries.all {
+    buildArgs.add("--initialize-at-build-time=" +
+            "io.vertx.core.logging.LoggerFactory," +
+            "io.vertx.core.logging.SLF4JLogDelegateFactory," +
+            "io.vertx.core.logging.SLF4JLogDelegate," +
+            "io.vertx.pgclient.impl.codec.DataTypeCodec")
+}
+
+micronaut {
+    testResources {
+        additionalModules.add(JDBC_POSTGRESQL)
+    }
+}
+
+dependencies {
+    implementation("io.vertx:vertx-pg-client")
+    implementation('com.ongres.scram:client:2.1')
+}

+ 94 - 0
frameworks/Java/micronaut/micronaut-vertx-pg-client/src/main/java/benchmark/AbstractVertxSqlClientRepository.java

@@ -0,0 +1,94 @@
+package benchmark;
+
+import io.vertx.core.AsyncResult;
+import io.vertx.sqlclient.Pool;
+import io.vertx.sqlclient.Row;
+import io.vertx.sqlclient.RowIterator;
+import io.vertx.sqlclient.RowSet;
+import io.vertx.sqlclient.SqlClient;
+import io.vertx.sqlclient.Tuple;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+import reactor.core.publisher.Sinks;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Function;
+
+public class AbstractVertxSqlClientRepository {
+
+    protected final Pool client;
+
+    public AbstractVertxSqlClientRepository(Pool client) {
+        this.client = client;
+    }
+
+    protected Flux<Row> execute(String sql) {
+        return Flux.defer(() -> {
+            Sinks.Many<Row> sink = Sinks.many().multicast().onBackpressureBuffer();
+            client.preparedQuery(sql).execute(event -> mapResult(sink, event));
+            return sink.asFlux();
+        });
+    }
+
+    protected <T> Mono<T> executeAndCollectOne(String sql, Tuple tuple, Function<Row, T> mapper) {
+        Sinks.One<T> sink = Sinks.one();
+        client.preparedQuery(sql).execute(tuple, event -> {
+            if (event.failed()) {
+                sink.emitError(event.cause(), Sinks.EmitFailureHandler.FAIL_FAST);
+            } else  {
+                RowIterator<Row> iterator = event.result().iterator();
+                if (iterator.hasNext()) {
+                    sink.emitValue(mapper.apply(iterator.next()), Sinks.EmitFailureHandler.FAIL_FAST);
+                } else {
+                    sink.emitEmpty(Sinks.EmitFailureHandler.FAIL_FAST);
+                }
+            }
+        });
+        return sink.asMono();
+    }
+
+    protected <T> Mono<List<T>> executeAndCollectList(String sql, Function<Row, T> mapper) {
+        Sinks.One<List<T>> sink = Sinks.one();
+        client.preparedQuery(sql).execute(event -> {
+            if (event.failed()) {
+                sink.emitError(event.cause(), Sinks.EmitFailureHandler.FAIL_FAST);
+            } else {
+                List<T> list = new ArrayList<>();
+                for (Row row : event.result()) {
+                    list.add(mapper.apply(row));
+                }
+                sink.emitValue(list, Sinks.EmitFailureHandler.FAIL_FAST);
+            }
+        });
+        return sink.asMono();
+    }
+
+    protected Flux<Row> execute(SqlClient sqlClient, String sql, Tuple data) {
+        return Flux.defer(() -> {
+            Sinks.Many<Row> sink = Sinks.many().multicast().onBackpressureBuffer();
+            sqlClient.preparedQuery(sql).execute(data, event -> mapResult(sink, event));
+            return sink.asFlux();
+        });
+    }
+
+    protected Flux<Row> executeBatch(String sql, List<Tuple> data) {
+        return Flux.defer(() -> {
+            Sinks.Many<Row> sink = Sinks.many().multicast().onBackpressureBuffer();
+            client.preparedQuery(sql).executeBatch(data, event -> mapResult(sink, event));
+            return sink.asFlux();
+        });
+    }
+
+    private void mapResult(Sinks.Many<Row> sink, AsyncResult<RowSet<Row>> event) {
+        if (event.failed()) {
+            sink.emitError(event.cause(), Sinks.EmitFailureHandler.FAIL_FAST);
+        } else {
+            for (Row row : event.result()) {
+                sink.emitNext(row, Sinks.EmitFailureHandler.FAIL_FAST);
+            }
+            sink.emitComplete(Sinks.EmitFailureHandler.FAIL_FAST);
+        }
+    }
+
+}

+ 58 - 0
frameworks/Java/micronaut/micronaut-vertx-pg-client/src/main/java/benchmark/PgClientFactory.java

@@ -0,0 +1,58 @@
+/*
+ * Copyright 2017-2020 original authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package benchmark;
+
+import io.micronaut.context.annotation.Bean;
+import io.micronaut.context.annotation.Factory;
+import io.micronaut.context.annotation.Property;
+import io.vertx.core.Vertx;
+import io.vertx.core.VertxOptions;
+import io.vertx.core.impl.VertxBuilder;
+import io.vertx.pgclient.PgConnectOptions;
+import io.vertx.pgclient.PgPool;
+import io.vertx.sqlclient.PoolOptions;
+import jakarta.inject.Singleton;
+
+/**
+ * The Factory for creating Vertx PG client.
+ */
+@Factory
+public class PgClientFactory {
+
+    @Singleton
+    @Bean(preDestroy = "close")
+    public PgPool client(@Property(name = "datasources.default.url") String url,
+                         @Property(name = "datasources.default.username") String user,
+                         @Property(name = "datasources.default.password") String password,
+                         @Property(name = "datasources.default.maximum-pool-size") int maxPoolSize) {
+
+        VertxOptions vertxOptions = new VertxOptions()
+                .setPreferNativeTransport(true);
+
+        PgConnectOptions connectOptions = PgConnectOptions.fromUri(url.substring(5))
+                .setUser(user)
+                .setPassword(password)
+                .setCachePreparedStatements(true)
+                .setTcpNoDelay(true)
+                .setTcpQuickAck(true)
+                .setPipeliningLimit(1024);
+        PoolOptions poolOptions = new PoolOptions();
+        poolOptions.setMaxSize(maxPoolSize);
+
+        Vertx vertx = new VertxBuilder(vertxOptions).init().vertx();
+        return PgPool.pool(vertx, connectOptions, poolOptions);
+    }
+}

+ 37 - 0
frameworks/Java/micronaut/micronaut-vertx-pg-client/src/main/java/benchmark/VertxPgFortuneRepository.java

@@ -0,0 +1,37 @@
+package benchmark;
+
+import benchmark.model.Fortune;
+import benchmark.repository.ReactiveFortuneRepository;
+import io.vertx.sqlclient.Pool;
+import io.vertx.sqlclient.Tuple;
+import jakarta.inject.Singleton;
+import org.reactivestreams.Publisher;
+import reactor.core.publisher.Mono;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.stream.Collectors;
+
+@Singleton
+public class VertxPgFortuneRepository extends AbstractVertxSqlClientRepository implements ReactiveFortuneRepository {
+
+    public VertxPgFortuneRepository(Pool client) {
+        super(client);
+    }
+
+    private Mono<Void> createTable() {
+        return execute("DROP TABLE IF EXISTS Fortune;").then(execute("CREATE TABLE Fortune (id INTEGER NOT NULL,message VARCHAR(255) NOT NULL);").then());
+    }
+
+    @Override
+    public Publisher<Void> initDb(Collection<Fortune> fortunes) {
+        List<Tuple> data = fortunes.stream().map(fortune -> Tuple.of(fortune.getId(), fortune.getMessage())).collect(Collectors.toList());
+        return createTable().then(executeBatch("INSERT INTO Fortune VALUES ($1, $2);", data).then());
+    }
+
+    @Override
+    public Publisher<List<Fortune>> findAll() {
+        return executeAndCollectList("SELECT * FROM Fortune", row -> new Fortune(row.getInteger(0), row.getString(1)));
+    }
+
+}

+ 64 - 0
frameworks/Java/micronaut/micronaut-vertx-pg-client/src/main/java/benchmark/VertxPgWorldRepository.java

@@ -0,0 +1,64 @@
+package benchmark;
+
+import benchmark.model.World;
+import benchmark.repository.ReactiveWorldRepository;
+import io.vertx.core.Future;
+import io.vertx.sqlclient.Pool;
+import io.vertx.sqlclient.Tuple;
+import jakarta.inject.Singleton;
+import org.reactivestreams.Publisher;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.stream.Collectors;
+
+@Singleton
+public class VertxPgWorldRepository extends AbstractVertxSqlClientRepository implements ReactiveWorldRepository {
+
+    public VertxPgWorldRepository(Pool client) {
+        super(client);
+    }
+
+    private Mono<Void> createTable() {
+        return execute("DROP TABLE IF EXISTS World;").then(execute("CREATE TABLE World (id INTEGER NOT NULL,randomNumber INTEGER NOT NULL);").then());
+    }
+
+    @Override
+    public Mono<Void> initDb(Collection<World> worlds) {
+        List<Tuple> data = worlds.stream().map(world -> Tuple.of(world.getId(), world.getRandomNumber())).collect(Collectors.toList());
+        return createTable().then(executeBatch("INSERT INTO world VALUES ($1, $2);", data).then());
+    }
+
+    @Override
+    public Publisher<World> findById(Integer id) {
+        return executeAndCollectOne("SELECT * FROM world WHERE id = $1", Tuple.of(id), row -> new World(row.getInteger(0), row.getInteger(1)));
+    }
+
+    @Override
+    public Publisher<List<World>> findByIds(List<Integer> ids) {
+        return asMono(
+                client.withConnection(sqlConnection -> asFuture(
+                        Flux.fromIterable(ids)
+                                .flatMap(id -> execute(sqlConnection, "SELECT * FROM world WHERE id = $1", Tuple.of(id))
+                                        .map(row -> new World(row.getInteger(0), row.getInteger(1))))
+                                .collectList()))
+        );
+    }
+
+    private <T> Mono<T> asMono(Future<T> future) {
+        return Mono.fromFuture(future.toCompletionStage().toCompletableFuture());
+    }
+
+    private <T> Future<T> asFuture(Mono<T> mono) {
+        return Future.fromCompletionStage(mono.toFuture());
+    }
+
+    @Override
+    public Publisher<Void> updateAll(Collection<World> worlds) {
+        List<Tuple> data = worlds.stream().map(world -> Tuple.of(world.getId(), world.getRandomNumber())).collect(Collectors.toList());
+        return executeBatch("UPDATE world SET randomnumber = $2 WHERE id = $1", data).then();
+    }
+
+}

+ 5 - 0
frameworks/Java/micronaut/micronaut-vertx-pg-client/src/main/resources/application.yml

@@ -0,0 +1,5 @@
+micronaut:
+  netty:
+    event-loops:
+      default:
+        prefer-native-transport: true

+ 8 - 12
frameworks/Java/micronaut/micronaut.dockerfile

@@ -1,16 +1,12 @@
-FROM gradle:6.9-jdk11 as build
-WORKDIR /micronaut
-COPY src src
-COPY build.gradle build.gradle
-COPY settings.gradle settings.gradle
-RUN gradle build buildLayers --no-daemon
+FROM gradle:7.5.1-jdk18 as build
+COPY --chown=gradle:gradle . /home/gradle/src
+WORKDIR /home/gradle/src
+RUN gradle micronaut-vertx-pg-client:build -x test --no-daemon
 
-FROM openjdk:11-jre-slim
+FROM openjdk:19
 WORKDIR /micronaut
-COPY --from=build /micronaut/build/docker/layers/libs /home/app/libs
-COPY --from=build /micronaut/build/docker/layers/resources /home/app/resources
-COPY --from=build /micronaut/build/docker/layers/application.jar /home/app/application.jar
+COPY --from=build /home/gradle/src/micronaut-vertx-pg-client/build/libs/micronaut-vertx-pg-client-all.jar micronaut.jar
+COPY run_benchmark.sh run_benchmark.sh
 
 EXPOSE 8080
-
-CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-Dmicronaut.environments=benchmark", "-Dlog-root-level=OFF", "-jar", "/home/app/application.jar"]
+ENTRYPOINT "./run_benchmark.sh"

+ 17 - 0
frameworks/Java/micronaut/run_benchmark.sh

@@ -0,0 +1,17 @@
+#!/bin/bash
+
+JAVA_OPTIONS="-server \
+  -XX:+UseParallelGC \
+  -XX:+UseNUMA \
+  -XX:+UseStringDeduplication \
+  -XX:-StackTraceInThrowable \
+  -Dio.netty.buffer.checkBounds=false \
+  -Dio.netty.buffer.checkAccessible=false \
+  -Dvertx.disableMetrics=true \
+  -Dvertx.threadChecks=false \
+  -Dvertx.disableContextTimings=true  \
+  -Dvertx.disableTCCL=true  \
+  -Dmicronaut.environments=benchmark
+  $@"
+
+java $JAVA_OPTIONS -jar micronaut.jar

+ 10 - 1
frameworks/Java/micronaut/settings.gradle

@@ -1,2 +1,11 @@
-rootProject.name = 'hello-micronaut'
+rootProject.name = 'micronaut-benchmark'
 
+include 'common'
+include 'common-test'
+
+include 'micronaut-jdbc'
+include 'micronaut-r2dbc'
+include 'micronaut-data-jdbc'
+include 'micronaut-data-r2dbc'
+include 'micronaut-data-mongodb'
+include 'micronaut-vertx-pg-client'

+ 0 - 79
frameworks/Java/micronaut/src/main/java/benchmark/controller/EntityController.java

@@ -1,79 +0,0 @@
-package benchmark.controller;
-
-import benchmark.entity.Fortune;
-import benchmark.entity.World;
-import benchmark.repository.EntityRepository;
-import io.micronaut.http.HttpResponse;
-import io.micronaut.http.annotation.Controller;
-import io.micronaut.http.annotation.Get;
-import io.micronaut.http.annotation.QueryValue;
-import io.micronaut.views.rocker.RockerWritable;
-import io.reactivex.rxjava3.core.Flowable;
-import io.reactivex.rxjava3.core.Single;
-import views.fortunes;
-
-import java.util.Arrays;
-import java.util.List;
-import java.util.concurrent.ThreadLocalRandom;
-
-import static java.util.Comparator.comparing;
-
-@Controller("/")
-public class EntityController {
-    private final EntityRepository entityRepository;
-
-    public EntityController(EntityRepository entityRepository) {
-        this.entityRepository = entityRepository;
-    }
-
-    @Get("/db")
-    public Single<World> db() {
-        return entityRepository.getWorld(randomWorldNumber());
-    }
-
-    @Get("/queries")
-    public Single<List<World>> queries(@QueryValue String queries) {
-        final Flowable<World>[] worlds = new Flowable[parseQueryCount(queries)];
-        Arrays.setAll(worlds, i -> entityRepository.getWorld(randomWorldNumber()).toFlowable());
-
-        return Flowable.merge(Arrays.asList(worlds)).toList();
-    }
-
-    @Get(value = "/fortunes")
-    public Single<HttpResponse<RockerWritable>> fortune() {
-        return entityRepository.fortunes().toList().map(fortuneList -> {
-            fortuneList.add(new Fortune(0, "Additional fortune added at request time."));
-            fortuneList.sort(comparing(Fortune::getMessage));
-            return HttpResponse.ok(new RockerWritable(fortunes.template(fortuneList)))
-                    .contentType("text/html;charset=utf-8");
-        });
-    }
-
-    @Get("/updates")
-    public Single<List<World>> updates(@QueryValue String queries) {
-        final Flowable<World>[] worlds = new Flowable[parseQueryCount(queries)];
-
-        Arrays.setAll(worlds, i ->
-                entityRepository.findAndUpdateWorld(randomWorldNumber(), randomWorldNumber()).toFlowable()
-        );
-
-        return Flowable.merge(Arrays.asList(worlds)).toList();
-    }
-
-    private int randomWorldNumber() {
-        return 1 + ThreadLocalRandom.current().nextInt(10000);
-    }
-
-    private int parseQueryCount(String textValue) {
-        if (textValue == null) {
-            return 1;
-        }
-        int parsedValue;
-        try {
-            parsedValue = Integer.parseInt(textValue);
-        } catch (NumberFormatException e) {
-            return 1;
-        }
-        return Math.min(500, Math.max(1, parsedValue));
-    }
-}

+ 0 - 14
frameworks/Java/micronaut/src/main/java/benchmark/repository/EntityRepository.java

@@ -1,14 +0,0 @@
-package benchmark.repository;
-
-import benchmark.entity.Fortune;
-import benchmark.entity.World;
-import io.reactivex.rxjava3.core.Flowable;
-import io.reactivex.rxjava3.core.Single;
-
-public interface EntityRepository {
-    Single<World> getWorld(int id);
-
-    Single<World> findAndUpdateWorld(int id, int randomNumber);
-
-    Flowable<Fortune> fortunes();
-}

+ 0 - 69
frameworks/Java/micronaut/src/main/java/benchmark/repository/PgClientEntityRepository.java

@@ -1,69 +0,0 @@
-package benchmark.repository;
-
-import benchmark.entity.Fortune;
-import benchmark.entity.World;
-import io.reactivex.rxjava3.core.BackpressureStrategy;
-import io.reactivex.rxjava3.core.Flowable;
-import io.reactivex.rxjava3.core.Single;
-import io.vertx.reactivex.pgclient.PgPool;
-import io.vertx.reactivex.sqlclient.Row;
-import io.vertx.reactivex.sqlclient.Tuple;
-import jakarta.inject.Singleton;
-
-@Singleton
-public class PgClientEntityRepository implements EntityRepository {
-    private final PgPool pgClient;
-
-    public PgClientEntityRepository(PgPool pgClient) {
-        this.pgClient = pgClient;
-    }
-
-    @Override
-    public Single<World> getWorld(int id) {
-        return Single.create(sink ->
-                pgClient.preparedQuery("SELECT * FROM world WHERE id = $1").execute(Tuple.of(id), ar -> {
-                    if (ar.failed()) {
-                        sink.onError(ar.cause());
-                    } else {
-                        final Row row = ar.result().iterator().next();
-                        World world = new World(row.getInteger(0), row.getInteger(1));
-                        sink.onSuccess(world);
-                    }
-                }));
-    }
-
-    private Single<World> updateWorld(World world) {
-        return Single.create(sink -> pgClient.preparedQuery("UPDATE world SET randomnumber = $1 WHERE id = $2")
-                .execute(Tuple.of(world.getRandomNumber(), world.getId()), ar -> {
-                    if (ar.failed()) {
-                        sink.onError(ar.cause());
-                    } else {
-                        sink.onSuccess(world);
-                    }
-                }));
-    }
-
-    @Override
-    public Single<World> findAndUpdateWorld(int id, int randomNumber) {
-        return getWorld(id).flatMap(world -> {
-            world.setRandomNumber(randomNumber);
-            return updateWorld(world);
-        });
-    }
-
-    @Override
-    public Flowable<Fortune> fortunes() {
-        return Flowable.create(sink ->
-                pgClient.preparedQuery("SELECT * FROM fortune").execute(ar -> {
-                    if (ar.failed()) {
-                        sink.onError(ar.cause());
-                        return;
-                    }
-
-                    for (Row row : ar.result()) {
-                        sink.onNext(new Fortune(row.getInteger(0), row.getString(1)));
-                    }
-                    sink.onComplete();
-                }), BackpressureStrategy.BUFFER);
-    }
-}

+ 0 - 9
frameworks/Java/micronaut/src/main/resources/application-benchmark-local.yml

@@ -1,9 +0,0 @@
-vertx:
-  pg:
-    client:
-      port: 5432
-      host: localhost
-      database: hello_world
-      user: benchmarkdbuser
-      password: benchmarkdbpass
-      maxSize: 5

+ 0 - 9
frameworks/Java/micronaut/src/main/resources/application-benchmark.yml

@@ -1,9 +0,0 @@
-vertx:
-    pg:
-        client:
-            port: 5432
-            host: tfb-database
-            database: hello_world
-            user: benchmarkdbuser
-            password: benchmarkdbpass
-            maxSize: 5

+ 0 - 6
frameworks/Java/micronaut/src/main/resources/application.yml

@@ -1,6 +0,0 @@
-micronaut:
-    application:
-        name: benchmark
-    server:
-        port: 8080
-        serverHeader: Micronaut

+ 0 - 25
frameworks/Java/micronaut/src/main/resources/views/fortunes.rocker.html

@@ -1,25 +0,0 @@
-@import benchmark.entity.Fortune
-@import java.util.List
-
-@args (List<Fortune> fortunes)
-
-<!DOCTYPE html>
-<html>
-<head>
-    <title>Fortunes</title>
-</head>
-<body>
-<table>
-    <tr>
-        <th>id</th>
-        <th>message</th>
-    </tr>
-    @for (Fortune fortune : fortunes) {
-    <tr>
-        <td>@fortune.getId()</td>
-        <td>@fortune.getMessage()</td>
-    </tr>
-    }
-</table>
-</body>
-</html>