Search in sources :

Example 1 with WebExchangeDataBinder

use of org.springframework.web.bind.support.WebExchangeDataBinder in project spring-framework by spring-projects.

the class ViewResolutionResultHandler method addBindingResult.

private void addBindingResult(BindingContext context, ServerWebExchange exchange) {
    Map<String, Object> model = context.getModel().asMap();
    model.keySet().stream().filter(name -> isBindingCandidate(name, model.get(name))).filter(name -> !model.containsKey(BindingResult.MODEL_KEY_PREFIX + name)).forEach(name -> {
        WebExchangeDataBinder binder = context.createDataBinder(exchange, model.get(name), name);
        model.put(BindingResult.MODEL_KEY_PREFIX + name, binder.getBindingResult());
    });
}
Also used : HttpRequestPathHelper(org.springframework.web.server.support.HttpRequestPathHelper) Ordered(org.springframework.core.Ordered) RequestedContentTypeResolver(org.springframework.web.reactive.accept.RequestedContentTypeResolver) WebExchangeDataBinder(org.springframework.web.bind.support.WebExchangeDataBinder) BindingResult(org.springframework.validation.BindingResult) BindingContext(org.springframework.web.reactive.BindingContext) HandlerResultHandlerSupport(org.springframework.web.reactive.result.HandlerResultHandlerSupport) ArrayList(java.util.ArrayList) ServerWebExchange(org.springframework.web.server.ServerWebExchange) Model(org.springframework.ui.Model) ModelAttribute(org.springframework.web.bind.annotation.ModelAttribute) Locale(java.util.Locale) Map(java.util.Map) MethodParameter(org.springframework.core.MethodParameter) HandlerResultHandler(org.springframework.web.reactive.HandlerResultHandler) ResolvableType(org.springframework.core.ResolvableType) ReactiveAdapterRegistry(org.springframework.core.ReactiveAdapterRegistry) ReactiveAdapter(org.springframework.core.ReactiveAdapter) ClassUtils(org.springframework.util.ClassUtils) Collection(java.util.Collection) MediaType(org.springframework.http.MediaType) Mono(reactor.core.publisher.Mono) NotAcceptableStatusException(org.springframework.web.server.NotAcceptableStatusException) Collectors(java.util.stream.Collectors) HandlerResult(org.springframework.web.reactive.HandlerResult) Flux(reactor.core.publisher.Flux) List(java.util.List) Collections(java.util.Collections) AnnotationAwareOrderComparator(org.springframework.core.annotation.AnnotationAwareOrderComparator) BeanUtils(org.springframework.beans.BeanUtils) Assert(org.springframework.util.Assert) StringUtils(org.springframework.util.StringUtils) WebExchangeDataBinder(org.springframework.web.bind.support.WebExchangeDataBinder)

Example 2 with WebExchangeDataBinder

use of org.springframework.web.bind.support.WebExchangeDataBinder in project spring-framework by spring-projects.

the class ModelInitializerTests method basic.

@SuppressWarnings("unchecked")
@Test
public void basic() throws Exception {
    TestController controller = new TestController();
    Validator validator = mock(Validator.class);
    controller.setValidator(validator);
    List<SyncInvocableHandlerMethod> binderMethods = getBinderMethods(controller);
    List<InvocableHandlerMethod> attributeMethods = getAttributeMethods(controller);
    WebBindingInitializer bindingInitializer = new ConfigurableWebBindingInitializer();
    BindingContext bindingContext = new InitBinderBindingContext(bindingInitializer, binderMethods);
    this.modelInitializer.initModel(bindingContext, attributeMethods, this.exchange).block(Duration.ofMillis(5000));
    WebExchangeDataBinder binder = bindingContext.createDataBinder(this.exchange, "name");
    assertEquals(Collections.singletonList(validator), binder.getValidators());
    Map<String, Object> model = bindingContext.getModel().asMap();
    assertEquals(5, model.size());
    Object value = model.get("bean");
    assertEquals("Bean", ((TestBean) value).getName());
    value = model.get("monoBean");
    assertEquals("Mono Bean", ((Mono<TestBean>) value).block(Duration.ofMillis(5000)).getName());
    value = model.get("singleBean");
    assertEquals("Single Bean", ((Single<TestBean>) value).toBlocking().value().getName());
    value = model.get("voidMethodBean");
    assertEquals("Void Method Bean", ((TestBean) value).getName());
    value = model.get("voidMonoMethodBean");
    assertEquals("Void Mono Method Bean", ((TestBean) value).getName());
}
Also used : InvocableHandlerMethod(org.springframework.web.reactive.result.method.InvocableHandlerMethod) SyncInvocableHandlerMethod(org.springframework.web.reactive.result.method.SyncInvocableHandlerMethod) Mono(reactor.core.publisher.Mono) SyncInvocableHandlerMethod(org.springframework.web.reactive.result.method.SyncInvocableHandlerMethod) BindingContext(org.springframework.web.reactive.BindingContext) WebExchangeDataBinder(org.springframework.web.bind.support.WebExchangeDataBinder) ConfigurableWebBindingInitializer(org.springframework.web.bind.support.ConfigurableWebBindingInitializer) Validator(org.springframework.validation.Validator) WebBindingInitializer(org.springframework.web.bind.support.WebBindingInitializer) ConfigurableWebBindingInitializer(org.springframework.web.bind.support.ConfigurableWebBindingInitializer) Test(org.junit.Test)

