diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/result/view/FragmentsRendering.java b/spring-webflux/src/main/java/org/springframework/web/reactive/result/view/FragmentsRendering.java index 6bb25eb15b..1a7ad5bcc1 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/result/view/FragmentsRendering.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/result/view/FragmentsRendering.java @@ -32,11 +32,11 @@ import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** - * Public API for HTML rendering from a collection or from a stream of - * {@link Fragment}s each with its own view and model. For use with - * view technologies such as htmx where multiple - * page fragments may be rendered in a single response. Supported as a return - * value from a WebFlux controller method. + * Public API for HTML rendering of a collection of fragments each with a view + * and independent model. For use with frontends technologies such as + * htmx where multiple page fragments may be + * rendered in one response. Supported as a return value from Spring WebFlux + * controller methods. * *

For full page rendering with a single model and view, use {@link Rendering}. * @@ -74,8 +74,8 @@ public interface FragmentsRendering { } /** - * Create a builder and add a fragment with a view name only, also - * inheriting model attributes from the model for the request. + * Variant of {@link #with(String, Map)} with a view name only, but also + * inheriting model attributes from the shared model for the request. * @param viewName the name of the view for the fragment * @return this builder */ @@ -84,14 +84,20 @@ public interface FragmentsRendering { } /** - * Create a builder to render with a collection of Fragments. + * Variant of {@link #with(String, Map)} with a collection of fragments. + * @param fragments the fragments to add; each fragment also inherits model + * attributes from the shared model for the request + * @return the created builder */ static Builder withCollection(Collection fragments) { return new DefaultFragmentsRenderingBuilder(fragments); } /** - * Create a builder to render with a {@link Publisher} of Fragments. + * Variant of {@link #with(String, Map)} with a {@link Publisher} of fragments. + * @param fragmentsPublisher the fragments to add; each fragment also + * inherits model attributes from the shared model for the request + * @return the created builder */ static

