diff --git a/framework-docs/modules/ROOT/pages/web/webflux-view.adoc b/framework-docs/modules/ROOT/pages/web/webflux-view.adoc index b37208c527..89b524bfb1 100644 --- a/framework-docs/modules/ROOT/pages/web/webflux-view.adoc +++ b/framework-docs/modules/ROOT/pages/web/webflux-view.adoc @@ -466,7 +466,7 @@ Java:: ---- @GetMapping FragmentsRendering handle() { - return FragmentsRendering.with("posts").fragment("comments").build(); + return FragmentsRendering.fragment("posts").fragment("comments").build(); } ---- @@ -476,7 +476,7 @@ Kotlin:: ---- @GetMapping fun handle(): FragmentsRendering { - return FragmentsRendering.with("posts").fragment("comments").build() + return FragmentsRendering.fragment("posts").fragment("comments").build() } ---- ====== diff --git a/framework-docs/modules/ROOT/pages/web/webmvc-view/mvc-fragments.adoc b/framework-docs/modules/ROOT/pages/web/webmvc-view/mvc-fragments.adoc index 45e4a57adc..953883659a 100644 --- a/framework-docs/modules/ROOT/pages/web/webmvc-view/mvc-fragments.adoc +++ b/framework-docs/modules/ROOT/pages/web/webmvc-view/mvc-fragments.adoc @@ -48,7 +48,7 @@ Java:: ---- @GetMapping FragmentsRendering handle() { - return FragmentsRendering.with("posts").fragment("comments").build(); + return FragmentsRendering.fragment("posts").fragment("comments").build(); } ---- @@ -58,7 +58,7 @@ Kotlin:: ---- @GetMapping fun handle(): FragmentsRendering { - return FragmentsRendering.with("posts").fragment("comments").build() + return FragmentsRendering.fragment("posts").fragment("comments").build() } ---- ====== diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/result/view/DefaultFragmentsRenderingBuilder.java b/spring-webflux/src/main/java/org/springframework/web/reactive/result/view/DefaultFragmentsRenderingBuilder.java index 5eeb4094a0..cbdb6c9dd4 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/result/view/DefaultFragmentsRenderingBuilder.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/result/view/DefaultFragmentsRenderingBuilder.java @@ -49,8 +49,8 @@ class DefaultFragmentsRenderingBuilder implements FragmentsRendering.Builder { @Nullable private HttpHeaders headers; - DefaultFragmentsRenderingBuilder(Collection fragments) { - this.fragmentsCollection = new ArrayList<>(fragments); + DefaultFragmentsRenderingBuilder() { + this.fragmentsCollection = null; this.fragmentsFlux = null; } @@ -84,22 +84,28 @@ class DefaultFragmentsRenderingBuilder implements FragmentsRendering.Builder { return this.headers; } - @Override - public FragmentsRendering.Builder fragment(String viewName, Map model) { - return fragment(Fragment.create(viewName, model)); - } - @Override public FragmentsRendering.Builder fragment(String viewName) { return fragment(Fragment.create(viewName)); } + @Override + public FragmentsRendering.Builder fragment(String viewName, Map model) { + return fragment(Fragment.create(viewName, model)); + } + @Override public FragmentsRendering.Builder fragment(Fragment fragment) { initFragmentsCollection().add(fragment); return this; } + @Override + public FragmentsRendering.Builder fragments(Collection fragments) { + initFragmentsCollection().addAll(fragments); + return this; + } + private Collection initFragmentsCollection() { if (this.fragmentsCollection == null) { this.fragmentsCollection = new ArrayList<>(); 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 29728917ac..0f821a1178 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 @@ -17,7 +17,6 @@ package org.springframework.web.reactive.result.view; import java.util.Collection; -import java.util.List; import java.util.Map; import java.util.function.Consumer; @@ -65,25 +64,27 @@ public interface FragmentsRendering { Flux fragments(); + /** + * Create a builder with one HTML fragment, also inheriting attributes from + * the shared model for the request. + * @param viewName the name of the view for the fragment + * @return this builder + * @since 6.2.1 + */ + static Builder fragment(String viewName) { + return new DefaultFragmentsRenderingBuilder().fragment(viewName); + } + /** * Create a builder with one HTML fragment. * @param viewName the view name for the fragment * @param model attributes for the fragment, in addition to attributes from the * shared model for the request * @return this builder + * @since 6.2.1 */ - static Builder with(String viewName, Map model) { - return withCollection(List.of(Fragment.create(viewName, model))); - } - - /** - * Create a builder with one HTML fragment, also inheriting attributes from - * the shared model for the request. - * @param viewName the name of the view for the fragment - * @return this builder - */ - static Builder with(String viewName) { - return withCollection(List.of(Fragment.create(viewName))); + static Builder fragment(String viewName, Map model) { + return new DefaultFragmentsRenderingBuilder().fragment(viewName, model); } /** @@ -91,9 +92,10 @@ public interface FragmentsRendering { * @param fragments the fragments to add; each fragment also inherits * attributes from the shared model for the request * @return the created builder + * @since 6.2.1 */ - static Builder withCollection(Collection fragments) { - return new DefaultFragmentsRenderingBuilder(fragments); + static Builder fragments(Collection fragments) { + return new DefaultFragmentsRenderingBuilder().fragments(fragments); } /** @@ -101,24 +103,83 @@ public interface FragmentsRendering { * @param fragmentsPublisher the fragments to add; each fragment also * inherits model attributes from the shared model for the request * @return the created builder + * @since 6.2.1 */ - static

> Builder withPublisher(P fragmentsPublisher) { + static

> Builder fragmentsPublisher(P fragmentsPublisher) { return new DefaultFragmentsRenderingBuilder(fragmentsPublisher); } /** - * Variant of {@link #withPublisher(Publisher)} that allows using any + * Variant of {@link #fragmentsPublisher(Publisher)} that allows using any * producer that can be resolved to {@link Publisher} via * {@link ReactiveAdapterRegistry}. + * @since 6.2.1 */ - static Builder withProducer(Object fragmentsProducer) { - return new DefaultFragmentsRenderingBuilder(adaptProducer(fragmentsProducer)); + static Builder fragmentsProducer(Object fragmentsProducer) { + ReactiveAdapter adapter = ReactiveAdapterRegistry.getSharedInstance().getAdapter(fragmentsProducer.getClass()); + Assert.isTrue(adapter != null, "Unknown producer " + fragmentsProducer.getClass()); + Publisher publisher = adapter.toPublisher(fragmentsProducer); + return fragmentsPublisher(publisher); } - private static Publisher adaptProducer(Object producer) { - ReactiveAdapter adapter = ReactiveAdapterRegistry.getSharedInstance().getAdapter(producer.getClass()); - Assert.isTrue(adapter != null, "Unknown producer " + producer.getClass()); - return adapter.toPublisher(producer); + /** + * Create a builder with one HTML fragment, also inheriting attributes from + * the shared model for the request. + * @param viewName the name of the view for the fragment + * @return this builder + * @deprecated in favor of {@link #fragment(String)} + */ + @Deprecated(since = "6.2.1", forRemoval = true) + static Builder with(String viewName) { + return fragment(viewName); + } + + /** + * Create a builder with one HTML fragment. + * @param viewName the view name for the fragment + * @param model attributes for the fragment, in addition to attributes from the + * shared model for the request + * @return this builder + * @deprecated in favor of {@link #fragment(String, Map)} + */ + @Deprecated(since = "6.2.1", forRemoval = true) + static Builder with(String viewName, Map model) { + return fragment(viewName, model); + } + + /** + * Create a builder with multiple HTML fragments. + * @param fragments the fragments to add; each fragment also inherits + * attributes from the shared model for the request + * @return the created builder + * @deprecated in favor of {@link #fragments(Collection)} + */ + @Deprecated(since = "6.2.1", forRemoval = true) + static Builder withCollection(Collection fragments) { + return fragments(fragments); + } + + /** + * Create a builder 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 + * @deprecated in favor of {@link #fragmentsPublisher(Publisher)} + */ + @Deprecated(since = "6.2.1", forRemoval = true) + static

> Builder withPublisher(P fragmentsPublisher) { + return fragmentsPublisher(fragmentsPublisher); + } + + /** + * Variant of {@link #fragmentsPublisher(Publisher)} that allows using any + * producer that can be resolved to {@link Publisher} via + * {@link ReactiveAdapterRegistry}. + * @deprecated in favor of {@link #fragmentsProducer(Object)} + */ + @Deprecated(since = "6.2.1", forRemoval = true) + static Builder withProducer(Object fragmentsProducer) { + return fragmentsProducer(fragmentsProducer); } @@ -169,11 +230,21 @@ public interface FragmentsRendering { /** * Add an HTML fragment. - * @param fragment the fragment to add + * @param fragment the fragment to add; the fragment also inherits + * attributes from the shared model for the request * @return this builder */ Builder fragment(Fragment fragment); + /** + * Add HTML fragments. + * @param fragments the fragments to add; each fragment also inherits + * attributes from the shared model for the request + * @return this builder + * @since 6.2.1 + */ + Builder fragments(Collection fragments); + /** * Build the {@link FragmentsRendering} instance. */ diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/result/view/ViewResolutionResultHandler.java b/spring-webflux/src/main/java/org/springframework/web/reactive/result/view/ViewResolutionResultHandler.java index 51866ba9dc..f492dabe69 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/result/view/ViewResolutionResultHandler.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/result/view/ViewResolutionResultHandler.java @@ -208,7 +208,7 @@ public class ViewResolutionResultHandler extends HandlerResultHandlerSupport imp if (adapter != null) { if (adapter.isMultiValue()) { valueMono = (result.getReturnValue() != null ? - Mono.just(FragmentsRendering.withPublisher(adapter.toPublisher(result.getReturnValue())).build()) : + Mono.just(FragmentsRendering.fragmentsPublisher(adapter.toPublisher(result.getReturnValue())).build()) : Mono.empty()); valueType = ResolvableType.forClass(FragmentsRendering.class); @@ -242,7 +242,7 @@ public class ViewResolutionResultHandler extends HandlerResultHandlerSupport imp } if (Collection.class.isAssignableFrom(clazz)) { - returnValue = FragmentsRendering.withCollection((Collection) returnValue).build(); + returnValue = FragmentsRendering.fragments((Collection) returnValue).build(); clazz = FragmentsRendering.class; } 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 40122c3f7a..09fb2b2154 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 @@ -64,9 +64,9 @@ public class FragmentViewResolutionResultHandlerTests { static Stream arguments() { Flux fragmentFlux = Flux.just(fragment1, fragment2).subscribeOn(Schedulers.boundedElastic()); return Stream.of( - Arguments.of(FragmentsRendering.withPublisher(fragmentFlux).build(), + Arguments.of(FragmentsRendering.fragmentsPublisher(fragmentFlux).build(), on(Handler.class).resolveReturnType(FragmentsRendering.class)), - Arguments.of(FragmentsRendering.withCollection(List.of(fragment1, fragment2)).build(), + Arguments.of(FragmentsRendering.fragments(List.of(fragment1, fragment2)).build(), on(Handler.class).resolveReturnType(FragmentsRendering.class)), Arguments.of(fragmentFlux, on(Handler.class).resolveReturnType(Flux.class, Fragment.class)), diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ModelAndViewMethodReturnValueHandler.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ModelAndViewMethodReturnValueHandler.java index 11dfd8fcdd..9d2b199040 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ModelAndViewMethodReturnValueHandler.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ModelAndViewMethodReturnValueHandler.java @@ -92,7 +92,7 @@ public class ModelAndViewMethodReturnValueHandler implements HandlerMethodReturn } if (returnValue instanceof Collection mavs) { - returnValue = FragmentsRendering.with((Collection) mavs).build(); + returnValue = FragmentsRendering.fragments((Collection) mavs).build(); } if (returnValue instanceof FragmentsRendering rendering) { diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ResponseBodyEmitterReturnValueHandler.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ResponseBodyEmitterReturnValueHandler.java index 288f644ae9..92a571ac44 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ResponseBodyEmitterReturnValueHandler.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ResponseBodyEmitterReturnValueHandler.java @@ -393,7 +393,7 @@ public class ResponseBodyEmitterReturnValueHandler implements HandlerMethodRetur FragmentHttpServletResponse fragmentResponse = new FragmentHttpServletResponse(this.response, this.charset); - FragmentsRendering render = FragmentsRendering.with(List.of(modelAndView)).build(); + FragmentsRendering render = FragmentsRendering.fragments(List.of(modelAndView)).build(); render.resolveNestedViews(this::resolveViewName, this.locale); render.render(modelAndView.getModel(), this.request, fragmentResponse); 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 739c20ee84..8c0a4bc38c 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 @@ -54,37 +54,77 @@ public interface FragmentsRendering extends SmartView { HttpHeaders headers(); + /** + * Create a builder with one HTML fragment, also inheriting attributes from + * the shared model for the request. + * @param viewName the name of the view for the fragment + * @return the created builder + * @since 6.2.1 + */ + static Builder fragment(String viewName) { + return new DefaultFragmentsRenderingBuilder().fragment(viewName); + } + /** * Create a builder with one HTML fragment. * @param viewName the view name for the fragment * @param model attributes for the fragment, in addition to attributes from the * shared model for the request * @return the created builder + * @since 6.2.1 */ - static Builder with(String viewName, Map model) { + static Builder fragment(String viewName, Map model) { return new DefaultFragmentsRenderingBuilder().fragment(viewName, model); } - /** - * Create a builder with one HTML fragment, also inheriting attributes from - * the shared model for the request. - * @param viewName the name of the view for the fragment - * @return the created builder - */ - static Builder with(String viewName) { - return new DefaultFragmentsRenderingBuilder().fragment(viewName); - } - /** * Create a builder with multiple HTML fragments. * @param fragments the fragments to add; each fragment also inherits * attributes from the shared model for the request * @return the created builder + * @since 6.2.1 */ - static Builder with(Collection fragments) { + static Builder fragments(Collection fragments) { return new DefaultFragmentsRenderingBuilder().fragments(fragments); } + /** + * Create a builder with one HTML fragment, also inheriting attributes from + * the shared model for the request. + * @param viewName the name of the view for the fragment + * @return the created builder + * @deprecated in favor of {@link #fragment(String)} + */ + @Deprecated(since = "6.2.1", forRemoval = true) + static Builder with(String viewName) { + return fragment(viewName); + } + + /** + * Create a builder with one HTML fragment. + * @param viewName the view name for the fragment + * @param model attributes for the fragment, in addition to attributes from the + * shared model for the request + * @return the created builder + * @deprecated in favor of {@link #fragment(String, Map)} + */ + @Deprecated(since = "6.2.1", forRemoval = true) + static Builder with(String viewName, Map model) { + return fragment(viewName, model); + } + + /** + * Create a builder with multiple HTML fragments. + * @param fragments the fragments to add; each fragment also inherits + * attributes from the shared model for the request + * @return the created builder + * @deprecated in favor of {@link #fragments(Collection)} + */ + @Deprecated(since = "6.2.1", forRemoval = true) + static Builder with(Collection fragments) { + return fragments(fragments); + } + /** * Defines a builder for {@link FragmentsRendering}. diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ModelAndViewMethodReturnValueHandlerTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ModelAndViewMethodReturnValueHandlerTests.java index d48b682cc7..56e47c7478 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ModelAndViewMethodReturnValueHandlerTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ModelAndViewMethodReturnValueHandlerTests.java @@ -91,7 +91,7 @@ class ModelAndViewMethodReturnValueHandlerTests { @Test void handleFragmentsRendering() throws Exception { - FragmentsRendering rendering = FragmentsRendering.with("viewName").build(); + FragmentsRendering rendering = FragmentsRendering.fragment("viewName").build(); handler.handleReturnValue(rendering, returnParamModelAndView, mavContainer, webRequest); assertThat(mavContainer.getView()).isInstanceOf(SmartView.class); diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/view/DefaultFragmentsRenderingTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/view/DefaultFragmentsRenderingTests.java index 0031ddb84c..160012b6aa 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/view/DefaultFragmentsRenderingTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/view/DefaultFragmentsRenderingTests.java @@ -56,7 +56,8 @@ public class DefaultFragmentsRenderingTests { MockHttpServletRequest request = new MockHttpServletRequest(); MockHttpServletResponse response = new MockHttpServletResponse(); - FragmentsRendering view = FragmentsRendering.with("fragment1", Map.of("foo", "Foo")) + FragmentsRendering view = FragmentsRendering + .fragment("fragment1", Map.of("foo", "Foo")) .fragment("fragment2", Map.of("bar", "Bar")) .header("headerName", "headerValue") .build();