Support for populating model attributes through data class constructors
Includes a new overloaded ModelAndView constructor with an HttpStatus argument, as well as a HandlerMethodArgumentResolverSupport refactoring (revised checkParameterType signature, actually implementing the HandlerMethodArgumentResolver interface). Issue: SPR-15199
This commit is contained in:
@@ -56,12 +56,9 @@ import org.springframework.web.server.ServerWebExchange;
|
||||
import org.springframework.web.server.ServerWebInputException;
|
||||
import org.springframework.web.server.UnsupportedMediaTypeStatusException;
|
||||
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.springframework.core.ResolvableType.forClassWithGenerics;
|
||||
import static org.springframework.mock.http.server.reactive.test.MockServerHttpRequest.post;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.springframework.core.ResolvableType.*;
|
||||
import static org.springframework.mock.http.server.reactive.test.MockServerHttpRequest.*;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link AbstractMessageReaderArgumentResolver}.
|
||||
@@ -307,7 +304,16 @@ public class MessageReaderArgumentResolverTests {
|
||||
private AbstractMessageReaderArgumentResolver resolver(Decoder<?>... decoders) {
|
||||
List<ServerHttpMessageReader<?>> readers = new ArrayList<>();
|
||||
Arrays.asList(decoders).forEach(decoder -> readers.add(new DecoderHttpMessageReader<>(decoder)));
|
||||
return new AbstractMessageReaderArgumentResolver(readers) {};
|
||||
return new AbstractMessageReaderArgumentResolver(readers) {
|
||||
@Override
|
||||
public boolean supportsParameter(MethodParameter parameter) {
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public Mono<Object> resolveArgument(MethodParameter parameter, BindingContext bindingContext, ServerWebExchange exchange) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -42,16 +42,13 @@ import org.springframework.web.method.ResolvableMethod;
|
||||
import org.springframework.web.reactive.BindingContext;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link ModelAttributeMethodArgumentResolver}.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @author Juergen Hoeller
|
||||
*/
|
||||
public class ModelAttributeMethodArgumentResolverTests {
|
||||
|
||||
@@ -116,7 +113,6 @@ public class ModelAttributeMethodArgumentResolverTests {
|
||||
|
||||
@Test
|
||||
public void createAndBindToMono() throws Exception {
|
||||
|
||||
MethodParameter parameter = this.testMethod
|
||||
.annotNotPresent(ModelAttribute.class).arg(Mono.class, Foo.class);
|
||||
|
||||
@@ -130,7 +126,6 @@ public class ModelAttributeMethodArgumentResolverTests {
|
||||
|
||||
@Test
|
||||
public void createAndBindToSingle() throws Exception {
|
||||
|
||||
MethodParameter parameter = this.testMethod
|
||||
.annotPresent(ModelAttribute.class).arg(Single.class, Foo.class);
|
||||
|
||||
@@ -211,6 +206,7 @@ public class ModelAttributeMethodArgumentResolverTests {
|
||||
|
||||
Foo foo = valueExtractor.apply(value);
|
||||
assertEquals("Robert", foo.getName());
|
||||
assertEquals(25, foo.getAge());
|
||||
|
||||
String key = "foo";
|
||||
String bindingResultKey = BindingResult.MODEL_KEY_PREFIX + key;
|
||||
@@ -231,7 +227,6 @@ public class ModelAttributeMethodArgumentResolverTests {
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void validationErrorToMono() throws Exception {
|
||||
|
||||
MethodParameter parameter = this.testMethod
|
||||
.annotNotPresent(ModelAttribute.class).arg(Mono.class, Foo.class);
|
||||
|
||||
@@ -246,7 +241,6 @@ public class ModelAttributeMethodArgumentResolverTests {
|
||||
|
||||
@Test
|
||||
public void validationErrorToSingle() throws Exception {
|
||||
|
||||
MethodParameter parameter = this.testMethod
|
||||
.annotPresent(ModelAttribute.class).arg(Single.class, Foo.class);
|
||||
|
||||
@@ -264,7 +258,6 @@ public class ModelAttributeMethodArgumentResolverTests {
|
||||
|
||||
ServerWebExchange exchange = postForm("age=invalid");
|
||||
Mono<?> mono = createResolver().resolveArgument(param, this.bindContext, exchange);
|
||||
|
||||
mono = valueMonoExtractor.apply(mono);
|
||||
|
||||
StepVerifier.create(mono)
|
||||
@@ -277,6 +270,31 @@ public class ModelAttributeMethodArgumentResolverTests {
|
||||
.verify();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void bindDataClass() throws Exception {
|
||||
testBindBar(this.testMethod.annotNotPresent(ModelAttribute.class).arg(Bar.class));
|
||||
}
|
||||
|
||||
private void testBindBar(MethodParameter param) throws Exception {
|
||||
Object value = createResolver()
|
||||
.resolveArgument(param, this.bindContext, postForm("name=Robert&age=25&count=1"))
|
||||
.block(Duration.ZERO);
|
||||
|
||||
Bar bar = (Bar) value;
|
||||
assertEquals("Robert", bar.getName());
|
||||
assertEquals(25, bar.getAge());
|
||||
assertEquals(1, bar.getCount());
|
||||
|
||||
String key = "bar";
|
||||
String bindingResultKey = BindingResult.MODEL_KEY_PREFIX + key;
|
||||
|
||||
Map<String, Object> map = bindContext.getModel().asMap();
|
||||
assertEquals(map.toString(), 2, map.size());
|
||||
assertSame(bar, map.get(key));
|
||||
assertNotNull(map.get(bindingResultKey));
|
||||
assertTrue(map.get(bindingResultKey) instanceof BindingResult);
|
||||
}
|
||||
|
||||
|
||||
private ModelAttributeMethodArgumentResolver createResolver() {
|
||||
return new ModelAttributeMethodArgumentResolver(new ReactiveAdapterRegistry(), false);
|
||||
@@ -298,7 +316,8 @@ public class ModelAttributeMethodArgumentResolverTests {
|
||||
Foo fooNotAnnotated,
|
||||
String stringNotAnnotated,
|
||||
Mono<Foo> monoNotAnnotated,
|
||||
Mono<String> monoStringNotAnnotated) {
|
||||
Mono<String> monoStringNotAnnotated,
|
||||
Bar barNotAnnotated) {
|
||||
}
|
||||
|
||||
|
||||
@@ -333,4 +352,35 @@ public class ModelAttributeMethodArgumentResolverTests {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static class Bar {
|
||||
|
||||
private final String name;
|
||||
|
||||
private final int age;
|
||||
|
||||
private int count;
|
||||
|
||||
public Bar(String name, int age) {
|
||||
this.name = name;
|
||||
this.age = age;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public int getAge() {
|
||||
return this.age;
|
||||
}
|
||||
|
||||
public int getCount() {
|
||||
return count;
|
||||
}
|
||||
|
||||
public void setCount(int count) {
|
||||
this.count = count;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user