@@ -336,17 +336,14 @@ protected void collectAll()
336336 _renameUsing (props , naming );
337337 }
338338
339- /* Sort by visibility (explicit over implicit); drop all but first
340- * of member type (getter, setter etc) if there is visibility
341- * difference
342- */
339+ // Sort by visibility (explicit over implicit); drop all but first of member
340+ // type (getter, setter etc) if there is visibility difference
343341 for (POJOPropertyBuilder property : props .values ()) {
344342 property .trimByVisibility ();
345343 }
346344
347- /* and, if required, apply wrapper name: note, MUST be done after
348- * annotations are merged.
349- */
345+ // and, if required, apply wrapper name: note, MUST be done after
346+ // annotations are merged.
350347 if (_config .isEnabled (MapperFeature .USE_WRAPPER_NAME_AS_PROPERTY_NAME )) {
351348 _renameWithWrappers (props );
352349 }
@@ -933,25 +930,24 @@ protected void _renameWithWrappers(Map<String, POJOPropertyBuilder> props)
933930 /**********************************************************
934931 */
935932
936- /* First, order by [JACKSON-90] (explicit ordering and/or alphabetic)
937- * and then for [JACKSON-170] (implicitly order creator properties before others)
938- */
933+ // First, order by(explicit ordering and/or alphabetic),
934+ // then by (optional) index (if any)
935+ // and then implicitly order creator properties before others)
936+
939937 protected void _sortProperties (Map <String , POJOPropertyBuilder > props )
940938 {
941939 // Then how about explicit ordering?
942- AnnotationIntrospector intr = _annotationIntrospector ;
940+ final AnnotationIntrospector intr = _annotationIntrospector ;
943941 Boolean alpha = intr .findSerializationSortAlphabetically ((Annotated ) _classDef );
944- boolean sort ;
945-
946- if (alpha == null ) {
947- sort = _config .shouldSortPropertiesAlphabetically ();
948- } else {
949- sort = alpha .booleanValue ();
950- }
942+ final boolean sort = (alpha == null )
943+ ? _config .shouldSortPropertiesAlphabetically ()
944+ : alpha .booleanValue ();
945+ final boolean indexed = _anyIndexed (props .values ());
946+
951947 String [] propertyOrder = intr .findSerializationPropertyOrder (_classDef );
952948
953949 // no sorting? no need to shuffle, then
954- if (!sort && (_creatorProperties == null ) && (propertyOrder == null )) {
950+ if (!sort && ! indexed && (_creatorProperties == null ) && (propertyOrder == null )) {
955951 return ;
956952 }
957953 int size = props .size ();
@@ -966,11 +962,11 @@ protected void _sortProperties(Map<String, POJOPropertyBuilder> props)
966962 for (POJOPropertyBuilder prop : props .values ()) {
967963 all .put (prop .getName (), prop );
968964 }
969- Map <String ,POJOPropertyBuilder > ordered = new LinkedHashMap <String , POJOPropertyBuilder >(size +size );
965+ Map <String ,POJOPropertyBuilder > ordered = new LinkedHashMap <>(size +size );
970966 // Ok: primarily by explicit order
971967 if (propertyOrder != null ) {
972968 for (String name : propertyOrder ) {
973- POJOPropertyBuilder w = all .get (name );
969+ POJOPropertyBuilder w = all .remove (name );
974970 if (w == null ) { // will also allow use of "implicit" names for sorting
975971 for (POJOPropertyBuilder prop : props .values ()) {
976972 if (name .equals (prop .getInternalName ())) {
@@ -986,7 +982,26 @@ protected void _sortProperties(Map<String, POJOPropertyBuilder> props)
986982 }
987983 }
988984 }
989- // And secondly by sorting Creator properties before other unordered properties
985+
986+ // Second (starting with 2.11): index, if any:
987+ if (indexed ) {
988+ Map <Integer ,POJOPropertyBuilder > byIndex = new TreeMap <>();
989+ Iterator <Map .Entry <String ,POJOPropertyBuilder >> it = all .entrySet ().iterator ();
990+ while (it .hasNext ()) {
991+ Map .Entry <String ,POJOPropertyBuilder > entry = it .next ();
992+ POJOPropertyBuilder prop = entry .getValue ();
993+ Integer index = prop .getMetadata ().getIndex ();
994+ if (index != null ) {
995+ byIndex .put (index , prop );
996+ it .remove ();
997+ }
998+ }
999+ for (POJOPropertyBuilder prop : byIndex .values ()) {
1000+ ordered .put (prop .getName (), prop );
1001+ }
1002+ }
1003+
1004+ // Third by sorting Creator properties before other unordered properties
9901005 if (_creatorProperties != null ) {
9911006 /* As per [databind#311], this is bit delicate; but if alphabetic ordering
9921007 * is mandated, at least ensure creator properties are in alphabetic
@@ -1008,6 +1023,8 @@ protected void _sortProperties(Map<String, POJOPropertyBuilder> props)
10081023 // 16-Jan-2016, tatu: Related to [databind#1317], make sure not to accidentally
10091024 // add back pruned creator properties!
10101025 String name = prop .getName ();
1026+ // 27-Nov-2019, tatu: Not sure why, but we should NOT remove it from `all` tho:
1027+ // if (all.remove(name) != null) {
10111028 if (all .containsKey (name )) {
10121029 ordered .put (name , prop );
10131030 }
@@ -1017,7 +1034,16 @@ protected void _sortProperties(Map<String, POJOPropertyBuilder> props)
10171034 ordered .putAll (all );
10181035 props .clear ();
10191036 props .putAll (ordered );
1020- }
1037+ }
1038+
1039+ private boolean _anyIndexed (Collection <POJOPropertyBuilder > props ) {
1040+ for (POJOPropertyBuilder prop : props ) {
1041+ if (prop .getMetadata ().hasIndex ()) {
1042+ return true ;
1043+ }
1044+ }
1045+ return false ;
1046+ }
10211047
10221048 /*
10231049 /**********************************************************
0 commit comments