001// *************************************************************************************************************************** 002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * 003// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * 004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * 005// * with the License. You may obtain a copy of the License at * 006// * * 007// * http://www.apache.org/licenses/LICENSE-2.0 * 008// * * 009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * 010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * 011// * specific language governing permissions and limitations under the License. * 012// *************************************************************************************************************************** 013package org.apache.juneau; 014 015import java.lang.reflect.*; 016import java.util.*; 017import java.util.function.*; 018 019import org.apache.juneau.reflect.*; 020 021/** 022 * Represents a simple settable value. 023 * 024 * <p> 025 * Similar to an {@link Optional} but mutable. 026 * 027 * <h5 class='section'>Notes:</h5><ul> 028 * <li class='warn'>This class is not thread safe. 029 * </ul> 030 * 031 * <h5 class='section'>See Also:</h5><ul> 032 * </ul> 033 * 034 * @param <T> The value type. 035 */ 036public class Value<T> { 037 038 //----------------------------------------------------------------------------------------------------------------- 039 // Static 040 //----------------------------------------------------------------------------------------------------------------- 041 042 /** 043 * Static creator. 044 * 045 * @param <T> The value type. 046 * @param object The object being wrapped. 047 * @return A new {@link Value} object. 048 */ 049 public static <T> Value<T> of(T object) { 050 return new Value<>(object); 051 } 052 053 /** 054 * Static creator. 055 * 056 * @param <T> The value type. 057 * @return An empty {@link Value} object. 058 */ 059 public static <T> Value<T> empty() { 060 return new Value<>(null); 061 } 062 063 /** 064 * Returns the generic parameter type of the Value type. 065 * 066 * @param t The type to find the parameter type of. 067 * @return The parameter type of the value, or <jk>null</jk> if the type is not a subclass of <c>Value</c>. 068 */ 069 public static Type getParameterType(Type t) { 070 if (t instanceof ParameterizedType) { 071 ParameterizedType pt = (ParameterizedType)t; 072 if (pt.getRawType() == Value.class) { 073 Type[] ta = pt.getActualTypeArguments(); 074 if (ta.length > 0) 075 return ta[0]; 076 } 077 } else if (t instanceof Class) { 078 Class<?> c = (Class<?>)t; 079 if (Value.class.isAssignableFrom(c)) { 080 return ClassInfo.of(c).getParameterType(0, Value.class); 081 } 082 } 083 084 return null; 085 } 086 087 /** 088 * Returns the unwrapped type. 089 * 090 * @param t The type to unwrap. 091 * @return The unwrapped type, or the same type if the type isn't {@link Value}. 092 */ 093 public static Type unwrap(Type t) { 094 Type x = getParameterType(t); 095 return x != null ? x : t; 096 } 097 098 /** 099 * Convenience method for checking if the specified type is this class. 100 * 101 * @param t The type to check. 102 * @return <jk>true</jk> if the specified type is this class. 103 */ 104 public static boolean isType(Type t) { 105 return 106 (t instanceof ParameterizedType && ((ParameterizedType)t).getRawType() == Value.class) 107 || (t instanceof Class && Value.class.isAssignableFrom((Class<?>)t)); 108 } 109 110 //----------------------------------------------------------------------------------------------------------------- 111 // Implementation 112 //----------------------------------------------------------------------------------------------------------------- 113 114 115 private T t; 116 private ValueListener<T> listener; 117 118 /** 119 * Constructor. 120 */ 121 public Value() {} 122 123 /** 124 * Constructor. 125 * 126 * @param t Initial value. 127 */ 128 public Value(T t) { 129 set(t); 130 } 131 132 /** 133 * Adds a listener for this value. 134 * 135 * @param listener The new listener for this value. 136 * @return This object. 137 */ 138 public Value<T> listener(ValueListener<T> listener) { 139 this.listener = listener; 140 return this; 141 } 142 143 /** 144 * Sets the value. 145 * 146 * @param t The new value. 147 * @return This object. 148 */ 149 public Value<T> set(T t) { 150 this.t = t; 151 if (listener != null) 152 listener.onSet(t); 153 return this; 154 } 155 156 /** 157 * Sets the value if it's not already set. 158 * 159 * @param t The new value. 160 * @return This object. 161 */ 162 public Value<T> setIfEmpty(T t) { 163 if (isEmpty()) 164 set(t); 165 return this; 166 } 167 168 /** 169 * Returns the value. 170 * 171 * @return The value, or <jk>null</jk> if it is not set. 172 */ 173 public T get() { 174 return t; 175 } 176 177 /** 178 * Returns the value and then unsets it. 179 * 180 * @return The value before it was unset. 181 */ 182 public T getAndUnset() { 183 T t2 = t; 184 t = null; 185 return t2; 186 } 187 188 /** 189 * Returns <jk>true</jk> if the value is set. 190 * 191 * @return <jk>true</jk> if the value is set. 192 */ 193 public boolean isPresent() { 194 return get() != null; 195 } 196 197 /** 198 * If a value is present, invoke the specified consumer with the value, otherwise do nothing. 199 * 200 * @param consumer Block to be executed if a value is present. 201 */ 202 public void ifPresent(Consumer<? super T> consumer) { 203 if (t != null) 204 consumer.accept(t); 205 } 206 207 /** 208 * Applies a mapping function against the contents of this value. 209 * 210 * @param <T2> The mapped value type. 211 * @param mapper The mapping function. 212 * @return The mapped value. 213 */ 214 public <T2> Value<T2> map(Function<? super T, T2> mapper) { 215 if (t != null) 216 return Value.of(mapper.apply(t)); 217 return Value.empty(); 218 } 219 220 /** 221 * Returns the contents of this value or the default value if <jk>null</jk>. 222 * 223 * @param def The default value. 224 * @return The contents of this value or the default value if <jk>null</jk>. 225 */ 226 public T orElse(T def) { 227 return t == null ? def : t; 228 } 229 /** 230 * Returns <jk>true</jk> if the value is empty. 231 * 232 * @return <jk>true</jk> if the value is empty. 233 */ 234 public boolean isEmpty() { 235 return t == null; 236 } 237 238 /** 239 * Return the value if present, otherwise invoke {@code other} and return 240 * the result of that invocation. 241 * 242 * @param other a {@code Supplier} whose result is returned if no value 243 * is present 244 * @return the value if present otherwise the result of {@code other.get()} 245 * @throws NullPointerException if value is not present and {@code other} is 246 * null 247 */ 248 public T orElseGet(Supplier<? extends T> other) { 249 return t != null ? t : other.get(); 250 } 251 252 /** 253 * Return the contained value, if present, otherwise throw an exception 254 * to be created by the provided supplier. 255 * 256 * @param <X> The exception type. 257 * @param exceptionSupplier The supplier which will return the exception to 258 * be thrown 259 * @return the present value 260 * @throws X if there is no value present 261 * @throws NullPointerException if no value is present and 262 * {@code exceptionSupplier} is null 263 */ 264 public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X { 265 if (t != null) 266 return t; 267 throw exceptionSupplier.get(); 268 } 269 270 @Override /* Object */ 271 public String toString() { 272 return "Value("+t+")"; 273 } 274}