Skip to content

Commit f939280

Browse files
committed
Bit more work on #1498
1 parent e72a526 commit f939280

File tree

6 files changed

+298
-10
lines changed

6 files changed

+298
-10
lines changed

src/main/java/com/fasterxml/jackson/databind/DeserializationConfig.java

+53-3
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,11 @@ public final class DeserializationConfig
5555
*/
5656
protected final CoercionConfigs _coercionConfigs;
5757

58+
/**
59+
* @since 2.12
60+
*/
61+
protected final ConstructorDetector _ctorDetector;
62+
5863
/*
5964
/**********************************************************
6065
/* Deserialization features
@@ -109,13 +114,13 @@ public final class DeserializationConfig
109114
*/
110115
public DeserializationConfig(BaseSettings base,
111116
SubtypeResolver str, SimpleMixInResolver mixins, RootNameLookup rootNames,
112-
ConfigOverrides configOverrides,
113-
CoercionConfigs coercionConfigs)
117+
ConfigOverrides configOverrides, CoercionConfigs coercionConfigs)
114118
{
115119
super(base, str, mixins, rootNames, configOverrides);
116120
_deserFeatures = DESER_FEATURE_DEFAULTS;
117121
_problemHandlers = null;
118122
_nodeFactory = JsonNodeFactory.instance;
123+
_ctorDetector = null;
119124
_coercionConfigs = coercionConfigs;
120125
_parserFeatures = 0;
121126
_parserFeaturesToChange = 0;
@@ -137,6 +142,7 @@ protected DeserializationConfig(DeserializationConfig src,
137142
_deserFeatures = src._deserFeatures;
138143
_problemHandlers = src._problemHandlers;
139144
_nodeFactory = src._nodeFactory;
145+
_ctorDetector = src._ctorDetector;
140146
_coercionConfigs = coercionConfigs;
141147
_parserFeatures = src._parserFeatures;
142148
_parserFeaturesToChange = src._parserFeaturesToChange;
@@ -177,6 +183,7 @@ private DeserializationConfig(DeserializationConfig src,
177183
_problemHandlers = src._problemHandlers;
178184
_nodeFactory = src._nodeFactory;
179185
_coercionConfigs = src._coercionConfigs;
186+
_ctorDetector = src._ctorDetector;
180187
_parserFeatures = parserFeatures;
181188
_parserFeaturesToChange = parserFeatureMask;
182189
_formatReadFeatures = formatFeatures;
@@ -194,6 +201,7 @@ private DeserializationConfig(DeserializationConfig src, SubtypeResolver str)
194201
_problemHandlers = src._problemHandlers;
195202
_nodeFactory = src._nodeFactory;
196203
_coercionConfigs = src._coercionConfigs;
204+
_ctorDetector = src._ctorDetector;
197205
_parserFeatures = src._parserFeatures;
198206
_parserFeaturesToChange = src._parserFeaturesToChange;
199207
_formatReadFeatures = src._formatReadFeatures;
@@ -207,19 +215,36 @@ private DeserializationConfig(DeserializationConfig src, BaseSettings base)
207215
_problemHandlers = src._problemHandlers;
208216
_nodeFactory = src._nodeFactory;
209217
_coercionConfigs = src._coercionConfigs;
218+
_ctorDetector = src._ctorDetector;
210219
_parserFeatures = src._parserFeatures;
211220
_parserFeaturesToChange = src._parserFeaturesToChange;
212221
_formatReadFeatures = src._formatReadFeatures;
213222
_formatReadFeaturesToChange = src._formatReadFeaturesToChange;
214223
}
215-
224+
216225
private DeserializationConfig(DeserializationConfig src, JsonNodeFactory f)
217226
{
218227
super(src);
219228
_deserFeatures = src._deserFeatures;
220229
_problemHandlers = src._problemHandlers;
221230
_nodeFactory = f;
222231
_coercionConfigs = src._coercionConfigs;
232+
_ctorDetector = src._ctorDetector;
233+
_parserFeatures = src._parserFeatures;
234+
_parserFeaturesToChange = src._parserFeaturesToChange;
235+
_formatReadFeatures = src._formatReadFeatures;
236+
_formatReadFeaturesToChange = src._formatReadFeaturesToChange;
237+
}
238+
239+
// @since 2.12
240+
private DeserializationConfig(DeserializationConfig src, ConstructorDetector ctorDetector)
241+
{
242+
super(src);
243+
_deserFeatures = src._deserFeatures;
244+
_problemHandlers = src._problemHandlers;
245+
_nodeFactory = src._nodeFactory;
246+
_coercionConfigs = src._coercionConfigs;
247+
_ctorDetector = ctorDetector;
223248
_parserFeatures = src._parserFeatures;
224249
_parserFeaturesToChange = src._parserFeaturesToChange;
225250
_formatReadFeatures = src._formatReadFeatures;
@@ -234,6 +259,7 @@ private DeserializationConfig(DeserializationConfig src,
234259
_problemHandlers = problemHandlers;
235260
_nodeFactory = src._nodeFactory;
236261
_coercionConfigs = src._coercionConfigs;
262+
_ctorDetector = src._ctorDetector;
237263
_parserFeatures = src._parserFeatures;
238264
_parserFeaturesToChange = src._parserFeaturesToChange;
239265
_formatReadFeatures = src._formatReadFeatures;
@@ -247,6 +273,7 @@ private DeserializationConfig(DeserializationConfig src, PropertyName rootName)
247273
_problemHandlers = src._problemHandlers;
248274
_nodeFactory = src._nodeFactory;
249275
_coercionConfigs = src._coercionConfigs;
276+
_ctorDetector = src._ctorDetector;
250277
_parserFeatures = src._parserFeatures;
251278
_parserFeaturesToChange = src._parserFeaturesToChange;
252279
_formatReadFeatures = src._formatReadFeatures;
@@ -260,6 +287,7 @@ private DeserializationConfig(DeserializationConfig src, Class<?> view)
260287
_problemHandlers = src._problemHandlers;
261288
_nodeFactory = src._nodeFactory;
262289
_coercionConfigs = src._coercionConfigs;
290+
_ctorDetector = src._ctorDetector;
263291
_parserFeatures = src._parserFeatures;
264292
_parserFeaturesToChange = src._parserFeaturesToChange;
265293
_formatReadFeatures = src._formatReadFeatures;
@@ -273,6 +301,7 @@ protected DeserializationConfig(DeserializationConfig src, ContextAttributes att
273301
_problemHandlers = src._problemHandlers;
274302
_nodeFactory = src._nodeFactory;
275303
_coercionConfigs = src._coercionConfigs;
304+
_ctorDetector = src._ctorDetector;
276305
_parserFeatures = src._parserFeatures;
277306
_parserFeaturesToChange = src._parserFeaturesToChange;
278307
_formatReadFeatures = src._formatReadFeatures;
@@ -286,6 +315,7 @@ protected DeserializationConfig(DeserializationConfig src, SimpleMixInResolver m
286315
_problemHandlers = src._problemHandlers;
287316
_nodeFactory = src._nodeFactory;
288317
_coercionConfigs = src._coercionConfigs;
318+
_ctorDetector = src._ctorDetector;
289319
_parserFeatures = src._parserFeatures;
290320
_parserFeaturesToChange = src._parserFeaturesToChange;
291321
_formatReadFeatures = src._formatReadFeatures;
@@ -691,6 +721,16 @@ public DeserializationConfig with(JsonNodeFactory f) {
691721
return new DeserializationConfig(this, f);
692722
}
693723

724+
/**
725+
* @since 2.12
726+
*/
727+
public DeserializationConfig with(ConstructorDetector ctorDetector) {
728+
if (_ctorDetector == ctorDetector) {
729+
return this;
730+
}
731+
return new DeserializationConfig(this, ctorDetector);
732+
}
733+
694734
/**
695735
* Method that can be used to add a handler that can (try to)
696736
* resolve non-fatal deserialization problems.
@@ -841,6 +881,16 @@ public final JsonNodeFactory getNodeFactory() {
841881
return _nodeFactory;
842882
}
843883

884+
/**
885+
* @since 2.12
886+
*/
887+
public ConstructorDetector getConstructorDetector() {
888+
if (_ctorDetector == null) {
889+
return ConstructorDetector.DEFAULT;
890+
}
891+
return _ctorDetector;
892+
}
893+
844894
/*
845895
/**********************************************************
846896
/* Introspection methods

src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java

+13
Original file line numberDiff line numberDiff line change
@@ -2191,6 +2191,19 @@ public ObjectMapper setNodeFactory(JsonNodeFactory f) {
21912191
return this;
21922192
}
21932193

2194+
/**
2195+
* Method for specifying {@link ConstructorDetector} to use for
2196+
* determining some aspects of creator auto-detection (specifically
2197+
* auto-detection of constructor, and in particular behavior with
2198+
* single-argument constructors).
2199+
*
2200+
* @since 2.12
2201+
*/
2202+
public ObjectMapper setConstructorDetector(ConstructorDetector cd) {
2203+
_deserializationConfig = _deserializationConfig.with(cd);
2204+
return this;
2205+
}
2206+
21942207
/**
21952208
* Method for adding specified {@link DeserializationProblemHandler}
21962209
* to be used for handling specific problems during deserialization.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
package com.fasterxml.jackson.databind.cfg;
2+
3+
import java.io.IOException;
4+
import java.util.List;
5+
6+
import com.fasterxml.jackson.databind.DatabindContext;
7+
import com.fasterxml.jackson.databind.introspect.AnnotatedConstructor;
8+
9+
/**
10+
* Configurable handler used to select aspects of selecting
11+
* constructor to use as "Creator" for POJOs.
12+
* Defines the API for handlers, a pre-defined set of standard instances
13+
* and methods for constructing alternative configurations.
14+
*
15+
* @since 2.12
16+
*/
17+
public final class ConstructorDetector
18+
implements java.io.Serializable
19+
{
20+
private static final long serialVersionUID = 1L;
21+
22+
/**
23+
* Definition of alternate handling modes of single-argument constructors
24+
* that are annotated with {@link com.fasterxml.jackson.annotation.JsonCreator}
25+
* but without "mode" definition (or explicit name for the argument):
26+
* this is the case where two interpretations
27+
* are possible -- "properties" (in which case the argument is named parameter
28+
* of a JSON Object) and "delegating (in which case the argument maps to the
29+
* whole JSON value).
30+
*<p>
31+
* Default choice is {@code HEURISTIC} (which is Jackson pre-2.12 always uses)
32+
*<p>
33+
* NOTE: does NOT have any effect if explicit {@link @JsonCreator}} annotation
34+
* is required.
35+
*
36+
* @since 2.12
37+
*/
38+
public enum SingleArgConstructor {
39+
/**
40+
* Assume "delegating" mode if not explicitly annotated otherwise
41+
*/
42+
DELEGATING,
43+
44+
/**
45+
* Assume "properties" mode if not explicitly annotated otherwise
46+
*/
47+
PROPERTIES,
48+
49+
/**
50+
* Use heuristics to see if "properties" mode is to be used (POJO has a
51+
* property with the same name as the implicit name [if available] of
52+
* the constructor argument).
53+
* Note: this is the default choice for Jackson versions before 2.12.
54+
*/
55+
HEURISTIC,
56+
57+
/**
58+
* Refuse to decide implicit mode and instead throw a
59+
* {@link com.fasterxml.jackson.databind.exc.InvalidDefinitionException}
60+
* in ambiguous case.
61+
*/
62+
FAIL;
63+
}
64+
65+
// @FunctionalInterface
66+
/**
67+
* Simple interface for optionally defined handler that can select
68+
* specific Constructor to use if more than one implicitly detected ones
69+
* (and no explicitly annotated one) found.
70+
*/
71+
public interface ConstructorSelector {
72+
public AnnotatedConstructor select(DatabindContext ctxt,
73+
List<AnnotatedConstructor> ctors)
74+
throws IOException;
75+
}
76+
77+
/*
78+
/**********************************************************************
79+
/* Global default instances to use
80+
/**********************************************************************
81+
*/
82+
83+
/**
84+
* Instance used by default, which:
85+
*<ul>
86+
* <li>Uses {@link SingleArgConstructor#HEURISTIC} for single-argument constructor case
87+
* </li>
88+
* <li>Does not specify {@link ConstructorSelector} to solve ambiguous
89+
* (multiple implicitly discovered argument-taking Constructors}
90+
* </li>
91+
* <li>Does not require explicit {@code @JsonCreator} annotations (so allows
92+
* auto-detection of Visible constructors} (except for JDK types)
93+
* </li>
94+
* <li>Does not allow auto-detection of Visible constructors for so-called JDK
95+
* types; that is, classes in packages {@code java.*} and {@code javax.*}
96+
* </li>
97+
*</ul>
98+
*/
99+
public final static ConstructorDetector DEFAULT
100+
= new ConstructorDetector(SingleArgConstructor.HEURISTIC);
101+
102+
/**
103+
* Instance similar to {@link #DEFAULT} except that for single-argument case
104+
* uses setting of {@link SingleArgConstructor#PROPERTIES}.
105+
*/
106+
public final static ConstructorDetector USE_PROPERTIES_BASED
107+
= new ConstructorDetector(SingleArgConstructor.PROPERTIES);
108+
109+
/**
110+
* Instance similar to {@link #DEFAULT} except that for single-argument case
111+
* uses setting of {@link SingleArgConstructor#DELEGATING}.
112+
*/
113+
public final static ConstructorDetector USE_DELEGATING
114+
= new ConstructorDetector(SingleArgConstructor.DELEGATING);
115+
116+
/**
117+
* Instance similar to {@link #DEFAULT} except that for single-argument case
118+
* uses setting of {@link SingleArgConstructor#FAIL}.
119+
*/
120+
public final static ConstructorDetector EXPLICIT_ONLY
121+
= new ConstructorDetector(SingleArgConstructor.FAIL);
122+
123+
/*
124+
/**********************************************************************
125+
/* Configuration
126+
/**********************************************************************
127+
*/
128+
129+
protected final SingleArgConstructor _singleArgMode;
130+
131+
protected final ConstructorSelector _selector;
132+
133+
/**
134+
* Whether explicit {@link com.fasterxml.jackson.annotation.JsonCreator}
135+
* is always required for detecting constructors (even if visible) other
136+
* than the default (no argument) constructor.
137+
*/
138+
protected final boolean _requireCtorAnnotation;
139+
140+
/**
141+
* Whether auto-detection of constructors of "JDK types" (those in
142+
* packages {@code java.} and {@code javax.}) is allowed or not (
143+
*/
144+
protected final boolean _allowJDKTypeCtors;
145+
146+
/*
147+
/**********************************************************************
148+
/* Life-cycle
149+
/**********************************************************************
150+
*/
151+
152+
protected ConstructorDetector(SingleArgConstructor singleArgMode,
153+
ConstructorSelector selector,
154+
boolean requireCtorAnnotation,
155+
boolean allowJDKTypeCtors)
156+
{
157+
_singleArgMode = singleArgMode;
158+
_selector = selector;
159+
_requireCtorAnnotation = requireCtorAnnotation;
160+
_allowJDKTypeCtors = allowJDKTypeCtors;
161+
}
162+
163+
/**
164+
* Constructors used for default configurations which only varies
165+
* by {@code _singleArgMode}
166+
*/
167+
protected ConstructorDetector(SingleArgConstructor singleArgMode) {
168+
this(singleArgMode, null, false, false);
169+
}
170+
171+
protected ConstructorDetector withSingleArgMode(SingleArgConstructor singleArgMode) {
172+
return new ConstructorDetector(singleArgMode, _selector,
173+
_requireCtorAnnotation, _allowJDKTypeCtors);
174+
}
175+
176+
protected ConstructorDetector withSelector(ConstructorSelector selector) {
177+
return new ConstructorDetector(_singleArgMode, selector,
178+
_requireCtorAnnotation, _allowJDKTypeCtors);
179+
}
180+
181+
protected ConstructorDetector withRequireAnnotation(boolean state) {
182+
return new ConstructorDetector(_singleArgMode, _selector,
183+
state, _allowJDKTypeCtors);
184+
}
185+
186+
protected ConstructorDetector withAllowJDKTypes(boolean state) {
187+
return new ConstructorDetector(_singleArgMode, _selector,
188+
_requireCtorAnnotation, state);
189+
}
190+
191+
/*
192+
/**********************************************************************
193+
/* API
194+
/**********************************************************************
195+
*/
196+
197+
public SingleArgConstructor singleArgMode() {
198+
return _singleArgMode;
199+
}
200+
201+
public ConstructorSelector constructorSelector() {
202+
return _selector;
203+
}
204+
205+
public boolean requireCtorAnnotation() {
206+
return _requireCtorAnnotation;
207+
}
208+
209+
public boolean allowJDKTypeConstructors() {
210+
return _allowJDKTypeCtors;
211+
}
212+
}

0 commit comments

Comments
 (0)