3939 */
4040 public OptBoolean useInput () default OptBoolean .DEFAULT ;
4141
42+ /**
43+ * Whether to throw an exception when the {@code ObjectMapper} does not find
44+ * the value to inject.
45+ *<p>
46+ * Default is {@code OptBoolean.DEFAULT} for backwards-compatibility: in this
47+ * case {@code ObjectMapper} defaults are used (which in turn are same
48+ * as {code OptBoolean.FALSE}).
49+ *
50+ * @return {@link OptBoolean#FALSE} to throw an exception; {@link OptBoolean#TRUE}
51+ * to avoid throwing it; or {@link OptBoolean#DEFAULT} to use configure defaults
52+ * (which are same as {@link OptBoolean#FALSE} for Jackson 2.x)
53+ *
54+ * @since 2.20
55+ */
56+ public OptBoolean optional () default OptBoolean .DEFAULT ;
57+
4258 /*
4359 /**********************************************************
4460 /* Value class used to enclose information, allow for
@@ -58,7 +74,7 @@ public static class Value
5874 {
5975 private static final long serialVersionUID = 1L ;
6076
61- protected final static Value EMPTY = new Value (null , null );
77+ protected final static Value EMPTY = new Value (null , null , null );
6278
6379 /**
6480 * Id to use to access injected value; if `null`, "default" name, derived
@@ -68,9 +84,12 @@ public static class Value
6884
6985 protected final Boolean _useInput ;
7086
71- protected Value (Object id , Boolean useInput ) {
87+ protected final Boolean _optional ;
88+
89+ protected Value (Object id , Boolean useInput , Boolean optional ) {
7290 _id = id ;
7391 _useInput = useInput ;
92+ _optional = optional ;
7493 }
7594
7695 @ Override
@@ -88,25 +107,33 @@ public static Value empty() {
88107 return EMPTY ;
89108 }
90109
110+ @ Deprecated //since 2.20
91111 public static Value construct (Object id , Boolean useInput ) {
112+ return construct (id , useInput , null );
113+ }
114+
115+ /**
116+ * @since 2.20
117+ */
118+ public static Value construct (Object id , Boolean useInput , Boolean optional ) {
92119 if ("" .equals (id )) {
93120 id = null ;
94121 }
95- if (_empty (id , useInput )) {
122+ if (_empty (id , useInput , optional )) {
96123 return EMPTY ;
97124 }
98- return new Value (id , useInput );
125+ return new Value (id , useInput , optional );
99126 }
100127
101128 public static Value from (JacksonInject src ) {
102129 if (src == null ) {
103130 return EMPTY ;
104131 }
105- return construct (src .value (), src .useInput ().asBoolean ());
132+ return construct (src .value (), src .useInput ().asBoolean (), src . optional (). asBoolean () );
106133 }
107134
108135 public static Value forId (Object id ) {
109- return construct (id , null );
136+ return construct (id , null , null );
110137 }
111138
112139 /*
@@ -123,7 +150,7 @@ public Value withId(Object id) {
123150 } else if (id .equals (_id )) {
124151 return this ;
125152 }
126- return new Value (id , _useInput );
153+ return new Value (id , _useInput , _optional );
127154 }
128155
129156 public Value withUseInput (Boolean useInput ) {
@@ -134,7 +161,18 @@ public Value withUseInput(Boolean useInput) {
134161 } else if (useInput .equals (_useInput )) {
135162 return this ;
136163 }
137- return new Value (_id , useInput );
164+ return new Value (_id , useInput , _optional );
165+ }
166+
167+ public Value withOptional (Boolean optional ) {
168+ if (optional == null ) {
169+ if (_optional == null ) {
170+ return this ;
171+ }
172+ } else if (optional .equals (_optional )) {
173+ return this ;
174+ }
175+ return new Value (_id , _useInput , optional );
138176 }
139177
140178 /*
@@ -145,6 +183,7 @@ public Value withUseInput(Boolean useInput) {
145183
146184 public Object getId () { return _id ; }
147185 public Boolean getUseInput () { return _useInput ; }
186+ public Boolean getOptional () { return _optional ; }
148187
149188 public boolean hasId () {
150189 return _id != null ;
@@ -162,8 +201,8 @@ public boolean willUseInput(boolean defaultSetting) {
162201
163202 @ Override
164203 public String toString () {
165- return String .format ("JacksonInject.Value(id=%s,useInput=%s)" ,
166- _id , _useInput );
204+ return String .format ("JacksonInject.Value(id=%s,useInput=%s,optional=%s )" ,
205+ _id , _useInput , _optional );
167206 }
168207
169208 @ Override
@@ -175,6 +214,9 @@ public int hashCode() {
175214 if (_useInput != null ) {
176215 h += _useInput .hashCode ();
177216 }
217+ if (_optional != null ) {
218+ h += _optional .hashCode ();
219+ }
178220 return h ;
179221 }
180222
@@ -184,12 +226,13 @@ public boolean equals(Object o) {
184226 if (o == null ) return false ;
185227 if (o .getClass () == getClass ()) {
186228 Value other = (Value ) o ;
187- if (OptBoolean .equals (_useInput , other ._useInput )) {
188- if (_id == null ) {
189- return other ._id == null ;
190- }
191- return _id .equals (other ._id );
192- }
229+
230+ return (_id == null && other ._id == null
231+ || _id != null && _id .equals (other ._id ))
232+ && (_useInput == null && other ._useInput == null
233+ || _useInput != null && _useInput .equals (other ._useInput ))
234+ && (_optional == null && other ._optional == null
235+ || _optional != null && _optional .equals (other ._optional ));
193236 }
194237 return false ;
195238 }
@@ -200,8 +243,8 @@ public boolean equals(Object o) {
200243 /**********************************************************
201244 */
202245
203- private static boolean _empty (Object id , Boolean useInput ) {
204- return (id == null ) && (useInput == null );
246+ private static boolean _empty (Object id , Boolean useInput , Boolean optional ) {
247+ return (id == null ) && (useInput == null ) && optional == null ;
205248 }
206249 }
207250}
0 commit comments