Merge branch '6.1.x'

This commit is contained in:
Sam Brannen 2024-06-27 11:40:16 +02:00
commit e1567b93c2
8 changed files with 47 additions and 55 deletions

View File

@ -77,7 +77,7 @@ and others) and is equivalent to `required=false`.
| For access to a part in a `multipart/form-data` request. Supports reactive types.
See xref:web/webflux/controller/ann-methods/multipart-forms.adoc[Multipart Content] and xref:web/webflux/reactive-spring.adoc#webflux-multipart[Multipart Data].
| `java.util.Map`, `org.springframework.ui.Model`, and `org.springframework.ui.ModelMap`.
| `java.util.Map` or `org.springframework.ui.Model`
| For access to the model that is used in HTML controllers and is exposed to templates as
part of view rendering.
@ -89,9 +89,9 @@ and others) and is equivalent to `required=false`.
Note that use of `@ModelAttribute` is optional -- for example, to set its attributes.
See "`Any other argument`" later in this table.
| `Errors`, `BindingResult`
| `Errors` or `BindingResult`
| For access to errors from validation and data binding for a command object, i.e. a
`@ModelAttribute` argument. An `Errors`, or `BindingResult` argument must be declared
`@ModelAttribute` argument. An `Errors` or `BindingResult` argument must be declared
immediately after the validated method argument.
| `SessionStatus` + class-level `@SessionAttributes`

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -46,7 +46,7 @@ public class ConcurrentModel extends ConcurrentHashMap<String, Object> implement
}
/**
* Construct a new {@code ModelMap} containing the supplied attribute
* Construct a new {@code ConcurrentModel} containing the supplied attribute
* under the supplied name.
* @see #addAttribute(String, Object)
*/
@ -55,8 +55,8 @@ public class ConcurrentModel extends ConcurrentHashMap<String, Object> implement
}
/**
* Construct a new {@code ModelMap} containing the supplied attribute.
* Uses attribute name generation to generate the key for the supplied model
* Construct a new {@code ConcurrentModel} containing the supplied attribute.
* <p>Uses attribute name generation to generate the key for the supplied model
* object.
* @see #addAttribute(Object)
*/

View File

@ -1,6 +1,6 @@
/**
* Generic support for UI layer concepts.
* Provides a generic ModelMap for model holding.
* <p>Provides generic {@code Model} and {@code ModelMap} holders for model attributes.
*/
@NonNullApi
@NonNullFields

View File

