001/* 002 * Copyright 2002-2017 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.web.reactive; 018 019import java.util.function.Function; 020 021import reactor.core.publisher.Mono; 022 023import org.springframework.core.MethodParameter; 024import org.springframework.core.ResolvableType; 025import org.springframework.lang.Nullable; 026import org.springframework.ui.Model; 027import org.springframework.util.Assert; 028 029/** 030 * Represent the result of the invocation of a handler or a handler method. 031 * 032 * @author Rossen Stoyanchev 033 * @since 5.0 034 */ 035public class HandlerResult { 036 037 private final Object handler; 038 039 @Nullable 040 private final Object returnValue; 041 042 private final ResolvableType returnType; 043 044 private final BindingContext bindingContext; 045 046 @Nullable 047 private Function<Throwable, Mono<HandlerResult>> exceptionHandler; 048 049 050 /** 051 * Create a new {@code HandlerResult}. 052 * @param handler the handler that handled the request 053 * @param returnValue the return value from the handler possibly {@code null} 054 * @param returnType the return value type 055 */ 056 public HandlerResult(Object handler, @Nullable Object returnValue, MethodParameter returnType) { 057 this(handler, returnValue, returnType, null); 058 } 059 060 /** 061 * Create a new {@code HandlerResult}. 062 * @param handler the handler that handled the request 063 * @param returnValue the return value from the handler possibly {@code null} 064 * @param returnType the return value type 065 * @param context the binding context used for request handling 066 */ 067 public HandlerResult(Object handler, @Nullable Object returnValue, MethodParameter returnType, 068 @Nullable BindingContext context) { 069 070 Assert.notNull(handler, "'handler' is required"); 071 Assert.notNull(returnType, "'returnType' is required"); 072 this.handler = handler; 073 this.returnValue = returnValue; 074 this.returnType = ResolvableType.forMethodParameter(returnType); 075 this.bindingContext = (context != null ? context : new BindingContext()); 076 } 077 078 079 /** 080 * Return the handler that handled the request. 081 */ 082 public Object getHandler() { 083 return this.handler; 084 } 085 086 /** 087 * Return the value returned from the handler, if any. 088 */ 089 @Nullable 090 public Object getReturnValue() { 091 return this.returnValue; 092 } 093 094 /** 095 * Return the type of the value returned from the handler -- e.g. the return 096 * type declared on a controller method's signature. Also see 097 * {@link #getReturnTypeSource()} to obtain the underlying 098 * {@link MethodParameter} for the return type. 099 */ 100 public ResolvableType getReturnType() { 101 return this.returnType; 102 } 103 104 /** 105 * Return the {@link MethodParameter} from which {@link #getReturnType() 106 * returnType} was created. 107 */ 108 public MethodParameter getReturnTypeSource() { 109 return (MethodParameter) this.returnType.getSource(); 110 } 111 112 /** 113 * Return the BindingContext used for request handling. 114 */ 115 public BindingContext getBindingContext() { 116 return this.bindingContext; 117 } 118 119 /** 120 * Return the model used for request handling. This is a shortcut for 121 * {@code getBindingContext().getModel()}. 122 */ 123 public Model getModel() { 124 return this.bindingContext.getModel(); 125 } 126 127 /** 128 * Configure an exception handler that may be used to produce an alternative 129 * result when result handling fails. Especially for an async return value 130 * errors may occur after the invocation of the handler. 131 * @param function the error handler 132 * @return the current instance 133 */ 134 public HandlerResult setExceptionHandler(Function<Throwable, Mono<HandlerResult>> function) { 135 this.exceptionHandler = function; 136 return this; 137 } 138 139 /** 140 * Whether there is an exception handler. 141 */ 142 public boolean hasExceptionHandler() { 143 return (this.exceptionHandler != null); 144 } 145 146 /** 147 * Apply the exception handler and return the alternative result. 148 * @param failure the exception 149 * @return the new result or the same error if there is no exception handler 150 */ 151 public Mono<HandlerResult> applyExceptionHandler(Throwable failure) { 152 return (this.exceptionHandler != null ? this.exceptionHandler.apply(failure) : Mono.error(failure)); 153 } 154 155}