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}