@ -18,11 +18,11 @@ package org.springframework.web.reactive.result.method.annotation;
import java.util.HashSet;
import java.util.Map;
import org.junit.jupiter.api.Test;
import org.springframework.beans.testfixture.beans.TestBean;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.server.WebSession;
import org.springframework.web.testfixture.server.MockWebSession;
@ -31,7 +31,8 @@ import static java.util.Arrays.asList;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Test fixture with {@link SessionAttributesHandler}.
* Tests for {@link SessionAttributesHandler}.
*
* @author Rossen Stoyanchev
*/
class SessionAttributesHandlerTests {
@ -86,11 +87,11 @@ class SessionAttributesHandlerTests {
@Test
void storeAttributes() {
ModelMap model = new ModelMap();
model.put("attr1", "value1");
model.put("attr2", "value2");
model.put("attr3", new TestBean());
Map<String, Object> model = Map.of(
"attr1", "value1",
"attr2", "value2",
"attr3", new TestBean()
);
WebSession session = new MockWebSession();
sessionAttributesHandler.storeAttributes(session, model);

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -20,7 +20,6 @@ import java.util.List;
import java.util.Map;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.ui.ModelMap;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.util.UriComponents;
import org.springframework.web.util.UriComponentsBuilder;
@ -38,7 +37,7 @@ public class DummyMacroRequestContext {
private final ServerWebExchange exchange;
private final ModelMap model;
private final Map<String, Object> model;
private final GenericApplicationContext context;
@ -46,7 +45,7 @@ public class DummyMacroRequestContext {
private String contextPath;
public DummyMacroRequestContext(ServerWebExchange exchange, ModelMap model, GenericApplicationContext context) {
public DummyMacroRequestContext(ServerWebExchange exchange, Map<String, Object> model, GenericApplicationContext context) {
this.exchange = exchange;
this.model = model;
this.context = context;

View File

@ -17,11 +17,10 @@
package org.springframework.web.reactive.result.view;
import java.time.Duration;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import org.junit.jupiter.api.Test;
import reactor.test.StepVerifier;
@ -30,8 +29,6 @@ import org.springframework.core.codec.CharSequenceEncoder;
import org.springframework.http.MediaType;
import org.springframework.http.codec.json.Jackson2JsonEncoder;
import org.springframework.http.codec.xml.Jaxb2XmlEncoder;
import org.springframework.ui.ExtendedModelMap;
import org.springframework.ui.ModelMap;
import org.springframework.web.testfixture.http.server.reactive.MockServerHttpRequest;
import org.springframework.web.testfixture.server.MockServerWebExchange;
@ -48,7 +45,7 @@ class HttpMessageWriterViewTests {
private HttpMessageWriterView view = new HttpMessageWriterView(new Jackson2JsonEncoder());
private final ModelMap model = new ExtendedModelMap();
private final Map<String, Object> model = new HashMap<>();
private final MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("/"));
@ -63,18 +60,18 @@ class HttpMessageWriterViewTests {
@Test
void singleMatch() throws Exception {
this.view.setModelKeys(Collections.singleton("foo2"));
this.model.addAttribute("foo1", Collections.singleton("bar1"));
this.model.addAttribute("foo2", Collections.singleton("bar2"));
this.model.addAttribute("foo3", Collections.singleton("bar3"));
this.view.setModelKeys(Set.of("foo2"));
this.model.put("foo1", Set.of("bar1"));
this.model.put("foo2", Set.of("bar2"));
this.model.put("foo3", Set.of("bar3"));
assertThat(doRender()).isEqualTo("[\"bar2\"]");
}
@Test
void noMatch() throws Exception {
this.view.setModelKeys(Collections.singleton("foo2"));
this.model.addAttribute("foo1", "bar1");
this.view.setModelKeys(Set.of("foo2"));
this.model.put("foo1", "bar1");
assertThat(doRender()).isEmpty();
}
@ -82,18 +79,18 @@ class HttpMessageWriterViewTests {
@Test
void noMatchBecauseNotSupported() throws Exception {
this.view = new HttpMessageWriterView(new Jaxb2XmlEncoder());
this.view.setModelKeys(new HashSet<>(Collections.singletonList("foo1")));
this.model.addAttribute("foo1", "bar1");
this.view.setModelKeys(Set.of("foo1"));
this.model.put("foo1", "bar1");
assertThat(doRender()).isEmpty();
}
@Test
void multipleMatches() throws Exception {
this.view.setModelKeys(new HashSet<>(Arrays.asList("foo1", "foo2")));
this.model.addAttribute("foo1", Collections.singleton("bar1"));
this.model.addAttribute("foo2", Collections.singleton("bar2"));
this.model.addAttribute("foo3", Collections.singleton("bar3"));
this.view.setModelKeys(Set.of("foo1", "foo2"));
this.model.put("foo1", Set.of("bar1"));
this.model.put("foo2", Set.of("bar2"));
this.model.put("foo3", Set.of("bar3"));
assertThat(doRender()).isEqualTo("{\"foo1\":[\"bar1\"],\"foo2\":[\"bar2\"]}");
}
@ -101,13 +98,13 @@ class HttpMessageWriterViewTests {
@Test
void multipleMatchesNotSupported() throws Exception {
this.view = new HttpMessageWriterView(CharSequenceEncoder.allMimeTypes());
this.view.setModelKeys(new HashSet<>(Arrays.asList("foo1", "foo2")));
this.model.addAttribute("foo1", "bar1");
this.model.addAttribute("foo2", "bar2");
this.view.setModelKeys(Set.of("foo1", "foo2"));
this.model.put("foo1", "bar1");
this.model.put("foo2", "bar2");
assertThatIllegalStateException().isThrownBy(
this::doRender)
.withMessageContaining("Map rendering is not supported");
assertThatIllegalStateException()
.isThrownBy(this::doRender)
.withMessageContaining("Map rendering is not supported");
}
@Test
@ -115,8 +112,8 @@ class HttpMessageWriterViewTests {
Map<String, String> pojoData = new LinkedHashMap<>();
pojoData.put("foo", "f");
pojoData.put("bar", "b");
this.model.addAttribute("pojoData", pojoData);
this.view.setModelKeys(Collections.singleton("pojoData"));
this.model.put("pojoData", pojoData);
this.view.setModelKeys(Set.of("pojoData"));
this.view.render(this.model, MediaType.APPLICATION_JSON, exchange).block(Duration.ZERO);

View File

@ -37,8 +37,6 @@ import org.springframework.beans.testfixture.beans.TestBean;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.io.ClassPathResource;
import org.springframework.http.MediaType;
import org.springframework.ui.ExtendedModelMap;
import org.springframework.ui.ModelMap;
import org.springframework.util.FileCopyUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.reactive.result.view.BindStatus;
@ -322,7 +320,7 @@ class FreeMarkerMacroTests {
names.put("Fred", "Fred Bloggs");
names.put("Rob&Harrop", "Rob Harrop");
ModelMap model = new ExtendedModelMap();
Map<String, Object> model = new HashMap<>();
DummyMacroRequestContext rc = new DummyMacroRequestContext(this.exchange, model,
this.applicationContext);
rc.setMessageMap(msgMap);

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -19,6 +19,7 @@ package org.springframework.web.reactive.result.view.freemarker;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.util.Locale;
import java.util.Map;
import freemarker.template.Configuration;
import org.junit.jupiter.api.BeforeEach;
@ -28,8 +29,6 @@ import reactor.test.StepVerifier;
import org.springframework.context.ApplicationContextException;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.ui.ExtendedModelMap;
import org.springframework.ui.ModelMap;
import org.springframework.web.reactive.result.view.ZeroDemandResponse;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.adapter.DefaultServerWebExchange;
@ -125,8 +124,7 @@ class FreeMarkerViewTests {
freeMarkerView.setConfiguration(this.freeMarkerConfig);
freeMarkerView.setUrl("test.ftl");
ModelMap model = new ExtendedModelMap();
model.addAttribute("hello", "hi FreeMarker");
Map<String, Object> model = Map.of("hello", "hi FreeMarker");
freeMarkerView.render(model, null, this.exchange).block(Duration.ofMillis(5000));
StepVerifier.create(this.exchange.getResponse().getBody())
@ -148,8 +146,7 @@ class FreeMarkerViewTests {
freeMarkerView.setConfiguration(this.freeMarkerConfig);
freeMarkerView.setUrl("test.ftl");
ModelMap model = new ExtendedModelMap();
model.addAttribute("hello", "hi FreeMarker");
Map<String, Object> model = Map.of("hello", "hi FreeMarker");
freeMarkerView.render(model, null, exchange).subscribe();
response.cancelWrite();