10
10
import com .fasterxml .jackson .databind .*;
11
11
import com .fasterxml .jackson .databind .cfg .DeserializerFactoryConfig ;
12
12
import com .fasterxml .jackson .databind .cfg .HandlerInstantiator ;
13
+ import com .fasterxml .jackson .databind .cfg .MapperConfig ;
13
14
import com .fasterxml .jackson .databind .deser .impl .CreatorCollector ;
14
15
import com .fasterxml .jackson .databind .deser .std .*;
15
16
import com .fasterxml .jackson .databind .ext .OptionalHandlerFactory ;
21
22
import com .fasterxml .jackson .databind .util .ClassUtil ;
22
23
import com .fasterxml .jackson .databind .util .EnumResolver ;
23
24
import com .fasterxml .jackson .databind .util .NameTransformer ;
25
+ import com .fasterxml .jackson .databind .util .SimpleBeanPropertyDefinition ;
24
26
import com .fasterxml .jackson .databind .util .TokenBuffer ;
25
27
26
28
/**
@@ -310,9 +312,12 @@ protected ValueInstantiator _constructDefaultValueInstantiator(DeserializationCo
310
312
* declarations (which are needed to access creator annotation, amongst other things).
311
313
* Easiest to combine that info first, then pass it to remaining processing.
312
314
*/
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
+ */
313
318
Map <AnnotatedWithParams ,BeanPropertyDefinition []> creatorDefs = _findCreatorsFromProperties (ctxt ,
314
319
beanDesc );
315
-
320
+
316
321
/* Important: first add factory methods; then constructors, so
317
322
* latter can override former!
318
323
*/
@@ -337,7 +342,7 @@ protected Map<AnnotatedWithParams,BeanPropertyDefinition[]> _findCreatorsFromPro
337
342
final int index = param .getIndex ();
338
343
339
344
if (defs == null ) {
340
- if (result .isEmpty ()) {
345
+ if (result .isEmpty ()) { // since emptyMap is immutable need to create a 'real' one
341
346
result = new LinkedHashMap <AnnotatedWithParams ,BeanPropertyDefinition []>();
342
347
}
343
348
defs = new BeanPropertyDefinition [owner .getParameterCount ()];
@@ -391,15 +396,6 @@ public ValueInstantiator _valueInstantiatorInstance(DeserializationConfig config
391
396
config .canOverrideAccessModifiers ());
392
397
}
393
398
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
-
403
399
protected void _addDeserializerConstructors
404
400
(DeserializationContext ctxt , BeanDescription beanDesc , VisibilityChecker <?> vchecker ,
405
401
AnnotationIntrospector intr , CreatorCollector creators ,
@@ -415,6 +411,10 @@ protected void _addDeserializerConstructors(DeserializationContext ctxt, BeanDes
415
411
creators .setDefaultCreator (defaultCtor );
416
412
}
417
413
}
414
+
415
+ // may need to keep track for [#725]
416
+ List <AnnotatedConstructor > implicitCtors = null ;
417
+
418
418
for (AnnotatedConstructor ctor : beanDesc .getConstructors ()) {
419
419
final boolean isCreator = intr .hasCreatorAnnotation (ctor );
420
420
BeanPropertyDefinition [] propDefs = creatorParams .get (ctor );
@@ -447,16 +447,21 @@ protected void _addDeserializerConstructors(DeserializationContext ctxt, BeanDes
447
447
}
448
448
449
449
// 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 ;
451
454
CreatorProperty [] properties = new CreatorProperty [argCount ];
452
455
int explicitNameCount = 0 ;
453
- int implicitNameCount = 0 ;
454
- int injectCount = 0 ;
456
+ int implicitWithCreatorCount = 0 ;
457
+ int injectCount = 0 ;
458
+
455
459
for (int i = 0 ; i < argCount ; ++i ) {
456
460
final AnnotatedParameter param = ctor .getParameter (i );
457
461
BeanPropertyDefinition propDef = (propDefs == null ) ? null : propDefs [i ];
458
462
Object injectId = intr .findInjectableValueId (param );
459
463
final PropertyName name = (propDef == null ) ? null : propDef .getFullName ();
464
+
460
465
if (propDef != null && propDef .isExplicitlyNamed ()) {
461
466
++explicitNameCount ;
462
467
properties [i ] = constructCreatorProperty (ctxt , beanDesc , name , i , param , injectId );
@@ -474,29 +479,27 @@ protected void _addDeserializerConstructors(DeserializationContext ctxt, BeanDes
474
479
continue ;
475
480
}
476
481
// 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 ;
483
486
}
484
487
if (nonAnnotatedParam == null ) {
485
488
nonAnnotatedParam = param ;
486
489
}
487
490
}
488
491
489
- final int namedCount = explicitNameCount + implicitNameCount ;
492
+ final int namedCount = explicitNameCount + implicitWithCreatorCount ;
490
493
// 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 ) ) {
492
495
// simple case; everything covered:
493
496
if ((namedCount + injectCount ) == argCount ) {
494
497
creators .addPropertyCreator (ctor , isCreator , properties );
495
498
} 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)
497
500
creators .addDelegatingCreator (ctor , isCreator , properties );
498
501
} 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...
500
503
int ix = nonAnnotatedParam .getIndex ();
501
504
if ((ix == 0 ) && ClassUtil .isNonStaticInnerClass (ctor .getDeclaringClass ())) {
502
505
throw new IllegalArgumentException ("Non-static inner classes like "
@@ -505,6 +508,77 @@ protected void _addDeserializerConstructors(DeserializationContext ctxt, BeanDes
505
508
throw new IllegalArgumentException ("Argument #" +ix
506
509
+" of constructor " +ctor +" has no property name annotation; must have name when multiple-parameter constructor annotated as Creator" );
507
510
}
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
+ }
508
582
}
509
583
}
510
584
}
@@ -585,15 +659,6 @@ protected boolean _handleSingleArgumentConstructor(DeserializationContext ctxt,
585
659
return false ;
586
660
}
587
661
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
-
597
662
protected void _addDeserializerFactoryMethods
598
663
(DeserializationContext ctxt , BeanDescription beanDesc , VisibilityChecker <?> vchecker ,
599
664
AnnotationIntrospector intr , CreatorCollector creators ,
@@ -805,17 +870,17 @@ protected CreatorProperty constructCreatorProperty(DeserializationContext ctxt,
805
870
}
806
871
return prop ;
807
872
}
808
-
873
+
809
874
protected PropertyName _findParamName (AnnotatedParameter param , AnnotationIntrospector intr )
810
875
{
811
876
if (param != null && intr != null ) {
812
877
PropertyName name = intr .findNameForDeserialization (param );
813
878
if (name != null ) {
814
879
return name ;
815
880
}
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
+
819
884
String str = intr .findImplicitPropertyName (param );
820
885
if (str != null && !str .isEmpty ()) {
821
886
return PropertyName .construct (str );
@@ -824,6 +889,7 @@ protected PropertyName _findParamName(AnnotatedParameter param, AnnotationIntros
824
889
return null ;
825
890
}
826
891
892
+ @ Deprecated // in 2.6, remove from 2.7
827
893
protected PropertyName _findExplicitParamName (AnnotatedParameter param , AnnotationIntrospector intr )
828
894
{
829
895
if (param != null && intr != null ) {
@@ -832,6 +898,7 @@ protected PropertyName _findExplicitParamName(AnnotatedParameter param, Annotati
832
898
return null ;
833
899
}
834
900
901
+ @ Deprecated // in 2.6, remove from 2.7
835
902
protected PropertyName _findImplicitParamName (AnnotatedParameter param , AnnotationIntrospector intr )
836
903
{
837
904
String str = intr .findImplicitPropertyName (param );
@@ -840,7 +907,8 @@ protected PropertyName _findImplicitParamName(AnnotatedParameter param, Annotati
840
907
}
841
908
return null ;
842
909
}
843
-
910
+
911
+ @ Deprecated // in 2.6, remove from 2.7
844
912
protected boolean _hasExplicitParamName (AnnotatedParameter param , AnnotationIntrospector intr )
845
913
{
846
914
if (param != null && intr != null ) {
0 commit comments