Skip to content

Commit a6943ec

Browse files
committed
Start #725 implementation; works for simple case, need to work on allowing overrides
1 parent 8022285 commit a6943ec

File tree

10 files changed

+224
-123
lines changed

10 files changed

+224
-123
lines changed

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

-19
Original file line numberDiff line numberDiff line change
@@ -619,14 +619,6 @@ public JsonDeserializer<?> handlePrimaryContextualization(JsonDeserializer<?> de
619619
return deser;
620620
}
621621

622-
@Deprecated // since 2.5; remove from 2.6
623-
public JsonDeserializer<?> handlePrimaryContextualization(JsonDeserializer<?> deser,
624-
BeanProperty prop)
625-
throws JsonMappingException
626-
{
627-
return handlePrimaryContextualization(deser, prop, TypeFactory.unknownType());
628-
}
629-
630622
/**
631623
* Method called for secondary property deserializers (ones
632624
* NOT directly created to deal with an annotatable POJO property,
@@ -658,17 +650,6 @@ public JsonDeserializer<?> handleSecondaryContextualization(JsonDeserializer<?>
658650
return deser;
659651
}
660652

661-
@Deprecated // since 2.5; remove from 2.6
662-
public JsonDeserializer<?> handleSecondaryContextualization(JsonDeserializer<?> deser,
663-
BeanProperty prop)
664-
throws JsonMappingException
665-
{
666-
if (deser instanceof ContextualDeserializer) {
667-
deser = ((ContextualDeserializer) deser).createContextual(this, prop);
668-
}
669-
return deser;
670-
}
671-
672653
/*
673654
/**********************************************************
674655
/* Parsing methods that may use reusable/-cyclable objects

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

+106-38
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import com.fasterxml.jackson.databind.*;
1111
import com.fasterxml.jackson.databind.cfg.DeserializerFactoryConfig;
1212
import com.fasterxml.jackson.databind.cfg.HandlerInstantiator;
13+
import com.fasterxml.jackson.databind.cfg.MapperConfig;
1314
import com.fasterxml.jackson.databind.deser.impl.CreatorCollector;
1415
import com.fasterxml.jackson.databind.deser.std.*;
1516
import com.fasterxml.jackson.databind.ext.OptionalHandlerFactory;
@@ -21,6 +22,7 @@
2122
import com.fasterxml.jackson.databind.util.ClassUtil;
2223
import com.fasterxml.jackson.databind.util.EnumResolver;
2324
import com.fasterxml.jackson.databind.util.NameTransformer;
25+
import com.fasterxml.jackson.databind.util.SimpleBeanPropertyDefinition;
2426
import com.fasterxml.jackson.databind.util.TokenBuffer;
2527

2628
/**
@@ -310,9 +312,12 @@ protected ValueInstantiator _constructDefaultValueInstantiator(DeserializationCo
310312
* declarations (which are needed to access creator annotation, amongst other things).
311313
* Easiest to combine that info first, then pass it to remaining processing.
312314
*/
315+
/* 15-Mar-2015, tatu: Alas, this won't help with constructors that only have implicit
316+
* names. Those will need to be resolved later on.
317+
*/
313318
Map<AnnotatedWithParams,BeanPropertyDefinition[]> creatorDefs = _findCreatorsFromProperties(ctxt,
314319
beanDesc);
315-
320+
316321
/* Important: first add factory methods; then constructors, so
317322
* latter can override former!
318323
*/
@@ -337,7 +342,7 @@ protected Map<AnnotatedWithParams,BeanPropertyDefinition[]> _findCreatorsFromPro
337342
final int index = param.getIndex();
338343

