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.commons.lang; 018 019import static org.apache.juneau.commons.utils.AssertionUtils.*; 020import static org.apache.juneau.commons.utils.Utils.*; 021 022import java.lang.reflect.*; 023import java.util.*; 024import java.util.function.*; 025 026import org.apache.juneau.commons.reflect.ClassInfo; 027 028/** 029 * A generic mutable value wrapper. 030 * 031 * <p> 032 * This class provides a simple way to wrap any object type in a mutable container, making it useful for passing 033 * mutable references to lambdas, inner classes, and methods. It is similar to {@link Optional} but allows the 034 * value to be changed after creation. 035 * 036 * <p> 037 * The class supports method chaining through fluent setters and provides various convenience methods for working 038 * with the wrapped value, including mapping, conditional execution, and default value handling. 039 * 040 * <h5 class='section'>Features:</h5> 041 * <ul class='spaced-list'> 042 * <li>Mutable value container with fluent API 043 * <li>Optional-like methods: {@link #get()}, {@link #orElse(Object)}, {@link #ifPresent(Consumer)}, {@link #map(Function)} 044 * <li>Atomic-like operations: {@link #getAndSet(Object)}, {@link #getAndUnset()} 045 * <li>Listener support for value changes via {@link ValueListener} 046 * <li>Method chaining for all setter operations 047 * </ul> 048 * 049 * <h5 class='section'>Notes:</h5><ul> 050 * <li class='warn'> 051 * This class is <b>not thread-safe</b>. For concurrent access, consider using atomic classes like 052 * {@link java.util.concurrent.atomic.AtomicReference}. 053 * </ul> 054 * 055 * <h5 class='section'>Examples:</h5> 056 * <p class='bjava'> 057 * <jc>// Basic usage</jc> 058 * Value<String> <jv>name</jv> = Value.<jsm>of</jsm>(<js>"John"</js>); 059 * <jv>name</jv>.set(<js>"Jane"</js>); 060 * String <jv>result</jv> = <jv>name</jv>.get(); <jc>// Returns "Jane"</jc> 061 * 062 * <jc>// Use in lambda (effectively final variable)</jc> 063 * Value<String> <jv>result</jv> = Value.<jsm>empty</jsm>(); 064 * list.forEach(<jv>x</jv> -> { 065 * <jk>if</jk> (<jv>x</jv>.matches(criteria)) { 066 * <jv>result</jv>.set(<jv>x</jv>); 067 * } 068 * }); 069 * 070 * <jc>// With default values</jc> 071 * Value<String> <jv>optional</jv> = Value.<jsm>empty</jsm>(); 072 * String <jv>value</jv> = <jv>optional</jv>.orElse(<js>"default"</js>); <jc>// Returns "default"</jc> 073 * 074 * <jc>// Mapping values</jc> 075 * Value<Integer> <jv>number</jv> = Value.<jsm>of</jsm>(5); 076 * Value<String> <jv>text</jv> = <jv>number</jv>.map(Object::toString); <jc>// Value of "5"</jc> 077 * 078 * <jc>// With listener for change notification</jc> 079 * Value<String> <jv>monitored</jv> = Value.<jsm>of</jsm>(<js>"initial"</js>) 080 * .listener(<jv>newValue</jv> -> <jsm>log</jsm>(<js>"Value changed to: "</js> + <jv>newValue</jv>)); 081 * <jv>monitored</jv>.set(<js>"updated"</js>); <jc>// Triggers listener</jc> 082 * </p> 083 * 084 * <h5 class='section'>Specialized Value Classes:</h5> 085 * <p> 086 * For primitive types and common use cases, specialized subclasses are available with additional convenience methods: 087 * <ul class='spaced-list'> 088 * <li>{@link IntegerValue} - For mutable integers with {@code getAndIncrement()} 089 * <li>{@link LongValue} - For mutable longs with {@code getAndIncrement()} 090 * <li>{@link ShortValue} - For mutable shorts with {@code getAndIncrement()} 091 * <li>{@link FloatValue} - For mutable floats 092 * <li>{@link DoubleValue} - For mutable doubles 093 * <li>{@link CharValue} - For mutable characters 094 * <li>{@link BooleanValue} - For nullable booleans with {@code isTrue()}/{@code isNotTrue()} 095 * <li>{@link Flag} - For non-nullable boolean flags (true/false only, no null state) 096 * </ul> 097 * 098 * <h5 class='section'>See Also:</h5><ul> 099 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauCommonsLang">Lang Package</a> 100 * <li class='jc'>{@link ValueListener} 101 * <li class='jc'>{@link IntegerValue} 102 * <li class='jc'>{@link BooleanValue} 103 * <li class='jc'>{@link Flag} 104 * </ul> 105 * 106 * @param <T> The value type. 107 */ 108public class Value<T> { 109 /** 110 * Creates a new empty value (with <c>null</c> as the initial value). 111 * 112 * <h5 class='section'>Example:</h5> 113 * <p class='bjava'> 114 * Value<String> <jv>value</jv> = Value.<jsm>empty</jsm>(); 115 * <jsm>assertNull</jsm>(<jv>value</jv>.get()); 116 * <jsm>assertTrue</jsm>(<jv>value</jv>.isEmpty()); 117 * </p> 118 * 119 * @param <T> The value type. 120 * @return A new empty {@link Value} object. 121 */ 122 public static <T> Value<T> empty() { 123 return new Value<>(null); 124 } 125 126 /** 127 * Convenience method for checking if the specified type is this class. 128 * 129 * @param t The type to check. 130 * @return <jk>true</jk> if the specified type is this class. 131 */ 132 public static boolean isType(Type t) { 133 return (t instanceof ParameterizedType t2 && t2.getRawType() == Value.class) || (t instanceof Class t3 && Value.class.isAssignableFrom(t3)); 134 } 135 136 /** 137 * Creates a new value with the specified initial value. 138 * 139 * <h5 class='section'>Example:</h5> 140 * <p class='bjava'> 141 * Value<String> <jv>value</jv> = Value.<jsm>of</jsm>(<js>"hello"</js>); 142 * <jsm>assertEquals</jsm>(<js>"hello"</js>, <jv>value</jv>.get()); 143 * </p> 144 * 145 * @param <T> The value type. 146 * @param object The object being wrapped. Can be <jk>null</jk>. 147 * @return A new {@link Value} object containing the specified value. 148 */ 149 public static <T> Value<T> of(T object) { 150 return new Value<>(object); 151 } 152 153 /** 154 * Returns the generic parameter type of the Value type. 155 * 156 * @param t The type to find the parameter type of. 157 * @return The parameter type of the value, or <jk>null</jk> if the type is not a subclass of <c>Value</c>. 158 */ 159 public static Type getParameterType(Type t) { 160 if (t instanceof ParameterizedType t2) { 161 if (t2.getRawType() == Value.class) { 162 var ta = t2.getActualTypeArguments(); 163 if (ta.length > 0) 164 return ta[0]; 165 } 166 } else if ((t instanceof Class<?> t3) && Value.class.isAssignableFrom(t3)) { 167 return ClassInfo.of(t3).getParameterType(0, Value.class); 168 } 169 170 return null; 171 } 172 173 /** 174 * Returns the unwrapped type. 175 * 176 * @param t The type to unwrap. 177 * @return The unwrapped type, or the same type if the type isn't {@link Value}. 178 */ 179 public static Type unwrap(Type t) { 180 var x = getParameterType(t); 181 return nn(x) ? x : t; 182 } 183 184 private T t; 185 private ValueListener<T> listener; 186 187 /** 188 * Constructor. 189 */ 190 public Value() {} 191 192 /** 193 * Constructor. 194 * 195 * @param t Initial value. 196 */ 197 public Value(T t) { 198 set(t); 199 } 200 201 @Override /* Overridden from Object */ 202 public boolean equals(Object obj) { 203 return obj instanceof Value<?> obj2 && eq(this, obj2, (x, y) -> eq(x.t, y.t)); 204 } 205 206 /** 207 * If a value is present, and the value matches the given predicate, returns a {@link Value} describing the 208 * value, otherwise returns an empty {@link Value}. 209 * 210 * <p> 211 * This method is analogous to {@link java.util.Optional#filter(Predicate)}. 212 * 213 * <h5 class='section'>Example:</h5> 214 * <p class='bjava'> 215 * Value<String> <jv>value</jv> = Value.<jsm>of</jsm>(<js>"hello"</js>); 216 * Value<String> <jv>filtered</jv> = <jv>value</jv>.filter(<jv>s</jv> -> <jv>s</jv>.length() > 3); 217 * <jsm>assertTrue</jsm>(<jv>filtered</jv>.isPresent()); 218 * 219 * Value<String> <jv>filtered2</jv> = <jv>value</jv>.filter(<jv>s</jv> -> <jv>s</jv>.length() > 10); 220 * <jsm>assertFalse</jsm>(<jv>filtered2</jv>.isPresent()); 221 * </p> 222 * 223 * @param predicate The predicate to apply to the value, if present. Must not be <jk>null</jk>. 224 * @return A {@link Value} describing the value if it is present and matches the predicate, otherwise an empty {@link Value}. 225 */ 226 public Value<T> filter(Predicate<? super T> predicate) { 227 assertArgNotNull("predicate", predicate); 228 if (t == null) 229 return Value.empty(); 230 return predicate.test(t) ? this : Value.empty(); 231 } 232 233 /** 234 * If a value is present, returns the result of applying the given {@link Value}-bearing mapping function to 235 * the value, otherwise returns an empty {@link Value}. 236 * 237 * <p> 238 * This method is similar to {@link #map(Function)}, but the mapping function returns a {@link Value} rather 239 * than a simple value. This is analogous to {@link java.util.Optional#flatMap(Function)}. 240 * 241 * <h5 class='section'>Example:</h5> 242 * <p class='bjava'> 243 * Value<String> <jv>value</jv> = Value.<jsm>of</jsm>(<js>"hello"</js>); 244 * Value<Integer> <jv>length</jv> = <jv>value</jv>.flatMap(<jv>s</jv> -> Value.<jsm>of</jsm>(<jv>s</jv>.length())); 245 * <jsm>assertEquals</jsm>(5, <jv>length</jv>.get()); 246 * 247 * <jc>// Returns empty if mapper returns empty</jc> 248 * Value<String> <jv>empty</jv> = <jv>value</jv>.flatMap(<jv>s</jv> -> Value.<jsm>empty</jsm>()); 249 * <jsm>assertFalse</jsm>(<jv>empty</jv>.isPresent()); 250 * </p> 251 * 252 * @param <T2> The type of value in the {@link Value} returned by the mapping function. 253 * @param mapper The mapping function to apply to the value, if present. Must not be <jk>null</jk>. 254 * @return The result of applying the {@link Value}-bearing mapping function to the value if present, 255 * otherwise an empty {@link Value}. 256 */ 257 public <T2> Value<T2> flatMap(Function<? super T,? extends Value<? extends T2>> mapper) { 258 assertArgNotNull("mapper", mapper); 259 if (t == null) 260 return Value.empty(); 261 var result = mapper.apply(t); 262 @SuppressWarnings("unchecked") 263 var cast = (Value<T2>)result; 264 return cast; 265 } 266 267 /** 268 * Returns the value. 269 * 270 * @return The value, or <jk>null</jk> if it is not set. 271 */ 272 public T get() { 273 return t; 274 } 275 276 /** 277 * Returns the current value and then sets it to the specified value. 278 * 279 * <h5 class='section'>Example:</h5> 280 * <p class='bjava'> 281 * Value<String> <jv>value</jv> = Value.<jsm>of</jsm>(<js>"old"</js>); 282 * String <jv>oldValue</jv> = <jv>value</jv>.getAndSet(<js>"new"</js>); <jc>// Returns "old"</jc> 283 * String <jv>newValue</jv> = <jv>value</jv>.get(); <jc>// Returns "new"</jc> 284 * </p> 285 * 286 * @param t The new value. 287 * @return The value before it was set. 288 */ 289 public T getAndSet(T t) { 290 var t2 = this.t; 291 set(t); 292 return t2; 293 } 294 295 /** 296 * Returns the current value and then unsets it (sets to <jk>null</jk>). 297 * 298 * <p> 299 * This is useful for "consuming" a value, ensuring it can only be retrieved once. 300 * 301 * <h5 class='section'>Example:</h5> 302 * <p class='bjava'> 303 * Value<String> <jv>value</jv> = Value.<jsm>of</jsm>(<js>"data"</js>); 304 * String <jv>result</jv> = <jv>value</jv>.getAndUnset(); <jc>// Returns "data"</jc> 305 * <jsm>assertNull</jsm>(<jv>value</jv>.get()); <jc>// Value is now null</jc> 306 * </p> 307 * 308 * @return The value before it was unset, or <jk>null</jk> if it was already <jk>null</jk>. 309 */ 310 public T getAndUnset() { 311 var t2 = t; 312 t = null; 313 return t2; 314 } 315 316 @Override /* Overridden from Object */ 317 public int hashCode() { 318 return t == null ? 0 : t.hashCode(); 319 } 320 321 /** 322 * If a value is present (not <jk>null</jk>), invokes the specified consumer with the value, otherwise does nothing. 323 * 324 * <h5 class='section'>Example:</h5> 325 * <p class='bjava'> 326 * Value<String> <jv>value</jv> = Value.<jsm>of</jsm>(<js>"hello"</js>); 327 * <jv>value</jv>.ifPresent(<jsm>System.out</jsm>::<jv>println</jv>); <jc>// Prints "hello"</jc> 328 * 329 * Value<String> <jv>empty</jv> = Value.<jsm>empty</jsm>(); 330 * <jv>empty</jv>.ifPresent(<jsm>System.out</jsm>::<jv>println</jv>); <jc>// Does nothing</jc> 331 * </p> 332 * 333 * @param consumer Block to be executed if a value is present. Must not be <jk>null</jk>. 334 */ 335 public void ifPresent(Consumer<? super T> consumer) { 336 if (nn(t)) 337 consumer.accept(t); 338 } 339 340 /** 341 * Checks if the current value equals the specified value using {@link org.apache.juneau.commons.utils.Utils#eq(Object, Object)}. 342 * 343 * <p> 344 * This method uses {@code eq()} for equality comparison, which handles <jk>null</jk> values safely 345 * and performs deep equality checks for arrays and collections. 346 * 347 * <h5 class='section'>Example:</h5> 348 * <p class='bjava'> 349 * Value<String> <jv>value</jv> = Value.<jsm>of</jsm>(<js>"hello"</js>); 350 * <jsm>assertTrue</jsm>(<jv>value</jv>.is(<js>"hello"</js>)); 351 * <jsm>assertFalse</jsm>(<jv>value</jv>.is(<js>"world"</js>)); 352 * 353 * <jc>// Handles null values safely</jc> 354 * Value<String> <jv>empty</jv> = Value.<jsm>empty</jsm>(); 355 * <jsm>assertTrue</jsm>(<jv>empty</jv>.is(<jk>null</jk>)); 356 * <jsm>assertFalse</jsm>(<jv>empty</jv>.is(<js>"test"</js>)); 357 * 358 * <jc>// Works with any type</jc> 359 * Value<Integer> <jv>number</jv> = Value.<jsm>of</jsm>(42); 360 * <jsm>assertTrue</jsm>(<jv>number</jv>.is(42)); 361 * <jsm>assertFalse</jsm>(<jv>number</jv>.is(43)); 362 * </p> 363 * 364 * @param other The value to compare with. Can be <jk>null</jk>. 365 * @return <jk>true</jk> if the values are equal according to {@link org.apache.juneau.commons.utils.Utils#eq(Object, Object)}. 366 */ 367 public boolean is(T other) { 368 return eq(t, other); 369 } 370 371 /** 372 * Returns <jk>true</jk> if the value is empty. 373 * 374 * @return <jk>true</jk> if the value is empty. 375 */ 376 public boolean isEmpty() { return t == null; } 377 378 /** 379 * Returns <jk>true</jk> if the value is set. 380 * 381 * @return <jk>true</jk> if the value is set. 382 */ 383 public boolean isPresent() { return nn(get()); } 384 385 /** 386 * Registers a listener that will be called whenever the value is changed via {@link #set(Object)}. 387 * 388 * <p> 389 * Only one listener can be registered at a time. Calling this method again will replace the previous listener. 390 * 391 * <h5 class='section'>Example:</h5> 392 * <p class='bjava'> 393 * Value<String> <jv>value</jv> = Value.<jsm>of</jsm>(<js>"initial"</js>); 394 * <jv>value</jv>.listener(<jv>newValue</jv> -> <jsm>log</jsm>(<js>"Changed to: "</js> + <jv>newValue</jv>)); 395 * 396 * <jv>value</jv>.set(<js>"updated"</js>); <jc>// Triggers listener, logs "Changed to: updated"</jc> 397 * </p> 398 * 399 * @param listener The listener to be called on value changes. Can be <jk>null</jk> to remove the listener. 400 * @return This object for method chaining. 401 * @see ValueListener 402 */ 403 public Value<T> listener(ValueListener<T> listener) { 404 this.listener = listener; 405 return this; 406 } 407 408 /** 409 * Applies a mapping function to the value if present, returning a new {@link Value} with the result. 410 * 411 * <p> 412 * If this value is empty (<jk>null</jk>), returns an empty value without applying the mapper. 413 * 414 * <h5 class='section'>Example:</h5> 415 * <p class='bjava'> 416 * Value<String> <jv>name</jv> = Value.<jsm>of</jsm>(<js>"john"</js>); 417 * Value<String> <jv>upper</jv> = <jv>name</jv>.map(String::toUpperCase); 418 * <jsm>assertEquals</jsm>(<js>"JOHN"</js>, <jv>upper</jv>.get()); 419 * 420 * Value<Integer> <jv>length</jv> = <jv>name</jv>.map(String::length); 421 * <jsm>assertEquals</jsm>(4, <jv>length</jv>.get()); 422 * 423 * Value<String> <jv>empty</jv> = Value.<jsm>empty</jsm>(); 424 * Value<Integer> <jv>result</jv> = <jv>empty</jv>.map(String::length); <jc>// Returns empty Value</jc> 425 * </p> 426 * 427 * @param <T2> The mapped value type. 428 * @param mapper The mapping function to apply. Must not be <jk>null</jk>. 429 * @return A new {@link Value} containing the mapped result, or an empty value if this value is empty. 430 */ 431 public <T2> Value<T2> map(Function<? super T,T2> mapper) { 432 assertArgNotNull("mapper", mapper); 433 if (nn(t)) 434 return of(mapper.apply(t)); 435 return empty(); 436 } 437 438 /** 439 * Returns the contents of this value or the default value if <jk>null</jk>. 440 * 441 * @param def The default value. 442 * @return The contents of this value or the default value if <jk>null</jk>. 443 */ 444 public T orElse(T def) { 445 return t == null ? def : t; 446 } 447 448 /** 449 * Return the value if present, otherwise invoke {@code other} and return 450 * the result of that invocation. 451 * 452 * @param other a {@code Supplier} whose result is returned if no value 453 * is present 454 * @return the value if present otherwise the result of {@code other.get()} 455 * @throws NullPointerException if value is not present and {@code other} is 456 * null 457 */ 458 public T orElseGet(Supplier<? extends T> other) { 459 return nn(t) ? t : other.get(); 460 } 461 462 /** 463 * Return the contained value, if present, otherwise throw an exception 464 * to be created by the provided supplier. 465 * 466 * @param <X> The exception type. 467 * @param exceptionSupplier The supplier which will return the exception to 468 * be thrown 469 * @return the present value 470 * @throws X if there is no value present 471 * @throws NullPointerException if no value is present and 472 * {@code exceptionSupplier} is null 473 */ 474 public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X { 475 if (nn(t)) 476 return t; 477 throw exceptionSupplier.get(); 478 } 479 480 /** 481 * Sets the value. 482 * 483 * <p> 484 * If a {@link ValueListener} is registered, it will be notified of the change. 485 * 486 * <h5 class='section'>Example:</h5> 487 * <p class='bjava'> 488 * Value<String> <jv>value</jv> = Value.<jsm>empty</jsm>(); 489 * <jv>value</jv>.set(<js>"hello"</js>).set(<js>"world"</js>); <jc>// Method chaining</jc> 490 * <jsm>assertEquals</jsm>(<js>"world"</js>, <jv>value</jv>.get()); 491 * </p> 492 * 493 * @param t The new value. Can be <jk>null</jk>. 494 * @return This object for method chaining. 495 */ 496 public Value<T> set(T t) { 497 this.t = t; 498 if (nn(listener)) 499 listener.onSet(t); 500 return this; 501 } 502 503 /** 504 * Sets the value only if the specified condition is <jk>true</jk>. 505 * 506 * <h5 class='section'>Example:</h5> 507 * <p class='bjava'> 508 * Value<String> <jv>value</jv> = Value.<jsm>of</jsm>(<js>"old"</js>); 509 * <jv>value</jv>.setIf(<jk>true</jk>, <js>"new"</js>); <jc>// Sets to "new"</jc> 510 * <jv>value</jv>.setIf(<jk>false</jk>, <js>"newer"</js>); <jc>// Does nothing</jc> 511 * <jsm>assertEquals</jsm>(<js>"new"</js>, <jv>value</jv>.get()); 512 * </p> 513 * 514 * @param condition The condition to check. 515 * @param t The value to set if condition is <jk>true</jk>. 516 * @return This object. 517 */ 518 public Value<T> setIf(boolean condition, T t) { 519 if (condition) 520 set(t); 521 return this; 522 } 523 524 /** 525 * Sets the value only if it is currently empty (<jk>null</jk>). 526 * 527 * <p> 528 * If the value is already set, this method does nothing. 529 * 530 * <h5 class='section'>Example:</h5> 531 * <p class='bjava'> 532 * Value<String> <jv>value</jv> = Value.<jsm>empty</jsm>(); 533 * <jv>value</jv>.setIfEmpty(<js>"first"</js>); <jc>// Sets value to "first"</jc> 534 * <jv>value</jv>.setIfEmpty(<js>"second"</js>); <jc>// Does nothing, value remains "first"</jc> 535 * <jsm>assertEquals</jsm>(<js>"first"</js>, <jv>value</jv>.get()); 536 * </p> 537 * 538 * @param t The new value. Can be <jk>null</jk>. 539 * @return This object for method chaining. 540 */ 541 public Value<T> setIfEmpty(T t) { 542 if (isEmpty()) 543 set(t); 544 return this; 545 } 546 547 @Override /* Overridden from Object */ 548 public String toString() { 549 return "Value(" + t + ")"; 550 } 551 552 /** 553 * Updates the value in-place using the specified function. 554 * 555 * <p> 556 * If the current value is <jk>null</jk>, this is a no-op. 557 * 558 * <h5 class='section'>Example:</h5> 559 * <p class='bjava'> 560 * Value<String> <jv>value</jv> = Value.<jsm>of</jsm>(<js>"hello"</js>); 561 * <jv>value</jv>.update(String::toUpperCase); 562 * <jsm>assertEquals</jsm>(<js>"HELLO"</js>, <jv>value</jv>.get()); 563 * 564 * <jc>// No-op when null</jc> 565 * Value<String> <jv>empty</jv> = Value.<jsm>empty</jsm>(); 566 * <jv>empty</jv>.update(String::toUpperCase); <jc>// Does nothing</jc> 567 * <jsm>assertNull</jsm>(<jv>empty</jv>.get()); 568 * </p> 569 * 570 * @param updater The function to apply to the current value. Must not be <jk>null</jk>. 571 * @return This object. 572 */ 573 public Value<T> update(Function<T,T> updater) { 574 if (nn(t)) 575 set(updater.apply(t)); 576 return this; 577 } 578}