> Builder withPublisher(P fragmentsPublisher) { return new DefaultFragmentsRenderingBuilder(fragmentsPublisher); @@ -126,7 +132,7 @@ public interface FragmentsRendering { Builder status(HttpStatusCode status); /** - * Add the given, single header value under the given name. + * Add one or more header values under the given name. * @param headerName the header name * @param headerValues the header value(s) * @return this builder @@ -151,15 +157,16 @@ public interface FragmentsRendering { Builder fragment(String viewName, Map model); /** - * Add a fragment with a view name only, inheriting model attributes from - * the model for the request. + * Variant of {@link #fragment(String, Map)} with a view name only, where + * the fragment model also inherits model attributes from the shared + * model for the request. * @param viewName the name of the view for the fragment * @return this builder */ Builder fragment(String viewName); /** - * Add a fragment. + * Variant of {@link #fragment(String, Map)} with a {@link Fragment}. * @param fragment the fragment to add * @return this builder */ diff --git a/spring-webflux/src/test/java/org/springframework/web/reactive/result/view/FragmentViewResolutionResultHandlerTests.java b/spring-webflux/src/test/java/org/springframework/web/reactive/result/view/FragmentViewResolutionResultHandlerTests.java index aa89136773..dcb3834c26 100644 --- a/spring-webflux/src/test/java/org/springframework/web/reactive/result/view/FragmentViewResolutionResultHandlerTests.java +++ b/spring-webflux/src/test/java/org/springframework/web/reactive/result/view/FragmentViewResolutionResultHandlerTests.java @@ -22,6 +22,7 @@ import java.util.Locale; import java.util.Map; import java.util.stream.Stream; +import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; @@ -54,25 +55,21 @@ import static org.springframework.web.testfixture.method.ResolvableMethod.on; */ public class FragmentViewResolutionResultHandlerTests { + private static final Fragment fragment1 = Fragment.create("fragment1", Map.of("foo", "Foo")); + + private static final Fragment fragment2 = Fragment.create("fragment2", Map.of("bar", "Bar")); + + static Stream arguments() { - Fragment f1 = Fragment.create("fragment1", Map.of("foo", "Foo")); - Fragment f2 = Fragment.create("fragment2", Map.of("bar", "Bar")); + Flux fragmentFlux = Flux.just(fragment1, fragment2).subscribeOn(Schedulers.boundedElastic()); return Stream.of( - Arguments.of( - FragmentsRendering.withPublisher(Flux.just(f1, f2).subscribeOn(Schedulers.boundedElastic())) - .headers(headers -> headers.setContentType(MediaType.TEXT_HTML)) - .build(), + Arguments.of(FragmentsRendering.withPublisher(fragmentFlux).build(), on(Handler.class).resolveReturnType(FragmentsRendering.class)), - Arguments.of( - FragmentsRendering.withCollection(List.of(f1, f2)) - .headers(headers -> headers.setContentType(MediaType.TEXT_HTML)) - .build(), + Arguments.of(FragmentsRendering.withCollection(List.of(fragment1, fragment2)).build(), on(Handler.class).resolveReturnType(FragmentsRendering.class)), - Arguments.of( - Flux.just(f1, f2).subscribeOn(Schedulers.boundedElastic()), + Arguments.of(fragmentFlux, on(Handler.class).resolveReturnType(Flux.class, Fragment.class)), - Arguments.of( - List.of(f1, f2), + Arguments.of(List.of(fragment1, fragment2), on(Handler.class).resolveReturnType(List.class, Fragment.class))); } @@ -107,14 +104,14 @@ public class FragmentViewResolutionResultHandlerTests { } - @SuppressWarnings("unused") + @SuppressWarnings({"unused", "DataFlowIssue"}) private static class Handler { - FragmentsRendering rendering() { return null; } + FragmentsRendering render() { return null; } - Flux fragmentFlux() { return null; } + Flux renderFlux() { return null; } - List fragmentList() { return null; } + List renderList() { return null; } } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/view/FragmentsRendering.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/view/FragmentsRendering.java index 743a1867d0..8c3257c800 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/view/FragmentsRendering.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/view/FragmentsRendering.java @@ -27,11 +27,11 @@ import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.SmartView; /** - * Public API for HTML rendering a collection fragments each with its own view - * and model. For use with view technologies such as + * Public API for HTML rendering of a collection of fragments each with a view + * and independent model. For use with frontends technologies such as * htmx where multiple page fragments may be - * rendered in a single response. Supported as a return value from a Spring MVC - * controller method. + * rendered in one response. Supported as a return value from Spring MVC + * controller methods. * * @author Rossen Stoyanchev * @since 6.2 @@ -51,8 +51,7 @@ public interface FragmentsRendering extends SmartView { /** - * Create a builder for {@link FragmentsRendering}, adding a fragment with - * the given view name and model. + * Create a builder and add a fragment with a view name and a model. * @param viewName the name of the view for the fragment * @param model attributes for the fragment in addition to model * attributes inherited from the shared model for the request @@ -96,7 +95,7 @@ public interface FragmentsRendering extends SmartView { Builder status(HttpStatusCode status); /** - * Add the given, single header value under the given name. + * Add one or more header values under the given name. * @param headerName the header name * @param headerValues the header value(s) * @return this builder @@ -121,15 +120,15 @@ public interface FragmentsRendering extends SmartView { Builder fragment(String viewName, Map model); /** - * Add a fragment with a view name only, inheriting model attributes from - * the model for the request. + * Variant of {@link #fragment(String, Map)} with a view name only, but + * also inheriting model attributes from the shared model for the request. * @param viewName the name of the view for the fragment * @return this builder */ Builder fragment(String viewName); /** - * Add a fragment. + * Variant of {@link #fragment(String, Map)} with a {@link ModelAndView}. * @param fragment the fragment to add; the fragment also inherits model * attributes from the shared model for the request * @return this builder @@ -137,7 +136,7 @@ public interface FragmentsRendering extends SmartView { Builder fragment(ModelAndView fragment); /** - * Add a collection of fragments. + * Variant of {@link #fragment(String, Map)} with a collection of {@link ModelAndView}s. * @param fragments the fragments to add; each fragment also inherits model * attributes from the shared model for the request * @return this builder