1 /*
2 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License").
5 * You may not use this file except in compliance with the License.
6 * A copy of the License is located at
7 *
8 * http://aws.amazon.com/apache2.0
9 *
10 * or in the "license" file accompanying this file. This file is distributed
11 * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12 * express or implied. See the License for the specific language governing
13 * permissions and limitations under the License.
14 */
15
16 package software.amazon.awssdk.services.s3.internal;
17
18 import java.util.function.Supplier;
19 import software.amazon.awssdk.annotations.SdkInternalApi;
20 import software.amazon.awssdk.utils.Lazy;
21
22 /**
23 * A helper class for setting a field's value to a default if it isn't specified, while still keeping track of whether the value
24 * was from the default or from the field.
25 *
26 * For example, a "profile name" field-with-default might be set to "null" with a default of "foo". {@link #value()} returns
27 * "foo", while {@link #isDefault()} can be used to keep track of the fact that the value was from the default.
28 */
29 @SdkInternalApi
30 public abstract class FieldWithDefault<T> {
31 private FieldWithDefault(){
32 }
33
34 /**
35 * Create a {@link FieldWithDefault} using the provided field and its default value. If the field is null, the default value
36 * will be returned by {@link #value()} and {@link #isDefault()} will return true. If the field is not null, the field value
37 * will be returned by {@link #value()} and {@link #isDefault()} will return false.
38 *
39 * @see #createLazy(Object, Supplier)
40 */
41 public static <T> FieldWithDefault<T> create(T field, T defaultValue) {
42 return new Impl<>(field, defaultValue);
43 }
44
45 /**
46 * Create a {@link FieldWithDefault} using the provided field and its default value. If the field is null, the default value
47 * will be returned by {@link #value()} and {@link #isDefault()} will return true. If the field is not null, the field value
48 * will be returned by {@link #value()} and {@link #isDefault()} will return false.
49 *
50 * <p>This differs from {@link #create(Object, Object)} in that the default value won't be resolved if the provided field is
51 * not null. The default value also won't be resolved until the first {@link #value()} call. This is useful for delaying
52 * expensive calculations until right before they're needed.
53 */
54 public static <T> FieldWithDefault<T> createLazy(T field, Supplier<T> defaultValue) {
55 return new LazyImpl<>(field, defaultValue);
56 }
57
58 /**
59 * Retrieve the value of this field.
60 */
61 public abstract T value();
62
63 /**
64 * True, if the value returned by {@link #value()} is the default value (i.e. the field is null). False otherwise.
65 */
66 public abstract boolean isDefault();
67
68 /**
69 * Return the field exactly as it was specified when the field-with-default was created. If the field was null, this will
70 * return null. This will not resolve the default if this is a field from {@link #createLazy(Object, Supplier)}.
71 */
72 public abstract T valueOrNullIfDefault();
73
74 private static class Impl<T> extends FieldWithDefault<T> {
75 private final T value;
76 private final boolean isDefault;
77
78 private Impl(T field, T defaultValue) {
79 this.value = field != null ? field : defaultValue;
80 this.isDefault = field == null;
81 }
82
83 @Override
84 public T value() {
85 return value;
86 }
87
88 @Override
89 public boolean isDefault() {
90 return isDefault;
91 }
92
93 @Override
94 public T valueOrNullIfDefault() {
95 return isDefault ? null : value;
96 }
97 }
98
99 private static class LazyImpl<T> extends FieldWithDefault<T> {
100 private final Lazy<T> value;
101 private final boolean isDefault;
102
103 private LazyImpl(T field, Supplier<T> defaultValue) {
104 this.value = field != null ? new Lazy<>(() -> field) : new Lazy<>(defaultValue);
105 this.isDefault = field == null;
106 }
107
108 @Override
109 public T value() {
110 return value.getValue();
111 }
112
113 @Override
114 public boolean isDefault() {
115 return isDefault;
116 }
117
118 @Override
119 public T valueOrNullIfDefault() {
120 return isDefault ? null : value.getValue();
121 }
122 }
123 }
124