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