Skip to content

Commit 7620a6f

Browse files
committed
Complete implementation, testing
1 parent 042c437 commit 7620a6f

File tree

3 files changed

+146
-43
lines changed

3 files changed

+146
-43
lines changed

src/main/java/com/fasterxml/jackson/databind/introspect/POJOPropertiesCollector.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -798,7 +798,7 @@ private void _removeNonFactoryStaticMethods(List<PotentialCreator> ctors,
798798
while (it.hasNext()) {
799799
// explicit mode? Retain (for now)
800800
PotentialCreator ctor = it.next();
801-
if (ctor.creatorMode() != null) {
801+
if (ctor.isAnnotated()) {
802802
continue;
803803
}
804804
// Do not trim canonical either
@@ -836,7 +836,7 @@ private void _addExplicitlyAnnotatedCreators(PotentialCreators collector,
836836

837837
// If no explicit annotation, skip for now (may be discovered
838838
// at a later point)
839-
if (ctor.creatorMode() == null) {
839+
if (!ctor.isAnnotated()) {
840840
continue;
841841
}
842842

src/main/java/com/fasterxml/jackson/databind/introspect/PotentialCreator.java

Lines changed: 45 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,18 @@ public class PotentialCreator
1717
{
1818
private static final PropertyName[] NO_NAMES = new PropertyName[0];
1919

20-
private final AnnotatedWithParams creator;
20+
private final AnnotatedWithParams _creator;
21+
22+
private final boolean _isAnnotated;
2123

2224
/**
2325
* Declared Mode of the creator, if explicitly annotated; {@code null} otherwise
2426
*/
25-
private JsonCreator.Mode creatorMode;
27+
private JsonCreator.Mode _creatorMode;
2628

27-
private PropertyName[] implicitParamNames;
29+
private PropertyName[] _implicitParamNames;
2830

29-
private PropertyName[] explicitParamNames;
31+
private PropertyName[] _explicitParamNames;
3032

3133
/**
3234
* Parameter definitions if (and only if) this represents a
@@ -37,8 +39,9 @@ public class PotentialCreator
3739
public PotentialCreator(AnnotatedWithParams cr,
3840
JsonCreator.Mode cm)
3941
{
40-
creator = cr;
41-
creatorMode = cm;
42+
_creator = cr;
43+
_isAnnotated = (cm != null);
44+
_creatorMode = (cm == null) ? JsonCreator.Mode.DEFAULT : cm;
4245
}
4346

4447
/**
@@ -51,7 +54,7 @@ public PotentialCreator(AnnotatedWithParams cr,
5154
* @return This creator instance
5255
*/
5356
public PotentialCreator overrideMode(JsonCreator.Mode mode) {
54-
creatorMode = mode;
57+
_creatorMode = mode;
5558
return this;
5659
}
5760

@@ -68,30 +71,30 @@ public void assignPropertyDefs(List<? extends BeanPropertyDefinition> propertyDe
6871

6972
public PotentialCreator introspectParamNames(MapperConfig<?> config)
7073
{
71-
if (implicitParamNames != null) {
74+
if (_implicitParamNames != null) {
7275
return this;
7376
}
74-
final int paramCount = creator.getParameterCount();
77+
final int paramCount = _creator.getParameterCount();
7578

7679
if (paramCount == 0) {
77-
implicitParamNames = explicitParamNames = NO_NAMES;
80+
_implicitParamNames = _explicitParamNames = NO_NAMES;
7881
return this;
7982
}
8083

81-
explicitParamNames = new PropertyName[paramCount];
82-
implicitParamNames = new PropertyName[paramCount];
84+
_explicitParamNames = new PropertyName[paramCount];
85+
_implicitParamNames = new PropertyName[paramCount];
8386

8487
final AnnotationIntrospector intr = config.getAnnotationIntrospector();
8588
for (int i = 0; i < paramCount; ++i) {
86-
AnnotatedParameter param = creator.getParameter(i);
89+
AnnotatedParameter param = _creator.getParameter(i);
8790

8891
String rawImplName = intr.findImplicitPropertyName(param);
8992
if (rawImplName != null && !rawImplName.isEmpty()) {
90-
implicitParamNames[i] = PropertyName.construct(rawImplName);
93+
_implicitParamNames[i] = PropertyName.construct(rawImplName);
9194
}
9295
PropertyName explName = intr.findNameForDeserialization(param);
9396
if (explName != null && !explName.isEmpty()) {
94-
explicitParamNames[i] = explName;
97+
_explicitParamNames[i] = explName;
9598
}
9699
}
97100
return this;
@@ -104,25 +107,25 @@ public PotentialCreator introspectParamNames(MapperConfig<?> config)
104107
public PotentialCreator introspectParamNames(MapperConfig<?> config,
105108
PropertyName[] implicits)
106109
{
107-
if (implicitParamNames != null) {
110+
if (_implicitParamNames != null) {
108111
return this;
109112
}
110-
final int paramCount = creator.getParameterCount();
113+
final int paramCount = _creator.getParameterCount();
111114
if (paramCount == 0) {
112-
implicitParamNames = explicitParamNames = NO_NAMES;
115+
_implicitParamNames = _explicitParamNames = NO_NAMES;
113116
return this;
114117
}
115118

116-
explicitParamNames = new PropertyName[paramCount];
117-
implicitParamNames = implicits;
119+
_explicitParamNames = new PropertyName[paramCount];
120+
_implicitParamNames = implicits;
118121

119122
final AnnotationIntrospector intr = config.getAnnotationIntrospector();
120123
for (int i = 0; i < paramCount; ++i) {
121-
AnnotatedParameter param = creator.getParameter(i);
124+
AnnotatedParameter param = _creator.getParameter(i);
122125

123126
PropertyName explName = intr.findNameForDeserialization(param);
124127
if (explName != null && !explName.isEmpty()) {
125-
explicitParamNames[i] = explName;
128+
_explicitParamNames[i] = explName;
126129
}
127130
}
128131
return this;
@@ -134,57 +137,61 @@ public PotentialCreator introspectParamNames(MapperConfig<?> config,
134137
/**********************************************************************
135138
*/
136139

140+
public boolean isAnnotated() {
141+
return _isAnnotated;
142+
}
143+
137144
public AnnotatedWithParams creator() {
138-
return creator;
145+
return _creator;
139146
}
140147

141148
/**
142149
* @return Mode declared for this Creator by annotation, if any; {@code null}
143150
* if not annotated
144151
*/
145152
public JsonCreator.Mode creatorMode() {
146-
return creatorMode;
153+
return _creatorMode;
147154
}
148155

149156
/**
150157
* Same as {@link #creatorMode()} except that if {@code null} was to be
151158
* returned, will instead return {@code JsonCreator.Mode.DEFAULT}/
152159
*/
153160
public JsonCreator.Mode creatorModeOrDefault() {
154-
if (creatorMode == null) {
161+
if (_creatorMode == null) {
155162
return JsonCreator.Mode.DEFAULT;
156163
}
157-
return creatorMode;
164+
return _creatorMode;
158165
}
159166

160167
public int paramCount() {
161-
return creator.getParameterCount();
168+
return _creator.getParameterCount();
162169
}
163170

164171
public AnnotatedParameter param(int ix) {
165-
return creator.getParameter(ix);
172+
return _creator.getParameter(ix);
166173
}
167174

168175
public boolean hasExplicitNames() {
169-
for (int i = 0, end = explicitParamNames.length; i < end; ++i) {
170-
if (explicitParamNames[i] != null) {
176+
for (int i = 0, end = _explicitParamNames.length; i < end; ++i) {
177+
if (_explicitParamNames[i] != null) {
171178
return true;
172179
}
173180
}
174181
return false;
175182
}
176183

177184
public boolean hasNameFor(int ix) {
178-
return (explicitParamNames[ix] != null)
179-
|| (implicitParamNames[ix] != null);
185+
return (_explicitParamNames[ix] != null)
186+
|| (_implicitParamNames[ix] != null);
180187
}
181188

182189
public boolean hasNameOrInjectForAllParams(MapperConfig<?> config)
183190
{
184191
final AnnotationIntrospector intr = config.getAnnotationIntrospector();
185-
for (int i = 0, end = implicitParamNames.length; i < end; ++i) {
192+
for (int i = 0, end = _implicitParamNames.length; i < end; ++i) {
186193
if (!hasNameFor(i)) {
187-
if (intr == null || intr.findInjectableValue(creator.getParameter(i)) == null) {
194+
if (intr == null || intr.findInjectableValue(_creator.getParameter(i)) == null) {
188195
return false;
189196
}
190197
}
@@ -193,15 +200,15 @@ public boolean hasNameOrInjectForAllParams(MapperConfig<?> config)
193200
}
194201

195202
public PropertyName explicitName(int ix) {
196-
return explicitParamNames[ix];
203+
return _explicitParamNames[ix];
197204
}
198205

199206
public PropertyName implicitName(int ix) {
200-
return implicitParamNames[ix];
207+
return _implicitParamNames[ix];
201208
}
202209

203210
public String implicitNameSimple(int ix) {
204-
PropertyName pn = implicitParamNames[ix];
211+
PropertyName pn = _implicitParamNames[ix];
205212
return (pn == null) ? null : pn.getSimpleName();
206213
}
207214

@@ -221,7 +228,7 @@ public BeanPropertyDefinition[] propertyDefs() {
221228
// For troubleshooting
222229
@Override
223230
public String toString() {
224-
return "(mode="+creatorMode+")"+creator;
231+
return "(mode="+_creatorMode+")"+_creator;
225232
}
226233
}
227234

src/test/java/com/fasterxml/jackson/databind/introspect/CanonicalCreator4584Test.java

Lines changed: 99 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,39 @@ public String toString() {
5555
}
5656
}
5757

58+
// Let's also ensure that explicit annotation trumps Primary
59+
static class POJO4584Annotated {
60+
String value;
61+
62+
@JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
63+
POJO4584Annotated(@ImplicitName("v") String v, @ImplicitName("bogus") int bogus) {
64+
value = v;
65+
}
66+
67+
POJO4584Annotated(@ImplicitName("i") int i, @ImplicitName("foobar") String f) {
68+
throw new Error("Should NOT get called!");
69+
}
70+
71+
public static POJO4584Annotated wrongInt(@ImplicitName("i") int i) {
72+
throw new Error("Should NOT get called!");
73+
}
74+
75+
@JsonCreator(mode = JsonCreator.Mode.DELEGATING)
76+
public static POJO4584Annotated factoryString(String v) {
77+
return new POJO4584Annotated(v, 0);
78+
}
79+
80+
@Override
81+
public boolean equals(Object o) {
82+
return (o instanceof POJO4584Annotated) && Objects.equals(((POJO4584Annotated) o).value, value);
83+
}
84+
85+
@Override
86+
public String toString() {
87+
return "'"+value+"'";
88+
}
89+
}
90+
5891
static class PrimaryCreatorFindingIntrospector extends ImplicitNameIntrospector
5992
{
6093
private static final long serialVersionUID = 1L;
@@ -63,21 +96,44 @@ static class PrimaryCreatorFindingIntrospector extends ImplicitNameIntrospector
6396

6497
private JsonCreator.Mode _mode;
6598

99+
private final String _factoryName;
100+
66101
public PrimaryCreatorFindingIntrospector(JsonCreator.Mode mode,
67102
Class<?>... argTypes) {
68103
_mode = mode;
104+
_factoryName = null;
69105
_argTypes = argTypes;
70106
}
71107

108+
public PrimaryCreatorFindingIntrospector(JsonCreator.Mode mode,
109+
String factoryName) {
110+
_mode = mode;
111+
_factoryName = factoryName;
112+
_argTypes = new Class<?>[0];
113+
}
114+
72115
@Override
73116
public PotentialCreator findPrimaryCreator(MapperConfig<?> config,
74117
AnnotatedClass valueClass,
75118
List<PotentialCreator> declaredConstructors,
76119
List<PotentialCreator> declaredFactories)
77120
{
78-
if (valueClass.getRawType() != POJO4584.class) {
121+
// Apply to all test POJOs here but nothing else
122+
if (!valueClass.getRawType().toString().contains("4584")) {
79123
return null;
80124
}
125+
126+
if (_factoryName != null) {
127+
for (PotentialCreator ctor : declaredFactories) {
128+
if (ctor.creator().getName().equals(_factoryName)) {
129+
System.err.println("For "+valueClass.getRawType().getName()+" -> ('"+_factoryName+"') "+ctor);
130+
return ctor;
131+
}
132+
}
133+
System.err.println("For "+valueClass.getRawType().getName()+" -> ('"+_factoryName+"') NULL");
134+
return null;
135+
}
136+
81137
List<PotentialCreator> combo = new ArrayList<>(declaredConstructors);
82138
combo.addAll(declaredFactories);
83139
final int argCount = _argTypes.length;
@@ -101,7 +157,7 @@ public PotentialCreator findPrimaryCreator(MapperConfig<?> config,
101157

102158
/*
103159
/**********************************************************************
104-
/* Test methods; properties-based Creators
160+
/* Test methods; simple properties-based Creators
105161
/**********************************************************************
106162
*/
107163

@@ -113,6 +169,12 @@ public void testCanonicalConstructor1ArgPropertiesCreator() throws Exception
113169
readerWith(new PrimaryCreatorFindingIntrospector(JsonCreator.Mode.PROPERTIES,
114170
List.class))
115171
.readValue(a2q("{'list':[ 1, 2]}")));
172+
173+
// ok to map from empty Object too
174+
assertEquals(POJO4584.factoryString("List[-1]"),
175+
readerWith(new PrimaryCreatorFindingIntrospector(JsonCreator.Mode.PROPERTIES,
176+
List.class))
177+
.readValue(a2q("{}")));
116178
}
117179

118180
@Test
@@ -123,11 +185,17 @@ public void testCanonicalConstructor2ArgPropertiesCreator() throws Exception
123185
readerWith(new PrimaryCreatorFindingIntrospector(JsonCreator.Mode.PROPERTIES,
124186
String.class, Integer.TYPE))
125187
.readValue(a2q("{'bogus':12, 'v':'abc' }")));
188+
189+
// ok to map from empty Object too
190+
assertEquals(POJO4584.factoryString(null),
191+
readerWith(new PrimaryCreatorFindingIntrospector(JsonCreator.Mode.PROPERTIES,
192+
String.class, Integer.TYPE))
193+
.readValue(a2q("{}")));
126194
}
127195

128196
/*
129197
/**********************************************************************
130-
/* Test methods; delegation-based Creators
198+
/* Test methods; simple delegation-based Creators
131199
/**********************************************************************
132200
*/
133201

@@ -158,6 +226,34 @@ public void testCanonicalConstructorDelegatingArrayCreator() throws Exception
158226
.readValue(a2q("[true]")));
159227
}
160228

229+
/*
230+
/**********************************************************************
231+
/* Test methods; deal with explicitly annotated types
232+
/**********************************************************************
233+
*/
234+
235+
// Here we test to ensure that
236+
237+
@Test
238+
public void testDelegatingVsExplicit() throws Exception
239+
{
240+
assertEquals(POJO4584Annotated.factoryString("abc"),
241+
mapperWith(new PrimaryCreatorFindingIntrospector(JsonCreator.Mode.DELEGATING,
242+
"wrongInt"))
243+
.readerFor(POJO4584Annotated.class)
244+
.readValue(a2q("{'v':'abc','bogus':3}")));
245+
}
246+
247+
@Test
248+
public void testPropertiesBasedVsExplicit() throws Exception
249+
{
250+
assertEquals(POJO4584Annotated.factoryString("abc"),
251+
mapperWith(new PrimaryCreatorFindingIntrospector(JsonCreator.Mode.PROPERTIES,
252+
Integer.TYPE, String.class))
253+
.readerFor(POJO4584Annotated.class)
254+
.readValue(a2q("{'v':'abc','bogus':3}")));
255+
}
256+
161257
/*
162258
/**********************************************************************
163259
/* Helper methods

0 commit comments

Comments
 (0)