下面列出了怎么用org.springframework.core.ReactiveAdapter的API类实例代码及写法,或者点击链接到github查看源代码。
@Override
public boolean supports(HandlerResult result) {
if (hasModelAnnotation(result.getReturnTypeSource())) {
return true;
}
Class<?> type = result.getReturnType().toClass();
ReactiveAdapter adapter = getAdapter(result);
if (adapter != null) {
if (adapter.isNoValue()) {
return true;
}
type = result.getReturnType().getGeneric().toClass();
}
return (CharSequence.class.isAssignableFrom(type) || Rendering.class.isAssignableFrom(type) ||
Model.class.isAssignableFrom(type) || Map.class.isAssignableFrom(type) ||
void.class.equals(type) || View.class.isAssignableFrom(type) ||
!BeanUtils.isSimpleProperty(type));
}
private Mono<?> prepareAttributeMono(String attributeName, ResolvableType attributeType,
BindingContext context, ServerWebExchange exchange) {
Object attribute = context.getModel().asMap().get(attributeName);
if (attribute == null) {
attribute = findAndRemoveReactiveAttribute(context.getModel(), attributeName);
}
if (attribute == null) {
return createAttribute(attributeName, attributeType.toClass(), context, exchange);
}
ReactiveAdapter adapter = getAdapterRegistry().getAdapter(null, attribute);
if (adapter != null) {
Assert.isTrue(!adapter.isMultiValue(), "Data binding only supports single-value async types");
return Mono.from(adapter.toPublisher(attribute));
}
else {
return Mono.justOrEmpty(attribute);
}
}
@Nullable
private Object findAndRemoveReactiveAttribute(Model model, String attributeName) {
return model.asMap().entrySet().stream()
.filter(entry -> {
if (!entry.getKey().startsWith(attributeName)) {
return false;
}
ReactiveAdapter adapter = getAdapterRegistry().getAdapter(null, entry.getValue());
if (adapter == null) {
return false;
}
String name = attributeName + ClassUtils.getShortName(adapter.getReactiveType());
return entry.getKey().equals(name);
})
.findFirst()
.map(entry -> {
// Remove since we will be re-inserting the resolved attribute value
model.asMap().remove(entry.getKey());
return entry.getValue();
})
.orElse(null);
}
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 = MethodParameter.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 = parameter.getParameterAnnotation(ModelAttribute.class);
String name = (ann != null && StringUtils.hasText(ann.value()) ?
ann.value() : 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;
}
@Override
protected Object resolveNamedValue(String name, MethodParameter parameter, ServerWebExchange exchange) {
Object value = exchange.getAttribute(name);
ReactiveAdapter toAdapter = getAdapterRegistry().getAdapter(parameter.getParameterType());
if (toAdapter != null) {
if (value == null) {
Assert.isTrue(toAdapter.supportsEmpty(),
() -> "No request attribute '" + name + "' and target type " +
parameter.getGenericParameterType() + " doesn't support empty values.");
return toAdapter.fromPublisher(Mono.empty());
}
if (parameter.getParameterType().isAssignableFrom(value.getClass())) {
return value;
}
ReactiveAdapter fromAdapter = getAdapterRegistry().getAdapter(value.getClass());
Assert.isTrue(fromAdapter != null,
() -> getClass().getSimpleName() + " doesn't support " +
"reactive type wrapper: " + parameter.getGenericParameterType());
return toAdapter.fromPublisher(fromAdapter.toPublisher(value));
}
return value;
}
/**
* Evaluate the {@code Predicate} on the method parameter type but raise an
* {@code IllegalStateException} if the same matches the generic type
* within a reactive type wrapper.
*/
protected boolean checkParameterTypeNoReactiveWrapper(MethodParameter parameter, Predicate<Class<?>> predicate) {
Class<?> type = parameter.getParameterType();
ReactiveAdapter adapter = getAdapterRegistry().getAdapter(type);
if (adapter != null) {
assertHasValues(adapter, parameter);
type = parameter.nested().getNestedParameterType();
}
if (predicate.test(type)) {
if (adapter == null) {
return true;
}
throw buildReactiveWrapperException(parameter);
}
return false;
}
@Override
public boolean supports(HandlerResult result) {
if (hasModelAnnotation(result.getReturnTypeSource())) {
return true;
}
Class<?> type = result.getReturnType().toClass();
ReactiveAdapter adapter = getAdapter(result);
if (adapter != null) {
if (adapter.isNoValue()) {
return true;
}
type = result.getReturnType().getGeneric().toClass();
}
return (CharSequence.class.isAssignableFrom(type) || Rendering.class.isAssignableFrom(type) ||
Model.class.isAssignableFrom(type) || Map.class.isAssignableFrom(type) ||
void.class.equals(type) || View.class.isAssignableFrom(type) ||
!BeanUtils.isSimpleProperty(type));
}
private Mono<?> prepareAttributeMono(String attributeName, ResolvableType attributeType,
BindingContext context, ServerWebExchange exchange) {
Object attribute = context.getModel().asMap().get(attributeName);
if (attribute == null) {
attribute = findAndRemoveReactiveAttribute(context.getModel(), attributeName);
}
if (attribute == null) {
return createAttribute(attributeName, attributeType.toClass(), context, exchange);
}
ReactiveAdapter adapterFrom = getAdapterRegistry().getAdapter(null, attribute);
if (adapterFrom != null) {
Assert.isTrue(!adapterFrom.isMultiValue(), "Data binding only supports single-value async types");
return Mono.from(adapterFrom.toPublisher(attribute));
}
else {
return Mono.justOrEmpty(attribute);
}
}
@Nullable
private Object findAndRemoveReactiveAttribute(Model model, String attributeName) {
return model.asMap().entrySet().stream()
.filter(entry -> {
if (!entry.getKey().startsWith(attributeName)) {
return false;
}
ReactiveAdapter adapter = getAdapterRegistry().getAdapter(null, entry.getValue());
if (adapter == null) {
return false;
}
String name = attributeName + ClassUtils.getShortName(adapter.getReactiveType());
return entry.getKey().equals(name);
})
.findFirst()
.map(entry -> {
// Remove since we will be re-inserting the resolved attribute value
model.asMap().remove(entry.getKey());
return entry.getValue();
})
.orElse(null);
}
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 = MethodParameter.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 = parameter.getParameterAnnotation(ModelAttribute.class);
String name = (ann != null && StringUtils.hasText(ann.value()) ?
ann.value() : 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;
}
@Override
protected Object resolveNamedValue(String name, MethodParameter parameter, ServerWebExchange exchange) {
Object value = exchange.getAttribute(name);
ReactiveAdapter toAdapter = getAdapterRegistry().getAdapter(parameter.getParameterType());
if (toAdapter != null) {
if (value == null) {
Assert.isTrue(toAdapter.supportsEmpty(),
() -> "No request attribute '" + name + "' and target type " +
parameter.getGenericParameterType() + " doesn't support empty values.");
return toAdapter.fromPublisher(Mono.empty());
}
if (parameter.getParameterType().isAssignableFrom(value.getClass())) {
return value;
}
ReactiveAdapter fromAdapter = getAdapterRegistry().getAdapter(value.getClass());
Assert.isTrue(fromAdapter != null,
() -> getClass().getSimpleName() + " doesn't support " +
"reactive type wrapper: " + parameter.getGenericParameterType());
return toAdapter.fromPublisher(fromAdapter.toPublisher(value));
}
return value;
}
/**
* Evaluate the {@code Predicate} on the method parameter type but raise an
* {@code IllegalStateException} if the same matches the generic type
* within a reactive type wrapper.
*/
protected boolean checkParameterTypeNoReactiveWrapper(MethodParameter parameter, Predicate<Class<?>> predicate) {
Class<?> type = parameter.getParameterType();
ReactiveAdapter adapter = getAdapterRegistry().getAdapter(type);
if (adapter != null) {
assertHasValues(adapter, parameter);
type = parameter.nested().getNestedParameterType();
}
if (predicate.test(type)) {
if (adapter == null) {
return true;
}
throw buildReactiveWrapperException(parameter);
}
return false;
}
@SuppressWarnings("unchecked")
private Flux<DataBuffer> encodeContent(
@Nullable Object content, MethodParameter returnType, DataBufferFactory bufferFactory,
@Nullable MimeType mimeType, Map<String, Object> hints) {
ResolvableType returnValueType = ResolvableType.forMethodParameter(returnType);
ReactiveAdapter adapter = getAdapterRegistry().getAdapter(returnValueType.resolve(), content);
Publisher<?> publisher;
ResolvableType elementType;
if (adapter != null) {
publisher = adapter.toPublisher(content);
boolean isUnwrapped = KotlinDetector.isKotlinReflectPresent() &&
KotlinDetector.isKotlinType(returnType.getContainingClass()) &&
KotlinDelegate.isSuspend(returnType.getMethod()) &&
!COROUTINES_FLOW_CLASS_NAME.equals(returnValueType.toClass().getName());
ResolvableType genericType = isUnwrapped ? returnValueType : returnValueType.getGeneric();
elementType = getElementType(adapter, genericType);
}
else {
publisher = Mono.justOrEmpty(content);
elementType = (returnValueType.toClass() == Object.class && content != null ?
ResolvableType.forInstance(content) : returnValueType);
}
if (elementType.resolve() == void.class || elementType.resolve() == Void.class) {
return Flux.from(publisher).cast(DataBuffer.class);
}
Encoder<?> encoder = getEncoder(elementType, mimeType);
return Flux.from((Publisher) publisher).map(value ->
encodeValue(value, elementType, encoder, bufferFactory, mimeType, hints));
}
private ResolvableType getElementType(ReactiveAdapter adapter, ResolvableType type) {
if (adapter.isNoValue()) {
return VOID_RESOLVABLE_TYPE;
}
else if (type != ResolvableType.NONE) {
return type;
}
else {
return OBJECT_RESOLVABLE_TYPE;
}
}
private boolean isAsyncVoidReturnType(MethodParameter returnType, @Nullable ReactiveAdapter reactiveAdapter) {
if (reactiveAdapter != null && reactiveAdapter.supportsEmpty()) {
if (reactiveAdapter.isNoValue()) {
return true;
}
Type parameterType = returnType.getGenericParameterType();
if (parameterType instanceof ParameterizedType) {
ParameterizedType type = (ParameterizedType) parameterType;
if (type.getActualTypeArguments().length == 1) {
return Void.class.equals(type.getActualTypeArguments()[0]);
}
}
}
return false;
}
private Mono<Void> handleResult(HandlerResult handlerResult, BindingContext bindingContext) {
Object value = handlerResult.getReturnValue();
if (value != null) {
ResolvableType type = handlerResult.getReturnType();
ReactiveAdapter adapter = this.adapterRegistry.getAdapter(type.resolve(), value);
if (isAsyncVoidType(type, adapter)) {
return Mono.from(adapter.toPublisher(value));
}
String name = getAttributeName(handlerResult.getReturnTypeSource());
bindingContext.getModel().asMap().putIfAbsent(name, value);
}
return Mono.empty();
}
@Override
public boolean supports(HandlerResult result) {
Class<?> valueType = resolveReturnValueType(result);
if (isSupportedType(valueType)) {
return true;
}
ReactiveAdapter adapter = getAdapter(result);
return adapter != null && !adapter.isNoValue() &&
isSupportedType(result.getReturnType().getGeneric().toClass());
}
private ResolvableType getElementType(ReactiveAdapter adapter, ResolvableType genericType) {
if (adapter.isNoValue()) {
return ResolvableType.forClass(Void.class);
}
else if (genericType != ResolvableType.NONE) {
return genericType;
}
else {
return ResolvableType.forClass(Object.class);
}
}
@Override
public Mono<Object> resolveArgument(
MethodParameter parameter, BindingContext context, ServerWebExchange exchange) {
Mono<Principal> principal = exchange.getPrincipal();
ReactiveAdapter adapter = getAdapterRegistry().getAdapter(parameter.getParameterType());
return (adapter != null ? Mono.just(adapter.fromPublisher(principal)) : Mono.from(principal));
}
@Override
public Mono<Object> resolveArgument(
MethodParameter parameter, BindingContext context, ServerWebExchange exchange) {
Mono<WebSession> session = exchange.getSession();
ReactiveAdapter adapter = getAdapterRegistry().getAdapter(parameter.getParameterType());
return (adapter != null ? Mono.just(adapter.fromPublisher(session)) : Mono.from(session));
}
/**
* Evaluate the {@code Predicate} on the method parameter type or on
* the generic type within a reactive type wrapper.
*/
protected boolean checkParameterType(MethodParameter parameter, Predicate<Class<?>> predicate) {
Class<?> type = parameter.getParameterType();
ReactiveAdapter adapter = getAdapterRegistry().getAdapter(type);
if (adapter != null) {
assertHasValues(adapter, parameter);
type = parameter.nested().getNestedParameterType();
}
return predicate.test(type);
}
/**
* Evaluate the {@code Predicate} on the method parameter type if it has the
* given annotation, nesting within {@link java.util.Optional} if necessary,
* but raise an {@code IllegalStateException} if the same matches the generic
* type within a reactive type wrapper.
*/
protected <A extends Annotation> boolean checkAnnotatedParamNoReactiveWrapper(
MethodParameter parameter, Class<A> annotationType, BiPredicate<A, Class<?>> typePredicate) {
A annotation = parameter.getParameterAnnotation(annotationType);
if (annotation == null) {
return false;
}
parameter = parameter.nestedIfOptional();
Class<?> type = parameter.getNestedParameterType();
ReactiveAdapter adapter = getAdapterRegistry().getAdapter(type);
if (adapter != null) {
assertHasValues(adapter, parameter);
parameter = parameter.nested();
type = parameter.getNestedParameterType();
}
if (typePredicate.test(annotation, type)) {
if (adapter == null) {
return true;
}
throw buildReactiveWrapperException(parameter);
}
return false;
}
private static boolean isAsyncVoidReturnType(MethodParameter returnType, @Nullable ReactiveAdapter adapter) {
if (adapter != null && adapter.supportsEmpty()) {
if (adapter.isNoValue()) {
return true;
}
Type parameterType = returnType.getGenericParameterType();
if (parameterType instanceof ParameterizedType) {
ParameterizedType type = (ParameterizedType) parameterType;
if (type.getActualTypeArguments().length == 1) {
return Void.class.equals(type.getActualTypeArguments()[0]);
}
}
}
return false;
}
private Mono<Void> handleResult(HandlerResult handlerResult, BindingContext bindingContext) {
Object value = handlerResult.getReturnValue();
if (value != null) {
ResolvableType type = handlerResult.getReturnType();
ReactiveAdapter adapter = this.adapterRegistry.getAdapter(type.resolve(), value);
if (isAsyncVoidType(type, adapter)) {
return Mono.from(adapter.toPublisher(value));
}
String name = getAttributeName(handlerResult.getReturnTypeSource());
bindingContext.getModel().asMap().putIfAbsent(name, value);
}
return Mono.empty();
}
@Override
public Mono<Object> resolveArgument(
MethodParameter parameter, BindingContext context, ServerWebExchange exchange) {
Mono<WebSession> session = exchange.getSession();
ReactiveAdapter adapter = getAdapterRegistry().getAdapter(parameter.getParameterType());
return (adapter != null ? Mono.just(adapter.fromPublisher(session)) : Mono.from(session));
}
@Override
public boolean supports(HandlerResult result) {
Class<?> valueType = resolveReturnValueType(result);
if (isSupportedType(valueType)) {
return true;
}
ReactiveAdapter adapter = getAdapter(result);
return adapter != null && !adapter.isNoValue() &&
isSupportedType(result.getReturnType().getGeneric().toClass());
}
private ResolvableType getElementType(ReactiveAdapter adapter, ResolvableType genericType) {
if (adapter.isNoValue()) {
return ResolvableType.forClass(Void.class);
}
else if (genericType != ResolvableType.NONE) {
return genericType;
}
else {
return ResolvableType.forClass(Object.class);
}
}
@Override
public Mono<Object> resolveArgument(
MethodParameter parameter, BindingContext context, ServerWebExchange exchange) {
Mono<Principal> principal = exchange.getPrincipal();
ReactiveAdapter adapter = getAdapterRegistry().getAdapter(parameter.getParameterType());
return (adapter != null ? Mono.just(adapter.fromPublisher(principal)) : Mono.from(principal));
}
/**
* Evaluate the {@code Predicate} on the method parameter type or on
* the generic type within a reactive type wrapper.
*/
protected boolean checkParameterType(MethodParameter parameter, Predicate<Class<?>> predicate) {
Class<?> type = parameter.getParameterType();
ReactiveAdapter adapter = getAdapterRegistry().getAdapter(type);
if (adapter != null) {
assertHasValues(adapter, parameter);
type = parameter.nested().getNestedParameterType();
}
return predicate.test(type);
}
/**
* Evaluate the {@code Predicate} on the method parameter type if it has the
* given annotation, nesting within {@link java.util.Optional} if necessary,
* but raise an {@code IllegalStateException} if the same matches the generic
* type within a reactive type wrapper.
*/
protected <A extends Annotation> boolean checkAnnotatedParamNoReactiveWrapper(
MethodParameter parameter, Class<A> annotationType, BiPredicate<A, Class<?>> typePredicate) {
A annotation = parameter.getParameterAnnotation(annotationType);
if (annotation == null) {
return false;
}
parameter = parameter.nestedIfOptional();
Class<?> type = parameter.getNestedParameterType();
ReactiveAdapter adapter = getAdapterRegistry().getAdapter(type);
if (adapter != null) {
assertHasValues(adapter, parameter);
parameter = parameter.nested();
type = parameter.getNestedParameterType();
}
if (typePredicate.test(annotation, type)) {
if (adapter == null) {
return true;
}
throw buildReactiveWrapperException(parameter);
}
return false;
}