From 7a48c1a6e825353c7f4f34a27e3039041cbe395f Mon Sep 17 00:00:00 2001 From: Sergio del Amo Date: Fri, 19 Apr 2024 18:18:24 +0200 Subject: [PATCH 1/3] fix: turbo stream processing should use decoration (#778) --- .../io/micronaut/views/ModelAndViewTest.java | 39 ++++++++++--------- .../turbo/DefaultTurboStreamRenderer.java | 36 +++++++++++++++-- .../TurboStreamBuilderMessageBodyWriter.java | 3 +- ...oStreamListOfBuilderMessageBodyWriter.java | 3 +- 4 files changed, 58 insertions(+), 23 deletions(-) diff --git a/test-suite/src/test/java/io/micronaut/views/ModelAndViewTest.java b/test-suite/src/test/java/io/micronaut/views/ModelAndViewTest.java index 46a931304..2b75c708d 100644 --- a/test-suite/src/test/java/io/micronaut/views/ModelAndViewTest.java +++ b/test-suite/src/test/java/io/micronaut/views/ModelAndViewTest.java @@ -1,18 +1,3 @@ -/* - * Copyright 2017-2021 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 - * - * http://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 io.micronaut.views; import io.micronaut.context.BeanContext; @@ -26,23 +11,28 @@ import io.micronaut.http.HttpStatus; import io.micronaut.http.annotation.Controller; import io.micronaut.http.annotation.Get; +import io.micronaut.http.annotation.Produces; import io.micronaut.http.client.BlockingHttpClient; import io.micronaut.http.client.HttpClient; import io.micronaut.http.client.annotation.Client; import io.micronaut.http.client.exceptions.HttpClientResponseException; import io.micronaut.runtime.ApplicationConfiguration; import io.micronaut.test.extensions.junit5.annotation.MicronautTest; -import io.micronaut.views.ModelAndView; -import io.micronaut.views.View; import io.micronaut.views.model.ConfigViewModelProcessor; import io.micronaut.views.model.FruitsController; import io.micronaut.views.model.ViewModelProcessor; +import io.micronaut.views.turbo.TurboStream; +import io.micronaut.views.turbo.TurboStreamAction; +import io.micronaut.views.turbo.http.TurboMediaType; import jakarta.inject.Inject; import jakarta.inject.Singleton; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.function.Executable; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; @Property(name = "spec.name", value = "ModelAndViewSpec") @Property(name = "micronaut.views.soy.enabled", value = StringUtils.FALSE) @@ -180,6 +170,11 @@ void viewModelProcessorsWorkWithControllersReturningPOJOs() { //and: assertTrue(html.contains("

config: test

")); + + //when: + request = HttpRequest.GET("/turboStreamBuilderWithProcessor").accept(TurboMediaType.TURBO_STREAM); + html = client.retrieve(request, String.class); + assertTrue(html.contains("

config: test

")); } @Requires(property = "spec.name", value = "ModelAndViewSpec") @@ -190,6 +185,14 @@ static class ViewModelProcessorController { public Fruit pojoProcessor() { return new Fruit("orange", "orange"); } + + @Produces(TurboMediaType.TURBO_STREAM) + @Get("/turboStreamBuilderWithProcessor") + public TurboStream.Builder turboStreamBuilder() { + return TurboStream.builder() + .action(TurboStreamAction.REPLACE) + .template("fruits-processor", new Fruit("orange", "orange")); + } } @Introspected diff --git a/views-core/src/main/java/io/micronaut/views/turbo/DefaultTurboStreamRenderer.java b/views-core/src/main/java/io/micronaut/views/turbo/DefaultTurboStreamRenderer.java index 34ad8d943..d2dc02a41 100644 --- a/views-core/src/main/java/io/micronaut/views/turbo/DefaultTurboStreamRenderer.java +++ b/views-core/src/main/java/io/micronaut/views/turbo/DefaultTurboStreamRenderer.java @@ -16,12 +16,16 @@ package io.micronaut.views.turbo; import io.micronaut.context.annotation.Requires; +import io.micronaut.core.annotation.NextMajorVersion; import io.micronaut.core.annotation.NonNull; import io.micronaut.core.annotation.Nullable; import io.micronaut.core.io.Writable; import io.micronaut.http.HttpRequest; +import io.micronaut.views.ModelAndView; +import io.micronaut.views.ViewsModelDecorator; import io.micronaut.views.ViewsRendererLocator; import io.micronaut.views.turbo.http.TurboMediaType; +import jakarta.inject.Inject; import jakarta.inject.Singleton; import java.util.Optional; @@ -36,9 +40,30 @@ public class DefaultTurboStreamRenderer implements TurboStreamRenderer { protected final ViewsRendererLocator viewsRendererLocator; + @Nullable + @NextMajorVersion("remove the nullability annotation") + private final ViewsModelDecorator viewsModelDecorator; - public DefaultTurboStreamRenderer(ViewsRendererLocator viewsRendererLocator) { + /** + * + * @param viewsRendererLocator ViewRendererLocator + * @param viewsModelDecorator Views Model Decorator + */ + @Inject + public DefaultTurboStreamRenderer(ViewsRendererLocator viewsRendererLocator, + ViewsModelDecorator viewsModelDecorator) { this.viewsRendererLocator = viewsRendererLocator; + this.viewsModelDecorator = viewsModelDecorator; + } + + /** + * + * @param viewsRendererLocator View Renderer Locator + * @deprecated Use {@link #DefaultTurboStreamRenderer(ViewsRendererLocator, ViewsModelDecorator)} instead. + */ + @Deprecated(since = "5.2.1", forRemoval = true) + public DefaultTurboStreamRenderer(ViewsRendererLocator viewsRendererLocator) { + this(viewsRendererLocator, null); } @Override @@ -48,8 +73,13 @@ public Optional render(@NonNull TurboStream.Builder builder, return builder.getTemplateView() .map(viewName -> { Object model = builder.getTemplateModel().orElse(null); - return viewsRendererLocator.resolveViewsRenderer(viewName, TurboMediaType.TURBO_STREAM, model) - .flatMap(renderer -> builder.template(renderer.render(viewName, model, request)) + ModelAndView modelAndView = new ModelAndView<>(viewName, model); + if (request != null && viewsModelDecorator != null) { + viewsModelDecorator.decorate(request, modelAndView); + } + Object decoratedModel = modelAndView.getModel().orElse(null); + return viewsRendererLocator.resolveViewsRenderer(viewName, TurboMediaType.TURBO_STREAM, decoratedModel) + .flatMap(renderer -> builder.template(renderer.render(viewName, decoratedModel, request)) .build() .render()); }) diff --git a/views-core/src/main/java/io/micronaut/views/turbo/TurboStreamBuilderMessageBodyWriter.java b/views-core/src/main/java/io/micronaut/views/turbo/TurboStreamBuilderMessageBodyWriter.java index 8aa47a945..ff70c27ea 100644 --- a/views-core/src/main/java/io/micronaut/views/turbo/TurboStreamBuilderMessageBodyWriter.java +++ b/views-core/src/main/java/io/micronaut/views/turbo/TurboStreamBuilderMessageBodyWriter.java @@ -23,6 +23,7 @@ import io.micronaut.http.annotation.Produces; import io.micronaut.http.body.MessageBodyWriter; import io.micronaut.http.codec.CodecException; +import io.micronaut.http.context.ServerRequestContext; import io.micronaut.views.exceptions.ViewRenderingException; import io.micronaut.views.turbo.http.TurboMediaType; import jakarta.inject.Singleton; @@ -54,7 +55,7 @@ public void writeTo(@NonNull Argument type, @NonNull MutableHeaders outgoingHeaders, @NonNull OutputStream outputStream) throws CodecException { outgoingHeaders.set(HttpHeaders.CONTENT_TYPE, TurboMediaType.TURBO_STREAM); - turboStreamRenderer.render(turboStreamBuilder, null) + turboStreamRenderer.render(turboStreamBuilder, ServerRequestContext.currentRequest().orElse(null)) .ifPresent(writable -> { try { writable.writeTo(outputStream); diff --git a/views-core/src/main/java/io/micronaut/views/turbo/TurboStreamListOfBuilderMessageBodyWriter.java b/views-core/src/main/java/io/micronaut/views/turbo/TurboStreamListOfBuilderMessageBodyWriter.java index 4503f3af9..6cbc28da3 100644 --- a/views-core/src/main/java/io/micronaut/views/turbo/TurboStreamListOfBuilderMessageBodyWriter.java +++ b/views-core/src/main/java/io/micronaut/views/turbo/TurboStreamListOfBuilderMessageBodyWriter.java @@ -23,6 +23,7 @@ import io.micronaut.http.annotation.Produces; import io.micronaut.http.body.MessageBodyWriter; import io.micronaut.http.codec.CodecException; +import io.micronaut.http.context.ServerRequestContext; import io.micronaut.views.exceptions.ViewRenderingException; import io.micronaut.views.turbo.http.TurboMediaType; import jakarta.inject.Singleton; @@ -56,7 +57,7 @@ public void writeTo(@NonNull Argument> type, @NonNull OutputStream outputStream) throws CodecException { outgoingHeaders.set(HttpHeaders.CONTENT_TYPE, TurboMediaType.TURBO_STREAM); for (TurboStream.Builder builder : turboStreamBuilders) { - turboStreamRenderer.render(builder, null) + turboStreamRenderer.render(builder, ServerRequestContext.currentRequest().orElse(null)) .ifPresent(writable -> { try { writable.writeTo(outputStream); From 551b64a4918de8c2b99f6c4edb6879242554551e Mon Sep 17 00:00:00 2001 From: micronaut-build Date: Fri, 19 Apr 2024 16:19:41 +0000 Subject: [PATCH 2/3] [skip ci] Release v5.2.1 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 1f378d269..4525e2596 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -projectVersion=5.2.1-SNAPSHOT +projectVersion=5.2.1 projectGroup=io.micronaut.views title=Micronaut Views From 60073f63bbb12f242ce7181baa0f12ef1048a96a Mon Sep 17 00:00:00 2001 From: micronaut-build Date: Fri, 19 Apr 2024 16:25:51 +0000 Subject: [PATCH 3/3] chore: Bump version to 5.2.2-SNAPSHOT --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 4525e2596..195d05c3a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -projectVersion=5.2.1 +projectVersion=5.2.2-SNAPSHOT projectGroup=io.micronaut.views title=Micronaut Views