339344
if (defs == null) {
340-
if (result.isEmpty()) {
345+
if (result.isEmpty()) { // since emptyMap is immutable need to create a 'real' one
341346
result = new LinkedHashMap<AnnotatedWithParams,BeanPropertyDefinition[]>();
342347
}
343348
defs = new BeanPropertyDefinition[owner.getParameterCount()];
@@ -391,15 +396,6 @@ public ValueInstantiator _valueInstantiatorInstance(DeserializationConfig config
391396
config.canOverrideAccessModifiers());
392397
}
393398

394-
@Deprecated // since 2.5.0, removed from 2.6.0
395-
protected void _addDeserializerConstructors(DeserializationContext ctxt, BeanDescription beanDesc, VisibilityChecker<?> vchecker,
396-
AnnotationIntrospector intr, CreatorCollector creators)
397-
throws JsonMappingException
398-
{
399-
_addDeserializerConstructors(ctxt, beanDesc, vchecker, intr, creators,
400-
Collections.<AnnotatedWithParams,BeanPropertyDefinition[]>emptyMap());
401-
}
402-
403399
protected void _addDeserializerConstructors
404400
(DeserializationContext ctxt, BeanDescription beanDesc, VisibilityChecker<?> vchecker,
405401
AnnotationIntrospector intr, CreatorCollector creators,
@@ -415,6 +411,10 @@ protected void _addDeserializerConstructors(DeserializationContext ctxt, BeanDes
415411
creators.setDefaultCreator(defaultCtor);
416412
}
417413
}
414+
415+
// may need to keep track for [#725]
416+
List<AnnotatedConstructor> implicitCtors = null;
417+
418418
for (AnnotatedConstructor ctor : beanDesc.getConstructors()) {
419419
final boolean isCreator = intr.hasCreatorAnnotation(ctor);
420420
BeanPropertyDefinition[] propDefs = creatorParams.get(ctor);
@@ -447,16 +447,21 @@ protected void _addDeserializerConstructors(DeserializationContext ctxt, BeanDes
447447
}
448448

449449
// 2 or more args; all params must have names or be injectable
450-
AnnotatedParameter nonAnnotatedParam = null;
450+
// 14-Mar-2015, tatu (2.6): Or, as per [#725], implicit names will also
451+
// do, with some constraints. But that will require bit post processing...
452+
453+
AnnotatedParameter nonAnnotatedParam = null;
451454
CreatorProperty[] properties = new CreatorProperty[argCount];
452455
int explicitNameCount = 0;
453-
int implicitNameCount = 0;
454-
int injectCount = 0;
456+
int implicitWithCreatorCount = 0;
457+
int injectCount = 0;
458+
455459
for (int i = 0; i < argCount; ++i) {
456460
final AnnotatedParameter param = ctor.getParameter(i);
457461
BeanPropertyDefinition propDef = (propDefs == null) ? null : propDefs[i];
458462
Object injectId = intr.findInjectableValueId(param);
459463
final PropertyName name = (propDef == null) ? null : propDef.getFullName();
464+
460465
if (propDef != null && propDef.isExplicitlyNamed()) {
461466
++explicitNameCount;
462467
properties[i] = constructCreatorProperty(ctxt, beanDesc, name, i, param, injectId);
@@ -474,29 +479,27 @@ protected void _addDeserializerConstructors(DeserializationContext ctxt, BeanDes
474479
continue;
475480
}
476481
// One more thing: implicit names are ok iff ctor has creator annotation
477-
if (isCreator) {
478-
if (name != null && !name.isEmpty()) {
479-
++implicitNameCount;
480-
properties[i] = constructCreatorProperty(ctxt, beanDesc, name, i, param, injectId);
481-
continue;
482-
}
482+
if (isCreator && (name != null && !name.isEmpty())) {
483+
++implicitWithCreatorCount;
484+
properties[i] = constructCreatorProperty(ctxt, beanDesc, name, i, param, injectId);
485+
continue;
483486
}
484487
if (nonAnnotatedParam == null) {
485488
nonAnnotatedParam = param;
486489
}
487490
}
488491

489-
final int namedCount = explicitNameCount + implicitNameCount;
492+
final int namedCount = explicitNameCount + implicitWithCreatorCount;
490493
// Ok: if named or injectable, we have more work to do
491-
if (isCreator || explicitNameCount > 0 || injectCount > 0) {
494+
if (isCreator || (explicitNameCount > 0) || (injectCount > 0)) {
492495
// simple case; everything covered:
493496
if ((namedCount + injectCount) == argCount) {
494497
creators.addPropertyCreator(ctor, isCreator, properties);
495498
} else if ((explicitNameCount == 0) && ((injectCount + 1) == argCount)) {
496-
// [712] secondary: all but one injectable, one un-annotated (un-named)
499+
// Secondary: all but one injectable, one un-annotated (un-named)
497500
creators.addDelegatingCreator(ctor, isCreator, properties);
498501
} else { // otherwise, epic fail
499-
// 28-Dec-2014, tatu: Let's consider non-static inner class as a special case...
502+
// Let's consider non-static inner class as a special case...
500503
int ix = nonAnnotatedParam.getIndex();
501504
if ((ix == 0) && ClassUtil.isNonStaticInnerClass(ctor.getDeclaringClass())) {
502505
throw new IllegalArgumentException("Non-static inner classes like "
@@ -505,6 +508,77 @@ protected void _addDeserializerConstructors(DeserializationContext ctxt, BeanDes
505508
throw new IllegalArgumentException("Argument #"+ix
506509
+" of constructor "+ctor+" has no property name annotation; must have name when multiple-parameter constructor annotated as Creator");
507510
}
511+
continue;
512+
}
513+
// [#725]: as a fallback, all-implicit names may work as well
514+
if (!creators.hasDefaultCreator()) {
515+
if (implicitCtors == null) {
516+
implicitCtors = new LinkedList<AnnotatedConstructor>();
517+
}
518+
implicitCtors.add(ctor);
519+
}
520+
}
521+
522+
// last option, as per [#725]: consider implicit-names-only, visible constructor,
523+
// if just one found
524+
if ((implicitCtors != null) && !creators.hasDelegatingCreator()
525+
&& !creators.hasPropertyBasedCreator()) {
526+
_checkImplicitlyNamedConstructors(ctxt, beanDesc, vchecker, intr,
527+
creators, implicitCtors);
528+
}
529+
}
530+
531+
protected void _checkImplicitlyNamedConstructors(DeserializationContext ctxt,
532+
BeanDescription beanDesc, VisibilityChecker<?> vchecker,
533+
AnnotationIntrospector intr, CreatorCollector creators,
534+
List<AnnotatedConstructor> implicitCtors) throws JsonMappingException
535+
{
536+
AnnotatedConstructor found = null;
537+
CreatorProperty[] foundProps = null;
538+
539+
// Further checks: (a) must have names for all parameters, (b) only one visible
540+
// Also, since earlier matching of properties and creators relied on existence of
541+
// `@JsonCreator` (or equivalent) annotation, we need to do bit more re-inspection...
542+
543+
main_loop:
544+
for (AnnotatedConstructor ctor : implicitCtors) {
545+
if (!vchecker.isCreatorVisible(ctor)) {
546+
continue;
547+
}
548+
// as per earlier notes, only end up here if no properties associated with creator
549+
550+
final int argCount = ctor.getParameterCount();
551+
CreatorProperty[] properties = new CreatorProperty[argCount];
552+
for (int i = 0; i < argCount; ++i) {
553+
final AnnotatedParameter param = ctor.getParameter(i);
554+
final PropertyName name = _findParamName(param, intr);
555+
556+
// must have name (implicit fine)
557+
if (name == null || name.isEmpty()) {
558+
continue main_loop;
559+
}
560+
properties[i] = constructCreatorProperty(ctxt, beanDesc, name, param.getIndex(),
561+
param, /*injectId*/ null);
562+
}
563+
if (found != null) { // only one allowed
564+
found = null;
565+
break;
566+
}
567+
found = ctor;
568+
foundProps = properties;
569+
}
570+
// found one and only one visible? Ship it!
571+
if (found != null) {
572+
creators.addPropertyCreator(found, /*isCreator*/ false, foundProps);
573+
BasicBeanDescription bbd = (BasicBeanDescription) beanDesc;
574+
// Also: add properties, to keep error messages complete wrt known properties...
575+
for (CreatorProperty prop : foundProps) {
576+
PropertyName pn = prop.getFullName();
577+
if (!bbd.hasProperty(pn)) {
578+
BeanPropertyDefinition newDef = SimpleBeanPropertyDefinition.construct(
579+
ctxt.getConfig(), prop.getMember(), pn);
580+
bbd.addProperty(newDef);
581+
}
508582
}
509583
}
510584
}
@@ -585,15 +659,6 @@ protected boolean _handleSingleArgumentConstructor(DeserializationContext ctxt,
585659
return false;
586660
}
587661

588-
@Deprecated // since 2.5, remove from 2.6
589-
protected void _addDeserializerFactoryMethods(DeserializationContext ctxt, BeanDescription beanDesc, VisibilityChecker<?> vchecker,
590-
AnnotationIntrospector intr, CreatorCollector creators)
591-
throws JsonMappingException
592-
{
593-
_addDeserializerFactoryMethods(ctxt, beanDesc, vchecker, intr, creators,
594-
Collections.<AnnotatedWithParams,BeanPropertyDefinition[]>emptyMap());
595-
}
596-
597662
protected void _addDeserializerFactoryMethods
598663
(DeserializationContext ctxt, BeanDescription beanDesc, VisibilityChecker<?> vchecker,
599664
AnnotationIntrospector intr, CreatorCollector creators,
@@ -805,17 +870,17 @@ protected CreatorProperty constructCreatorProperty(DeserializationContext ctxt,
805870
}
806871
return prop;
807872
}
808-
873+
809874
protected PropertyName _findParamName(AnnotatedParameter param, AnnotationIntrospector intr)
810875
{
811876
if (param != null && intr != null) {
812877
PropertyName name = intr.findNameForDeserialization(param);
813878
if (name != null) {
814879
return name;
815880
}
816-
/* 14-Apr-2014, tatu: Need to also consider possible implicit name
817-
* (for JDK8, or via paranamer)
818-
*/
881+
// 14-Apr-2014, tatu: Need to also consider possible implicit name
882+
// (for JDK8, or via paranamer)
883+
819884
String str = intr.findImplicitPropertyName(param);
820885
if (str != null && !str.isEmpty()) {
821886
return PropertyName.construct(str);
@@ -824,6 +889,7 @@ protected PropertyName _findParamName(AnnotatedParameter param, AnnotationIntros
824889
return null;
825890
}
826891

892+
@Deprecated // in 2.6, remove from 2.7
827893
protected PropertyName _findExplicitParamName(AnnotatedParameter param, AnnotationIntrospector intr)
828894
{
829895
if (param != null && intr != null) {
@@ -832,6 +898,7 @@ protected PropertyName _findExplicitParamName(AnnotatedParameter param, Annotati
832898
return null;
833899
}
834900

901+
@Deprecated // in 2.6, remove from 2.7
835902
protected PropertyName _findImplicitParamName(AnnotatedParameter param, AnnotationIntrospector intr)
836903
{
837904
String str = intr.findImplicitPropertyName(param);
@@ -840,7 +907,8 @@ protected PropertyName _findImplicitParamName(AnnotatedParameter param, Annotati
840907
}
841908
return null;
842909
}
843-
910+
911+
@Deprecated // in 2.6, remove from 2.7
844912
protected boolean _hasExplicitParamName(AnnotatedParameter param, AnnotationIntrospector intr)
845913
{
846914
if (param != null && intr != null) {

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

+1-18
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ public class CreatorProperty
5555
* @since 2.3
5656
*/
5757
protected final SettableBeanProperty _fallbackSetter;
58-
58+
5959
/**
6060
* @param name Name of the logical property
6161
* @param type Type of the property, used to find deserializer
@@ -83,18 +83,6 @@ public CreatorProperty(PropertyName name, JavaType type, PropertyName wrapperNam
8383
_fallbackSetter = null;
8484
}
8585

86-
@Deprecated // since 2.3
87-
public CreatorProperty(String name, JavaType type, PropertyName wrapperName,
88-
TypeDeserializer typeDeser,
89-
Annotations contextAnnotations, AnnotatedParameter param,
90-
int index, Object injectableValueId,
91-
boolean isRequired)
92-
{
93-
this(new PropertyName(name), type, wrapperName, typeDeser,
94-
contextAnnotations, param, index, injectableValueId,
95-
PropertyMetadata.construct(isRequired, null, null, null));
96-
}
97-
9886
/**
9987
* @since 2.3
10088
*/
@@ -106,11 +94,6 @@ protected CreatorProperty(CreatorProperty src, PropertyName newName) {
10694
_fallbackSetter = src._fallbackSetter;
10795
}
10896

109-
@Deprecated // since 2.3
110-
protected CreatorProperty(CreatorProperty src, String newName) {
111-
this(src, new PropertyName(newName));
112-
}
113-
11497
protected CreatorProperty(CreatorProperty src, JsonDeserializer<?> deser) {
11598
super(src, deser);
11699
_annotated = src._annotated;

src/main/java/com/fasterxml/jackson/databind/deser/impl/CreatorCollector.java

+17-9
Original file line numberDiff line numberDiff line change
@@ -56,12 +56,12 @@ public class CreatorCollector
5656
* @since 2.5
5757
*/
5858
protected int _explicitCreators = 0;
59-
59+
6060
protected boolean _hasNonDefaultCreator = false;
61-
61+
6262
// when there are injectable values along with delegate:
6363
protected CreatorProperty[] _delegateArgs;
64-
64+
6565
protected CreatorProperty[] _propertyBasedArgs;
6666

6767
protected AnnotatedParameter _incompleteParameter;
@@ -240,12 +240,6 @@ public void addPropertyCreator(AnnotatedWithParams creator, CreatorProperty[] pr
240240
addPropertyCreator(creator, false, properties);
241241
}
242242

243-
@Deprecated // since 2.5, remove from 2.6
244-
protected AnnotatedWithParams verifyNonDup(AnnotatedWithParams newOne, int typeIndex) {
245-
verifyNonDup(newOne, typeIndex, false);
246-
return _creators[typeIndex];
247-
}
248-
249243
/*
250244
/**********************************************************
251245
/* Accessors
@@ -259,6 +253,20 @@ public boolean hasDefaultCreator() {
259253
return _creators[C_DEFAULT] != null;
260254
}
261255

256+
/**
257+
* @since 2.6
258+
*/
259+
public boolean hasDelegatingCreator() {
260+
return _creators[C_DELEGATE] != null;
261+
}
262+
263+
/**
264+
* @since 2.6
265+
*/
266+
public boolean hasPropertyBasedCreator() {
267+
return _creators[C_PROPS] != null;
268+
}
269+
262270
/*
263271
/**********************************************************
264272
/* Helper methods

0 commit comments

Comments
 (0)