Skip to content

Commit 2c77b62

Browse files
committed
Implement #3676
1 parent 7f243a5 commit 2c77b62

File tree

5 files changed

+62
-2
lines changed

5 files changed

+62
-2
lines changed

release-notes/VERSION-2.x

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@ Project: jackson-databind
44
=== Releases ===
55
------------------------------------------------------------------------
66

7+
2.15.0 (not yet released)
8+
9+
#3676: Allow use of `@JsonCreator(mode = Mode.PROPERTIES)` creator for POJOs
10+
with"empty String" coercion
11+
712
2.14.1 (not yet released)
813

914
#3655: `Enum` values can not be read from single-element array even with

src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializerBase.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1039,7 +1039,11 @@ public AccessPattern getEmptyAccessPattern() {
10391039
public Object getEmptyValue(DeserializationContext ctxt) throws JsonMappingException {
10401040
// alas, need to promote exception, if any:
10411041
try {
1042-
return _valueInstantiator.createUsingDefault(ctxt);
1042+
// 20-Nov-2022, tatu: Ok one more complication; may want to consider
1043+
// EITHER default Creator OR properties-one with no args.
1044+
// But that is encapsulated by `ValueInstantiator` now
1045+
// return _valueInstantiator.createUsingDefault(ctxt);
1046+
return _valueInstantiator.createUsingDefaultOrWithoutArguments(ctxt);
10431047
} catch (IOException e) {
10441048
return ClassUtil.throwAsMappingException(ctxt, e);
10451049
}

src/main/java/com/fasterxml/jackson/databind/deser/ValueInstantiator.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,19 @@ public Object createFromObjectWith(DeserializationContext ctxt, Object[] args) t
263263
"no creator with arguments specified");
264264
}
265265

266+
/**
267+
* Combination of {@link #createUsingDefault} and {@link #createFromObjectWith(DeserializationContext, Object[])}
268+
* which will call former first, if possible; or latter if possible (with {@code null}
269+
* arguments); and if neither works throw an exception.
270+
*
271+
* @since 2.15
272+
*/
273+
//public abstract Object createUsingDefaultOrWithoutArguments(DeserializationContext ctxt) throws IOException;
274+
public Object createUsingDefaultOrWithoutArguments(DeserializationContext ctxt) throws IOException {
275+
return ctxt.handleMissingInstantiator(getValueClass(), this, null,
276+
"neither default (no-arguments) nor with-arguments Creator found");
277+
}
278+
266279
/**
267280
* Method that delegates to
268281
* {@link #createFromObjectWith(DeserializationContext, Object[])} by

src/main/java/com/fasterxml/jackson/databind/deser/std/StdValueInstantiator.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,17 @@ public Object createFromObjectWith(DeserializationContext ctxt, Object[] args) t
294294
}
295295
}
296296

297+
@Override
298+
public Object createUsingDefaultOrWithoutArguments(DeserializationContext ctxt) throws IOException {
299+
if (_defaultCreator != null) { // sanity-check; caller should check
300+
return createUsingDefault(ctxt);
301+
}
302+
if (_withArgsCreator != null) {
303+
return createFromObjectWith(ctxt, new Object[_constructorArguments.length]);
304+
}
305+
return super.createUsingDefaultOrWithoutArguments(ctxt);
306+
}
307+
297308
@Override
298309
public Object createUsingDelegate(DeserializationContext ctxt, Object delegate) throws IOException
299310
{

src/test/java/com/fasterxml/jackson/databind/convert/CoercePojosTest.java

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package com.fasterxml.jackson.databind.convert;
22

3+
import com.fasterxml.jackson.annotation.JsonCreator;
4+
import com.fasterxml.jackson.annotation.JsonProperty;
35
import com.fasterxml.jackson.core.JacksonException;
46

57
import com.fasterxml.jackson.databind.*;
@@ -14,11 +16,20 @@ static class Bean {
1416
public String a;
1517
}
1618

17-
private final ObjectMapper MAPPER = newJsonMapper();
19+
static class BeanWithProp3676 {
20+
@JsonCreator
21+
public BeanWithProp3676(@JsonProperty("a") String a) {
22+
this.a = a;
23+
}
24+
25+
public String a;
26+
}
1827

1928
private final String JSON_EMPTY = q("");
2029
private final String JSON_BLANK = q(" ");
2130

31+
private final ObjectMapper MAPPER = newJsonMapper();
32+
2233
/*
2334
/********************************************************
2435
/* Test methods, from empty String
@@ -52,6 +63,22 @@ public void testPOJOFromEmptyPhysicalTypeConfig() throws Exception
5263
_testPOJOFromEmptyPhysicalTypeConfig(CoercionInputShape.EmptyString, JSON_EMPTY, null);
5364
}
5465

66+
// [databind#3676] Alternative test for "Mode.PROPERTIES" variant where we
67+
// have no "default" constructor
68+
public void testPOJOFromEmptyWithProperties() throws Exception
69+
{
70+
// Then coerce as empty
71+
ObjectMapper mapper = jsonMapperBuilder()
72+
.withCoercionConfigDefaults(h -> {
73+
h.setCoercion(CoercionInputShape.EmptyString, CoercionAction.AsEmpty);
74+
})
75+
.build();
76+
BeanWithProp3676 b = mapper.readerFor(BeanWithProp3676.class)
77+
.readValue(JSON_EMPTY);
78+
assertNotNull(b);
79+
assertNull(b.a);
80+
}
81+
5582
/*
5683
/********************************************************
5784
/* Test methods, from blank String

0 commit comments

Comments
 (0)