Skip to content

Commit cc478a2

Browse files
committed
Merge branch '2.7' into 2.8
2 parents 55f0f3e + 16d7725 commit cc478a2

File tree

8 files changed

+139
-98
lines changed

8 files changed

+139
-98
lines changed

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,13 @@ protected BeanDescription(JavaType type) {
5151

5252
public Class<?> getBeanClass() { return _type.getRawClass(); }
5353

54+
/**
55+
* @since 2.9
56+
*/
57+
public boolean isNonStaticInnerClass() {
58+
return getClassInfo().isNonStaticInnerClass();
59+
}
60+
5461
/**
5562
* Method for accessing low-level information about Class this
5663
* item describes.

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

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -295,7 +295,7 @@ protected ValueInstantiator _constructDefaultValueInstantiator(DeserializationCo
295295
BeanDescription beanDesc)
296296
throws JsonMappingException
297297
{
298-
CreatorCollector creators = new CreatorCollector(beanDesc, ctxt.getConfig());
298+
CreatorCollector creators = new CreatorCollector(beanDesc, ctxt.getConfig());
299299
AnnotationIntrospector intr = ctxt.getAnnotationIntrospector();
300300

301301
// need to construct suitable visibility checker:
@@ -313,10 +313,8 @@ protected ValueInstantiator _constructDefaultValueInstantiator(DeserializationCo
313313
*/
314314
Map<AnnotatedWithParams,BeanPropertyDefinition[]> creatorDefs = _findCreatorsFromProperties(ctxt,
315315
beanDesc);
316-
317-
/* Important: first add factory methods; then constructors, so
318-
* latter can override former!
319-
*/
316+
// Important: first add factory methods; then constructors, so
317+
// latter can override former!
320318
_addDeserializerFactoryMethods(ctxt, beanDesc, vchecker, intr, creators, creatorDefs);
321319
// constructors only usable on concrete types:
322320
if (beanDesc.getType().isConcrete()) {
@@ -398,8 +396,6 @@ public ValueInstantiator _valueInstantiatorInstance(DeserializationConfig config
398396
Map<AnnotatedWithParams,BeanPropertyDefinition[]> creatorParams)
399397
throws JsonMappingException
400398
{
401-
final boolean isNonStatic = ClassUtil.isNonStaticInnerClass(beanDesc.getBeanClass());
402-
403399
// First things first: the "default constructor" (zero-arg
404400
// constructor; whether implicit or explicit) is NOT included
405401
// in list of constructors, so needs to be handled separately.
@@ -410,23 +406,24 @@ public ValueInstantiator _valueInstantiatorInstance(DeserializationConfig config
410406
}
411407
}
412408

409+
// 25-Jan-2017, tatu: As per [databind#1501], [databind#1502], [databind#1503], best
410+
// for now to skip attempts at using anything but no-args constructor (see
411+
// `InnerClassProperty` construction for that)
412+
final boolean isNonStaticInnerClass = beanDesc.isNonStaticInnerClass();
413+
if (isNonStaticInnerClass) {
414+
// TODO: look for `@JsonCreator` annotated ones, throw explicit exception?
415+
return;
416+
}
417+
413418
// may need to keep track for [#725]
414419
List<AnnotatedConstructor> implicitCtors = null;
415420
for (AnnotatedConstructor ctor : beanDesc.getConstructors()) {
416421
final boolean isCreator = intr.hasCreatorAnnotation(ctor);
417422
BeanPropertyDefinition[] propDefs = creatorParams.get(ctor);
418-
int argCount = ctor.getParameterCount();
419-
420-
// 24-Jan-2017, tatu: Handling of constructors for non-static inner classes
421-
// cause nothing but grief (see [databind#1503] for example)... ugh.
422-
/*
423-
if (isNonStatic) {
424-
--argCount;
425-
}
426-
*/
423+
final int argCount = ctor.getParameterCount();
427424

428425
// some single-arg factory methods (String, number) are auto-detected
429-
if ((argCount == 1) && !isNonStatic) {
426+
if (argCount == 1) {
430427
BeanPropertyDefinition argDef = (propDefs == null) ? null : propDefs[0];
431428
boolean useProps = _checkIfCreatorPropertyBased(intr, ctor, argDef);
432429

@@ -514,10 +511,13 @@ public ValueInstantiator _valueInstantiatorInstance(DeserializationConfig config
514511
if (impl == null || impl.isEmpty()) {
515512
// Let's consider non-static inner class as a special case...
516513
int ix = nonAnnotatedParam.getIndex();
517-
if ((ix == 0) && ClassUtil.isNonStaticInnerClass(ctor.getDeclaringClass())) {
514+
// 25-Jan-2017, tatu: Non-static inner classes skipped altogether, now
515+
/*
516+
if ((ix == 0) && isNonStaticInnerClass) {
518517
throw new IllegalArgumentException("Non-static inner classes like "
519518
+ctor.getDeclaringClass().getName()+" can not use @JsonCreator for constructors");
520519
}
520+
*/
521521
throw new IllegalArgumentException("Argument #"+ix
522522
+" of constructor "+ctor+" has no property name annotation; must have name when multiple-parameter constructor annotated as Creator");
523523
}

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

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,11 @@
55
import java.lang.reflect.InvocationTargetException;
66
import java.util.*;
77

8-
import com.fasterxml.jackson.annotation.JsonFormat;
9-
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
10-
import com.fasterxml.jackson.annotation.JsonTypeInfo;
11-
import com.fasterxml.jackson.annotation.ObjectIdGenerator;
12-
import com.fasterxml.jackson.annotation.ObjectIdGenerators;
13-
import com.fasterxml.jackson.annotation.ObjectIdResolver;
8+
import com.fasterxml.jackson.annotation.*;
9+
1410
import com.fasterxml.jackson.core.*;
1511
import com.fasterxml.jackson.core.JsonParser.NumberType;
12+
1613
import com.fasterxml.jackson.databind.*;
1714
import com.fasterxml.jackson.databind.deser.impl.*;
1815
import com.fasterxml.jackson.databind.deser.std.StdDelegatingDeserializer;
@@ -840,7 +837,7 @@ protected SettableBeanProperty _resolveUnwrappedProperty(DeserializationContext
840837
*/
841838
protected SettableBeanProperty _resolveInnerClassValuedProperty(DeserializationContext ctxt,
842839
SettableBeanProperty prop)
843-
{
840+
{
844841
/* Should we encounter a property that has non-static inner-class
845842
* as value, we need to add some more magic to find the "hidden" constructor...
846843
*/
@@ -851,16 +848,19 @@ protected SettableBeanProperty _resolveInnerClassValuedProperty(DeserializationC
851848
ValueInstantiator vi = bd.getValueInstantiator();
852849
if (!vi.canCreateUsingDefault()) { // no default constructor
853850
Class<?> valueClass = prop.getType().getRawClass();
851+
// NOTE: almost same as `isNonStaticInnerClass()` but need to know enclosing...
854852
Class<?> enclosing = ClassUtil.getOuterClass(valueClass);
855853
// and is inner class of the bean class...
856-
if (enclosing != null && enclosing == _beanType.getRawClass()) {
854+
if ((enclosing != null) && (enclosing == _beanType.getRawClass())) {
857855
for (Constructor<?> ctor : valueClass.getConstructors()) {
858856
Class<?>[] paramTypes = ctor.getParameterTypes();
859-
if (paramTypes.length == 1 && paramTypes[0] == enclosing) {
860-
if (ctxt.canOverrideAccessModifiers()) {
861-
ClassUtil.checkAndFixAccess(ctor, ctxt.isEnabled(MapperFeature.OVERRIDE_PUBLIC_ACCESS_MODIFIERS));
857+
if (paramTypes.length == 1) {
858+
if (enclosing.equals(paramTypes[0])) {
859+
if (ctxt.canOverrideAccessModifiers()) {
860+
ClassUtil.checkAndFixAccess(ctor, ctxt.isEnabled(MapperFeature.OVERRIDE_PUBLIC_ACCESS_MODIFIERS));
861+
}
862+
return new InnerClassProperty(prop, ctor);
862863
}
863-
return new InnerClassProperty(prop, ctor);
864864
}
865865
}
866866
}
@@ -1202,8 +1202,16 @@ protected Object deserializeFromObjectUsingNonDefault(JsonParser p,
12021202
return ctxt.handleMissingInstantiator(handledType(), p,
12031203
"abstract type (need to add/enable type information?)");
12041204
}
1205-
return ctxt.handleMissingInstantiator(_beanType.getRawClass(), p,
1206-
"no suitable constructor found, can not deserialize from Object value (missing default constructor or creator, or perhaps need to add/enable type information?)");
1205+
// 25-Jan-2017, tatu: We do not actually support use of Creators for non-static
1206+
// inner classes -- with one and only one exception; that of default constructor!
1207+
// -- so let's indicate it
1208+
Class<?> raw = _beanType.getRawClass();
1209+
if (ClassUtil.isNonStaticInnerClass(raw)) {
1210+
return ctxt.handleMissingInstantiator(raw, p,
1211+
"can only instantiate non-static inner class by using default, no-argument constructor");
1212+
}
1213+
return ctxt.handleMissingInstantiator(raw, p,
1214+
"no suitable constructor found, can not deserialize from Object value (missing default constructor or creator, or perhaps need to add/enable type information?)");
12071215
}
12081216

12091217
protected abstract Object _deserializeUsingPropertyBased(final JsonParser p,

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -147,10 +147,10 @@ public JsonDeserializer<Object> createBuilderBasedDeserializer(
147147
Class<?> builderClass)
148148
throws JsonMappingException
149149
{
150-
// First: need a BeanDescription for builder class
151-
JavaType builderType = ctxt.constructType(builderClass);
152-
BeanDescription builderDesc = ctxt.getConfig().introspectForBuilder(builderType);
153-
return buildBuilderBasedDeserializer(ctxt, valueType, builderDesc);
150+
// First: need a BeanDescription for builder class
151+
JavaType builderType = ctxt.constructType(builderClass);
152+
BeanDescription builderDesc = ctxt.getConfig().introspectForBuilder(builderType);
153+
return buildBuilderBasedDeserializer(ctxt, valueType, builderDesc);
154154
}
155155

156156
/**

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

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,14 @@ public final class AnnotatedClass
124124
*/
125125
protected List<AnnotatedField> _fields;
126126

127+
/**
128+
* Lazily determined property to see if this is a non-static inner
129+
* class.
130+
*
131+
* @since 2.8.7
132+
*/
133+
protected transient Boolean _nonStaticInnerClass;
134+
127135
/*
128136
/**********************************************************
129137
/* Life-cycle
@@ -355,6 +363,18 @@ public Iterable<AnnotatedField> fields()
355363
return _fields;
356364
}
357365

366+
/**
367+
* @since 2.9
368+
*/
369+
public boolean isNonStaticInnerClass()
370+
{
371+
Boolean B = _nonStaticInnerClass;
372+
if (B == null) {
373+
_nonStaticInnerClass = B = ClassUtil.isNonStaticInnerClass(_class);
374+
}
375+
return B.booleanValue();
376+
}
377+
358378
/*
359379
/**********************************************************
360380
/* Public API, main-level resolution methods

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,11 @@ protected void collectAll()
300300
// First: gather basic data
301301
_addFields(props);
302302
_addMethods(props);
303-
_addCreators(props);
303+
// 25-Jan-2016, tatu: Avoid introspecting (constructor-)creators for non-static
304+
// inner classes, see [databind#1502]
305+
if (!_classDef.isNonStaticInnerClass()) {
306+
_addCreators(props);
307+
}
304308
_addInjectables(props);
305309

306310
// Remove ignored properties, first; this MUST precede annotation merging

src/test/java/com/fasterxml/jackson/databind/creators/InnerClassCreatorTest.java

Lines changed: 63 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,50 @@
44
import com.fasterxml.jackson.annotation.JsonProperty;
55
import com.fasterxml.jackson.databind.*;
66

7-
// for [databind#1501]
7+
// For [databind#1501], [databind#1502], [databind#1503]; mostly to
8+
// test that for non-static inner classes constructors are ignored
9+
// and no Creators should be processed (since they can not be made
10+
// to work in standard way anyway).
811
public class InnerClassCreatorTest extends BaseMapTest
912
{
1013
static class Something1501 {
11-
public InnerSomething a;
14+
public InnerSomething1501 a;
1215

1316
// important: must name the parameter (param names module, or explicit)
1417
@JsonCreator
15-
public Something1501(@JsonProperty("a") InnerSomething a) { this.a = a; }
18+
public Something1501(@JsonProperty("a") InnerSomething1501 a) { this.a = a; }
1619

17-
public Something1501(boolean bogus) { a = new InnerSomething(); }
20+
public Something1501(boolean bogus) { a = new InnerSomething1501(); }
1821

19-
class InnerSomething {
22+
class InnerSomething1501 {
2023
@JsonCreator
21-
public InnerSomething() { }
24+
public InnerSomething1501() { }
25+
}
26+
}
27+
28+
static class Something1502 {
29+
@JsonProperty
30+
public InnerSomething1502 a;
31+
32+
@JsonCreator
33+
public Something1502(InnerSomething1502 a) {}
34+
35+
class InnerSomething1502 {
36+
@JsonCreator
37+
public InnerSomething1502() {}
38+
}
39+
}
40+
41+
static class Outer1503 {
42+
public InnerClass1503 innerClass;
43+
44+
class InnerClass1503 {
45+
public Generic<?> generic;
46+
public InnerClass1503(@JsonProperty("generic") Generic<?> generic) {}
47+
}
48+
49+
static class Generic<T> {
50+
public int ignored;
2251
}
2352
}
2453

@@ -31,6 +60,33 @@ public InnerSomething() { }
3160
public void testIssue1501() throws Exception
3261
{
3362
String ser = MAPPER.writeValueAsString(new Something1501(false));
34-
MAPPER.readValue(ser, Something1501.class);
63+
try {
64+
MAPPER.readValue(ser, Something1501.class);
65+
fail("Should not pass");
66+
} catch (JsonMappingException e) {
67+
verifyException(e, "Can not construct instance");
68+
verifyException(e, "InnerSomething1501");
69+
verifyException(e, "can only instantiate non-static inner class by using default");
70+
}
71+
}
72+
73+
public void testIssue1502() throws Exception
74+
{
75+
String ser = MAPPER.writeValueAsString(new Something1502(null));
76+
try {
77+
MAPPER.readValue(ser, Something1502.class);
78+
fail("Should not pass");
79+
} catch (JsonMappingException e) {
80+
verifyException(e, "Can not construct instance");
81+
verifyException(e, "InnerSomething1502");
82+
verifyException(e, "can only instantiate non-static inner class by using default");
83+
}
84+
}
85+
86+
public void testIssue1503() throws Exception
87+
{
88+
String ser = MAPPER.writeValueAsString(new Outer1503());
89+
Outer1503 result = MAPPER.readValue(ser, Outer1503.class);
90+
assertNotNull(result);
3591
}
3692
}

src/test/java/com/fasterxml/jackson/failing/InnerClassCreator1502Test.java

Lines changed: 0 additions & 54 deletions
This file was deleted.

0 commit comments

Comments
 (0)