001/* 002 * Copyright 2002-2020 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.core; 018 019import java.util.function.Supplier; 020 021import org.springframework.lang.Nullable; 022import org.springframework.util.Assert; 023 024/** 025 * Describes the semantics of a reactive type including boolean checks for 026 * {@link #isMultiValue()}, {@link #isNoValue()}, and {@link #supportsEmpty()}. 027 * 028 * @author Rossen Stoyanchev 029 * @since 5.0 030 */ 031public final class ReactiveTypeDescriptor { 032 033 private final Class<?> reactiveType; 034 035 private final boolean multiValue; 036 037 private final boolean noValue; 038 039 @Nullable 040 private final Supplier<?> emptyValueSupplier; 041 042 private final boolean deferred; 043 044 045 private ReactiveTypeDescriptor(Class<?> reactiveType, boolean multiValue, boolean noValue, 046 @Nullable Supplier<?> emptySupplier) { 047 048 this(reactiveType, multiValue, noValue, emptySupplier, true); 049 } 050 051 private ReactiveTypeDescriptor(Class<?> reactiveType, boolean multiValue, boolean noValue, 052 @Nullable Supplier<?> emptySupplier, boolean deferred) { 053 054 Assert.notNull(reactiveType, "'reactiveType' must not be null"); 055 this.reactiveType = reactiveType; 056 this.multiValue = multiValue; 057 this.noValue = noValue; 058 this.emptyValueSupplier = emptySupplier; 059 this.deferred = deferred; 060 } 061 062 063 /** 064 * Return the reactive type for this descriptor. 065 */ 066 public Class<?> getReactiveType() { 067 return this.reactiveType; 068 } 069 070 /** 071 * Return {@code true} if the reactive type can produce more than 1 value 072 * can be produced and is therefore a good fit to adapt to {@code Flux}. 073 * A {@code false} return value implies the reactive type can produce 1 074 * value at most and is therefore a good fit to adapt to {@code Mono}. 075 */ 076 public boolean isMultiValue() { 077 return this.multiValue; 078 } 079 080 /** 081 * Return {@code true} if the reactive type does not produce any values and 082 * only provides completion and error signals. 083 */ 084 public boolean isNoValue() { 085 return this.noValue; 086 } 087 088 /** 089 * Return {@code true} if the reactive type can complete with no values. 090 */ 091 public boolean supportsEmpty() { 092 return (this.emptyValueSupplier != null); 093 } 094 095 /** 096 * Return an empty-value instance for the underlying reactive or async type. 097 * Use of this type implies {@link #supportsEmpty()} is true. 098 */ 099 public Object getEmptyValue() { 100 Assert.state(this.emptyValueSupplier != null, "Empty values not supported"); 101 return this.emptyValueSupplier.get(); 102 } 103 104 /** 105 * Whether the underlying operation is deferred and needs to be started 106 * explicitly, e.g. via subscribing (or similar), or whether it is triggered 107 * without the consumer having any control. 108 * @since 5.2.7 109 */ 110 public boolean isDeferred() { 111 return this.deferred; 112 } 113 114 115 @Override 116 public boolean equals(@Nullable Object other) { 117 if (this == other) { 118 return true; 119 } 120 if (other == null || getClass() != other.getClass()) { 121 return false; 122 } 123 return this.reactiveType.equals(((ReactiveTypeDescriptor) other).reactiveType); 124 } 125 126 @Override 127 public int hashCode() { 128 return this.reactiveType.hashCode(); 129 } 130 131 132 /** 133 * Descriptor for a reactive type that can produce 0..N values. 134 * @param type the reactive type 135 * @param emptySupplier a supplier of an empty-value instance of the reactive type 136 */ 137 public static ReactiveTypeDescriptor multiValue(Class<?> type, Supplier<?> emptySupplier) { 138 return new ReactiveTypeDescriptor(type, true, false, emptySupplier); 139 } 140 141 /** 142 * Descriptor for a reactive type that can produce 0..1 values. 143 * @param type the reactive type 144 * @param emptySupplier a supplier of an empty-value instance of the reactive type 145 */ 146 public static ReactiveTypeDescriptor singleOptionalValue(Class<?> type, Supplier<?> emptySupplier) { 147 return new ReactiveTypeDescriptor(type, false, false, emptySupplier); 148 } 149 150 /** 151 * Descriptor for a reactive type that must produce 1 value to complete. 152 * @param type the reactive type 153 */ 154 public static ReactiveTypeDescriptor singleRequiredValue(Class<?> type) { 155 return new ReactiveTypeDescriptor(type, false, false, null); 156 } 157 158 /** 159 * Descriptor for a reactive type that does not produce any values. 160 * @param type the reactive type 161 * @param emptySupplier a supplier of an empty-value instance of the reactive type 162 */ 163 public static ReactiveTypeDescriptor noValue(Class<?> type, Supplier<?> emptySupplier) { 164 return new ReactiveTypeDescriptor(type, false, true, emptySupplier); 165 } 166 167 /** 168 * The same as {@link #singleOptionalValue(Class, Supplier)} but for a 169 * non-deferred, async type such as {@link java.util.concurrent.CompletableFuture}. 170 * @param type the reactive type 171 * @param emptySupplier a supplier of an empty-value instance of the reactive type 172 * @since 5.2.7 173 */ 174 public static ReactiveTypeDescriptor nonDeferredAsyncValue(Class<?> type, Supplier<?> emptySupplier) { 175 return new ReactiveTypeDescriptor(type, false, false, emptySupplier, false); 176 } 177 178}