Example 3 with WebExchangeDataBinder

use of org.springframework.web.bind.support.WebExchangeDataBinder in project spring-framework by spring-projects.

the class ModelAttributeMethodArgumentResolver method resolveArgument.

@Override
public Mono<Object> resolveArgument(MethodParameter parameter, BindingContext context, ServerWebExchange exchange) {
    ResolvableType type = ResolvableType.forMethodParameter(parameter);
    Class<?> resolvedType = type.resolve();
    ReactiveAdapter adapter = (resolvedType != null ? getAdapterRegistry().getAdapter(resolvedType) : null);
    ResolvableType valueType = (adapter != null ? type.getGeneric() : type);
    Assert.state(adapter == null || !adapter.isMultiValue(), () -> getClass().getSimpleName() + " does not support multi-value reactive type wrapper: " + parameter.getGenericParameterType());
    String name = ModelInitializer.getNameForParameter(parameter);
    Mono<?> valueMono = prepareAttributeMono(name, valueType, context, exchange);
    // unsafe(): we're intercepting, already serialized Publisher signals
    Sinks.One<BindingResult> bindingResultSink = Sinks.unsafe().one();
    Map<String, Object> model = context.getModel().asMap();
    model.put(BindingResult.MODEL_KEY_PREFIX + name, bindingResultSink.asMono());
    return valueMono.flatMap(value -> {
        WebExchangeDataBinder binder = context.createDataBinder(exchange, value, name);
        return (bindingDisabled(parameter) ? Mono.empty() : bindRequestParameters(binder, exchange)).doOnError(bindingResultSink::tryEmitError).doOnSuccess(aVoid -> {
            validateIfApplicable(binder, parameter);
            BindingResult bindingResult = binder.getBindingResult();
            model.put(BindingResult.MODEL_KEY_PREFIX + name, bindingResult);
            model.put(name, value);
            // Ignore result: serialized and buffered (should never fail)
            bindingResultSink.tryEmitValue(bindingResult);
        }).then(Mono.fromCallable(() -> {
            BindingResult errors = binder.getBindingResult();
            if (adapter != null) {
                return adapter.fromPublisher(errors.hasErrors() ? Mono.error(new WebExchangeBindException(parameter, errors)) : valueMono);
            } else {
                if (errors.hasErrors() && !hasErrorsArgument(parameter)) {
                    throw new WebExchangeBindException(parameter, errors);
                }
                return value;
            }
        }));
    });
}
Also used : Sinks(reactor.core.publisher.Sinks) Errors(org.springframework.validation.Errors) WebExchangeDataBinder(org.springframework.web.bind.support.WebExchangeDataBinder) BindingResult(org.springframework.validation.BindingResult) BindingContext(org.springframework.web.reactive.BindingContext) Constructor(java.lang.reflect.Constructor) ServerWebExchange(org.springframework.web.server.ServerWebExchange) HandlerMethodArgumentResolverSupport(org.springframework.web.reactive.result.method.HandlerMethodArgumentResolverSupport) Model(org.springframework.ui.Model) ModelAttribute(org.springframework.web.bind.annotation.ModelAttribute) Map(java.util.Map) MethodParameter(org.springframework.core.MethodParameter) Nullable(org.springframework.lang.Nullable) ResolvableType(org.springframework.core.ResolvableType) ReactiveAdapterRegistry(org.springframework.core.ReactiveAdapterRegistry) WebExchangeBindException(org.springframework.web.bind.support.WebExchangeBindException) ReactiveAdapter(org.springframework.core.ReactiveAdapter) ClassUtils(org.springframework.util.ClassUtils) ValidationAnnotationUtils(org.springframework.validation.annotation.ValidationAnnotationUtils) Mono(reactor.core.publisher.Mono) List(java.util.List) Annotation(java.lang.annotation.Annotation) Optional(java.util.Optional) BeanUtils(org.springframework.beans.BeanUtils) Assert(org.springframework.util.Assert) BindingResult(org.springframework.validation.BindingResult) Sinks(reactor.core.publisher.Sinks) WebExchangeDataBinder(org.springframework.web.bind.support.WebExchangeDataBinder) WebExchangeBindException(org.springframework.web.bind.support.WebExchangeBindException) ResolvableType(org.springframework.core.ResolvableType) ReactiveAdapter(org.springframework.core.ReactiveAdapter)

