Browse Source

Micronaut: Use JTE template engine and GraalVM 22 (#9262)

* Micronaut: Use JTE template engine and GraalVM 22

* CR

* User Graalvm 21 for Micronaut Data
Denis Stepanov 11 months ago
parent
commit
1d0f0af629

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

@@ -28,7 +28,7 @@ dependencies {
 }
 
 graalvmNative.binaries.all {
-    buildArgs.add("--initialize-at-build-time=views")
+    buildArgs.add("--initialize-at-build-time=gg.jte.generated.precompiled")
 }
 
 test {

+ 14 - 10
frameworks/Java/micronaut/common/build.gradle

@@ -1,7 +1,7 @@
 plugins {
     id 'java'
     id "io.micronaut.library"
-    id "nu.studer.rocker" version "3.0.4"
+    id "gg.jte.gradle" version "3.1.12"
 }
 
 group 'io.micronaut.benchmark'
@@ -16,14 +16,10 @@ micronaut {
     testRuntime "junit5"
 }
 
-rocker {
-    configurations {
-        main {
-            templateDir = file('src/main/resources')
-            outputDir = file('build/generated/rocker')
-            optimize = true
-        }
-    }
+jte {
+    sourceDirectory = file("src/main/jte").toPath()
+    generate()
+    binaryStaticContent = true
 }
 
 dependencies {
@@ -38,7 +34,8 @@ dependencies {
         transitive = false
     }
 
-    implementation("com.fizzed:rocker-runtime")
+    // Switch to BOM version after https://github.com/micronaut-projects/micronaut-views/issues/876
+    implementation("gg.jte:jte-runtime:3.1.12")
 
     runtimeOnly("ch.qos.logback:logback-classic")
     runtimeOnly("org.yaml:snakeyaml")
@@ -46,4 +43,11 @@ dependencies {
 
 test {
     useJUnitPlatform()
+}
+
+// Gradle requires that generateJte is run before some tasks
+tasks.configureEach {
+    if (name == "inspectRuntimeClasspath") {
+        mustRunAfter("generateJte")
+    }
 }

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

@@ -5,6 +5,7 @@ import benchmark.model.World;
 
 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.IntStream;
@@ -12,6 +13,20 @@ import java.util.stream.IntStream;
 public class AbstractBenchmarkController {
 
     protected final Integer[] boxed = IntStream.range(1, 10001).boxed().toArray(Integer[]::new);
+    private static final Comparator<Fortune> FORTUNES_COMPARATOR = new Comparator<>() {
+        @Override
+        public int compare(Fortune o1, Fortune o2) {
+            return o1.message().compareTo(o2.message());
+        }
+    };
+
+    protected List<Fortune> prepareFortunes(List<Fortune> 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(FORTUNES_COMPARATOR);
+        return all;
+    }
 
     protected List<Fortune> createFortunes() {
         List<Integer> fortuneMessages = IntStream.range(0, 10).boxed().toList();

+ 2 - 11
frameworks/Java/micronaut/common/src/main/java/benchmark/controller/AsyncBenchmarkController.java

@@ -5,11 +5,9 @@ import benchmark.model.World;
 import benchmark.repository.AsyncFortuneRepository;
 import benchmark.repository.AsyncWorldRepository;
 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 views.fortunes;
 
 import java.util.ArrayList;
 import java.util.Comparator;
@@ -55,15 +53,8 @@ public class AsyncBenchmarkController extends AbstractBenchmarkController {
 
     // https://github.com/TechEmpower/FrameworkBenchmarks/wiki/Project-Information-Framework-Tests-Overview#fortunes
     @Get(value = "/fortunes", produces = "text/html;charset=utf-8")
-    public CompletionStage<HttpResponse<String>> fortune() {
-        return fortuneRepository.findAll().thenApply(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::message));
-            String body = fortunes.template(all).render().toString();
-            return HttpResponse.ok(body).contentType("text/html;charset=utf-8");
-        });
+    public CompletionStage<List<Fortune>> fortune() {
+        return fortuneRepository.findAll().thenApply(this::prepareFortunes);
     }
 
     // https://github.com/TechEmpower/FrameworkBenchmarks/wiki/Project-Information-Framework-Tests-Overview#database-updates

+ 3 - 14
frameworks/Java/micronaut/common/src/main/java/benchmark/controller/BenchmarkController.java

@@ -5,19 +5,14 @@ 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 views.fortunes;
 
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.Comparator;
 import java.util.List;
 
-import static java.util.Comparator.comparing;
-
 @Requires(beans = {WorldRepository.class, FortuneRepository.class})
 @Controller
 public class BenchmarkController extends AbstractBenchmarkController {
@@ -56,14 +51,8 @@ public class BenchmarkController extends AbstractBenchmarkController {
 
     // 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::message));
-        String body = fortunes.template(fortunesList).render().toString();
-        return HttpResponse.ok(body).contentType("text/html;charset=utf-8");
+    public List<Fortune> fortune() {
+        return prepareFortunes(fortuneRepository.findAll());
     }
 
     // https://github.com/TechEmpower/FrameworkBenchmarks/wiki/Project-Information-Framework-Tests-Overview#database-updates
@@ -77,5 +66,5 @@ public class BenchmarkController extends AbstractBenchmarkController {
         worldRepository.updateAll(worldList);
         return worldList;
     }
-    
+
 }

+ 54 - 0
frameworks/Java/micronaut/common/src/main/java/benchmark/controller/FortunesBodyWriter.java

@@ -0,0 +1,54 @@
+package benchmark.controller;
+
+import benchmark.model.Fortune;
+import gg.jte.TemplateOutput;
+import gg.jte.generated.precompiled.JtefortunesGenerated;
+import gg.jte.html.OwaspHtmlTemplateOutput;
+import io.micronaut.core.annotation.NonNull;
+import io.micronaut.core.type.Argument;
+import io.micronaut.core.type.MutableHeaders;
+import io.micronaut.http.MediaType;
+import io.micronaut.http.body.MessageBodyWriter;
+import io.micronaut.http.codec.CodecException;
+import io.micronaut.http.netty.NettyHttpHeaders;
+import jakarta.inject.Singleton;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+
+@Singleton
+public class FortunesBodyWriter implements MessageBodyWriter<List<Fortune>> {
+
+    @Override
+    public void writeTo(@NonNull Argument<List<Fortune>> type,
+                        @NonNull MediaType mediaType,
+                        List<Fortune> values,
+                        @NonNull MutableHeaders outgoingHeaders,
+                        @NonNull OutputStream outputStream) throws CodecException {
+        outgoingHeaders.set(NettyHttpHeaders.CONTENT_TYPE, "text/html;charset=utf-8");
+        TemplateOutput output = new TemplateOutput() {
+
+            @Override
+            public void writeContent(String value) {
+                writeBinaryContent(value.getBytes(StandardCharsets.UTF_8));
+            }
+
+            @Override
+            public void writeContent(String value, int beginIndex, int endIndex) {
+                writeBinaryContent(value.substring(beginIndex, endIndex).getBytes(StandardCharsets.UTF_8));
+            }
+
+            @Override
+            public void writeBinaryContent(byte[] value) {
+                try {
+                    outputStream.write(value);
+                } catch (IOException e) {
+                    throw new RuntimeException(e);
+                }
+            }
+        };
+        JtefortunesGenerated.render(new OwaspHtmlTemplateOutput(output), null, values);
+    }
+}

+ 2 - 13
frameworks/Java/micronaut/common/src/main/java/benchmark/controller/ReactiveBenchmarkController.java

@@ -6,21 +6,17 @@ 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.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.Comparator;
 import java.util.List;
 
-import static java.util.Comparator.comparing;
-
 @Requires(beans = {ReactiveWorldRepository.class, ReactiveFortuneRepository.class})
 @Controller
 public class ReactiveBenchmarkController extends AbstractBenchmarkController {
@@ -61,15 +57,8 @@ public class ReactiveBenchmarkController extends AbstractBenchmarkController {
     // 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::message));
-            String body = fortunes.template(all).render().toString();
-            return HttpResponse.ok(body).contentType("text/html;charset=utf-8");
-        });
+    public Mono<List<Fortune>> fortune() {
+        return Mono.from(fortuneRepository.findAll()).map(this::prepareFortunes);
     }
 
     // https://github.com/TechEmpower/FrameworkBenchmarks/wiki/Project-Information-Framework-Tests-Overview#database-updates

+ 2 - 1
frameworks/Java/micronaut/common/src/main/java/benchmark/repository/FortuneRepository.java

@@ -4,11 +4,12 @@ import benchmark.model.Fortune;
 import org.reactivestreams.Publisher;
 
 import java.util.Collection;
+import java.util.List;
 
 public interface FortuneRepository {
 
     void initDb(Collection<Fortune> fortunes);
 
-    Collection<Fortune> findAll();
+    List<Fortune> findAll();
 
 }

+ 4 - 0
frameworks/Java/micronaut/common/src/main/jte/fortunes.jte

@@ -0,0 +1,4 @@
+@param java.util.List<benchmark.model.Fortune> fortunes
+<!DOCTYPE html><html><head><title>Fortunes</title></head><body><table><tr><th>id</th><th>message</th></tr>@for(benchmark.model.Fortune fortune : fortunes)
+    <tr><td>${fortune.id()}</td><td>${fortune.message()}</td></tr>@endfor
+</table></body></html>

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

@@ -1,8 +0,0 @@
-@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.id()</td><td>@fortune.message()</td></tr>
-    }
-</table></body></html>

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

@@ -1 +1 @@
-micronautVersion=4.6.0
+micronautVersion=4.6.1

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

@@ -2,6 +2,7 @@ package benchmark;
 
 import benchmark.model.World;
 import benchmark.repository.WorldRepository;
+import io.micronaut.data.connection.annotation.Connectable;
 import io.micronaut.data.jdbc.annotation.JdbcRepository;
 import io.micronaut.data.model.query.builder.sql.Dialect;
 import io.micronaut.data.repository.GenericRepository;
@@ -20,6 +21,7 @@ public interface JdbcWorldRepository extends GenericRepository<World, Integer>,
 
     void saveAll(Collection<World> worlds);
 
+    @Connectable
     @Override
     default List<World> findByIds(List<Integer> ids) {
         return WorldRepository.super.findByIds(ids);

+ 1 - 1
frameworks/Java/micronaut/micronaut-graalvm.dockerfile

@@ -1,4 +1,4 @@
-FROM container-registry.oracle.com/graalvm/native-image:21
+FROM container-registry.oracle.com/graalvm/native-image:22
 RUN microdnf install findutils # Gradle 8.7 requires xargs
 COPY . /home/gradle/src
 WORKDIR /home/gradle/src

+ 1 - 1
frameworks/Java/micronaut/micronaut-jdbc-graalvm.dockerfile

@@ -1,4 +1,4 @@
-FROM container-registry.oracle.com/graalvm/native-image:21
+FROM container-registry.oracle.com/graalvm/native-image:22
 RUN microdnf install findutils # Gradle 8.7 requires xargs
 COPY . /home/gradle/src
 WORKDIR /home/gradle/src

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

@@ -42,7 +42,7 @@ public class JdbcFortuneRepository implements FortuneRepository {
     }
 
     @Override
-    public Collection<Fortune> findAll() {
+    public List<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)) {

+ 1 - 1
frameworks/Java/micronaut/micronaut-r2dbc-graalvm.dockerfile

@@ -1,4 +1,4 @@
-FROM container-registry.oracle.com/graalvm/native-image:21
+FROM container-registry.oracle.com/graalvm/native-image:22
 RUN microdnf install findutils # Gradle 8.7 requires xargs
 COPY . /home/gradle/src
 WORKDIR /home/gradle/src