spring ErrorsMethodArgumentResolver 源码

  • 2022-08-08
  • 浏览 (440)

spring ErrorsMethodArgumentResolver 代码

文件路径:/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/ErrorsMethodArgumentResolver.java

/*
 * Copyright 2002-2022 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.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.web.reactive.result.method.annotation;

import reactor.core.publisher.Mono;

import org.springframework.core.Conventions;
import org.springframework.core.MethodParameter;
import org.springframework.core.ReactiveAdapter;
import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.core.annotation.SynthesizingMethodParameter;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.validation.BindingResult;
import org.springframework.validation.Errors;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.reactive.BindingContext;
import org.springframework.web.reactive.result.method.HandlerMethodArgumentResolverSupport;
import org.springframework.web.server.ServerWebExchange;

/**
 * Resolve {@link Errors} or {@link BindingResult} method arguments.
 *
 * <p>An {@code Errors} argument is expected to appear immediately after the
 * model attribute in the method signature.
 *
 * @author Rossen Stoyanchev
 * @author Sam Brannen
 * @since 5.0
 */
public class ErrorsMethodArgumentResolver extends HandlerMethodArgumentResolverSupport {

	public ErrorsMethodArgumentResolver(ReactiveAdapterRegistry registry) {
		super(registry);
	}


	@Override
	public boolean supportsParameter(MethodParameter parameter) {
		return checkParameterType(parameter, Errors.class::isAssignableFrom);
	}

	@Override
	public Mono<Object> resolveArgument(
			MethodParameter parameter, BindingContext context, ServerWebExchange exchange) {

		Object errors = getErrors(parameter, context);

		// Initially ModelAttributeMethodArgumentResolver adds Errors/BindingResult as a
		// Mono in the model even if it can't be declared as such on a controller method.
		// This is done to enable early argument resolution here. When the Mono actually
		// completes it is replaced in the model with the actual value.

		if (Mono.class.isAssignableFrom(errors.getClass())) {
			return ((Mono<?>) errors).cast(Object.class);
		}
		else if (Errors.class.isAssignableFrom(errors.getClass())) {
			return Mono.just(errors);
		}
		else {
			throw new IllegalStateException("Unexpected Errors/BindingResult type: " + errors.getClass().getName());
		}
	}

	private Object getErrors(MethodParameter parameter, BindingContext context) {
		Assert.isTrue(parameter.getParameterIndex() > 0,
				"Errors argument must be declared immediately after a model attribute argument");

		int index = parameter.getParameterIndex() - 1;
		MethodParameter attributeParam = SynthesizingMethodParameter.forExecutable(parameter.getExecutable(), index);
		ReactiveAdapter adapter = getAdapterRegistry().getAdapter(attributeParam.getParameterType());

		Assert.state(adapter == null, "An @ModelAttribute and an Errors/BindingResult argument " +
				"cannot both be declared with an async type wrapper. " +
				"Either declare the @ModelAttribute without an async wrapper type or " +
				"handle a WebExchangeBindException error signal through the async type.");

		ModelAttribute ann = attributeParam.getParameterAnnotation(ModelAttribute.class);
		String name = (ann != null && StringUtils.hasText(ann.name()) ? ann.name() :
				Conventions.getVariableNameForParameter(attributeParam));
		Object errors = context.getModel().asMap().get(BindingResult.MODEL_KEY_PREFIX + name);

		Assert.state(errors != null, () -> "An Errors/BindingResult argument is expected " +
				"immediately after the @ModelAttribute argument to which it applies. " +
				"For @RequestBody and @RequestPart arguments, please declare them with a reactive " +
				"type wrapper and use its onError operators to handle WebExchangeBindException: " +
				parameter.getMethod());

		return errors;
	}

}

相关信息

spring 源码目录

相关文章

spring AbstractMessageReaderArgumentResolver 源码

spring AbstractMessageWriterResultHandler 源码

spring AbstractNamedValueArgumentResolver 源码

spring AbstractNamedValueSyncArgumentResolver 源码

spring ArgumentResolverConfigurer 源码

spring ContinuationHandlerMethodArgumentResolver 源码

spring ControllerMethodResolver 源码

spring CookieValueMethodArgumentResolver 源码

spring ExpressionValueMethodArgumentResolver 源码

spring HttpEntityMethodArgumentResolver 源码

0  赞