Example 4 with WebExchangeDataBinder

use of org.springframework.web.bind.support.WebExchangeDataBinder in project spring-framework by spring-projects.

the class ModelAttributeMethodArgumentResolver method constructAttribute.

private Mono<?> constructAttribute(Constructor<?> ctor, String attributeName, BindingContext context, ServerWebExchange exchange) {
    if (ctor.getParameterCount() == 0) {
        // A single default constructor -> clearly a standard JavaBeans arrangement.
        return Mono.just(BeanUtils.instantiateClass(ctor));
    }
    // A single data class constructor -> resolve constructor arguments from request parameters.
    WebExchangeDataBinder binder = context.createDataBinder(exchange, null, attributeName);
    return getValuesToBind(binder, exchange).map(bindValues -> {
        String[] paramNames = BeanUtils.getParameterNames(ctor);
        Class<?>[] paramTypes = ctor.getParameterTypes();
        Object[] args = new Object[paramTypes.length];
        String fieldDefaultPrefix = binder.getFieldDefaultPrefix();
        String fieldMarkerPrefix = binder.getFieldMarkerPrefix();
        for (int i = 0; i < paramNames.length; i++) {
            String paramName = paramNames[i];
            Class<?> paramType = paramTypes[i];
            Object value = bindValues.get(paramName);
            if (value == null) {
                if (fieldDefaultPrefix != null) {
                    value = bindValues.get(fieldDefaultPrefix + paramName);
                }
                if (value == null && fieldMarkerPrefix != null) {
                    if (bindValues.get(fieldMarkerPrefix + paramName) != null) {
                        value = binder.getEmptyValue(paramType);
                    }
                }
            }
            value = (value instanceof List ? ((List<?>) value).toArray() : value);
            MethodParameter methodParam = new MethodParameter(ctor, i);
            if (value == null && methodParam.isOptional()) {
                args[i] = (methodParam.getParameterType() == Optional.class ? Optional.empty() : null);
            } else {
                args[i] = binder.convertIfNecessary(value, paramTypes[i], methodParam);
            }
        }
        return BeanUtils.instantiateClass(ctor, args);
    });
}
Also used : Optional(java.util.Optional) List(java.util.List) MethodParameter(org.springframework.core.MethodParameter) WebExchangeDataBinder(org.springframework.web.bind.support.WebExchangeDataBinder)

Example 5 with WebExchangeDataBinder

use of org.springframework.web.bind.support.WebExchangeDataBinder in project spring-framework by spring-projects.

the class AbstractMessageReaderArgumentResolver method validate.

private void validate(Object target, Object[] validationHints, MethodParameter param, BindingContext binding, ServerWebExchange exchange) {
    String name = Conventions.getVariableNameForParameter(param);
    WebExchangeDataBinder binder = binding.createDataBinder(exchange, target, name);
    binder.validate(validationHints);
    if (binder.getBindingResult().hasErrors()) {
        throw new WebExchangeBindException(param, binder.getBindingResult());
    }
}
Also used : WebExchangeDataBinder(org.springframework.web.bind.support.WebExchangeDataBinder) WebExchangeBindException(org.springframework.web.bind.support.WebExchangeBindException)

Aggregations

WebExchangeDataBinder (org.springframework.web.bind.support.WebExchangeDataBinder)10 Validator (org.springframework.validation.Validator)4 BindingContext (org.springframework.web.reactive.BindingContext)4 List (java.util.List)3 Map (java.util.Map)3 Test (org.junit.jupiter.api.Test)3 MethodParameter (org.springframework.core.MethodParameter)3 ReactiveAdapterRegistry (org.springframework.core.ReactiveAdapterRegistry)3 ResolvableType (org.springframework.core.ResolvableType)3 Mono (reactor.core.publisher.Mono)3 Optional (java.util.Optional)2 BeanUtils (org.springframework.beans.BeanUtils)2 ApplicationContext (org.springframework.context.ApplicationContext)2 AnnotationConfigApplicationContext (org.springframework.context.annotation.AnnotationConfigApplicationContext)2 ReactiveAdapter (org.springframework.core.ReactiveAdapter)2 MediaType (org.springframework.http.MediaType)2 Model (org.springframework.ui.Model)2 Assert (org.springframework.util.Assert)2 ClassUtils (org.springframework.util.ClassUtils)2 BindingResult (org.springframework.validation.BindingResult)2