@@ -554,6 +554,7 @@ private static void parseObject(final ParseContext context, ObjectMapper mapper,
554554                    throw  new  StrictDynamicMappingException (dynamic .name ().toLowerCase (Locale .ROOT ), mapper .fullPath (), currentFieldName );
555555                case  TRUE :
556556                case  STRICT_ALLOW_TEMPLATES :
557+                 case  FALSE_ALLOW_TEMPLATES :
557558                    Mapper .Builder  builder  = findTemplateBuilder (
558559                        context ,
559560                        currentFieldName ,
@@ -563,6 +564,10 @@ private static void parseObject(final ParseContext context, ObjectMapper mapper,
563564                    );
564565
565566                    if  (builder  == null ) {
567+                         if  (dynamic  == ObjectMapper .Dynamic .FALSE_ALLOW_TEMPLATES ) {
568+                             context .parser ().skipChildren ();
569+                             break ;
570+                         }
566571                        builder  = new  ObjectMapper .Builder (currentFieldName ).enabled (true );
567572                    }
568573                    Mapper .BuilderContext  builderContext  = new  Mapper .BuilderContext (context .indexSettings ().getSettings (), context .path ());
@@ -614,6 +619,7 @@ private static void parseArray(ParseContext context, ObjectMapper parentMapper,
614619                        );
615620                    case  TRUE :
616621                    case  STRICT_ALLOW_TEMPLATES :
622+                     case  FALSE_ALLOW_TEMPLATES :
617623                        Mapper .Builder  builder  = findTemplateBuilder (
618624                            context ,
619625                            arrayFieldName ,
@@ -622,6 +628,10 @@ private static void parseArray(ParseContext context, ObjectMapper parentMapper,
622628                            parentMapper .fullPath ()
623629                        );
624630                        if  (builder  == null ) {
631+                             if  (dynamic  == ObjectMapper .Dynamic .FALSE_ALLOW_TEMPLATES ) {
632+                                 context .parser ().skipChildren ();
633+                                 break ;
634+                             }
625635                            parseNonDynamicArray (context , parentMapper , lastFieldName , arrayFieldName );
626636                        } else  {
627637                            Mapper .BuilderContext  builderContext  = new  Mapper .BuilderContext (
@@ -786,13 +796,13 @@ private static Mapper.Builder<?> createBuilderFromDynamicValue(
786796            if  (parseableAsLong  && context .root ().numericDetection ()) {
787797                Mapper .Builder  builder  = findTemplateBuilder (context , currentFieldName , XContentFieldType .LONG , dynamic , fullPath );
788798                if  (builder  == null ) {
789-                     builder  =  newLongBuilder (currentFieldName , context .indexSettings ().getSettings ());
799+                     return   handleNoTemplateFound ( dynamic , () ->  newLongBuilder (currentFieldName , context .indexSettings ().getSettings () ));
790800                }
791801                return  builder ;
792802            } else  if  (parseableAsDouble  && context .root ().numericDetection ()) {
793803                Mapper .Builder  builder  = findTemplateBuilder (context , currentFieldName , XContentFieldType .DOUBLE , dynamic , fullPath );
794804                if  (builder  == null ) {
795-                     builder  =  newFloatBuilder (currentFieldName , context .indexSettings ().getSettings ());
805+                     return   handleNoTemplateFound ( dynamic , () ->  newFloatBuilder (currentFieldName , context .indexSettings ().getSettings () ));
796806                }
797807                return  builder ;
798808            } else  if  (parseableAsLong  == false  && parseableAsDouble  == false  && context .root ().dateDetection ()) {
@@ -808,14 +818,16 @@ private static Mapper.Builder<?> createBuilderFromDynamicValue(
808818                    }
809819                    Mapper .Builder  builder  = findTemplateBuilder (context , currentFieldName , dateTimeFormatter , dynamic , fullPath );
810820                    if  (builder  == null ) {
811-                         boolean  ignoreMalformed  = IGNORE_MALFORMED_SETTING .get (context .indexSettings ().getSettings ());
812-                         builder  = new  DateFieldMapper .Builder (
813-                             currentFieldName ,
814-                             DateFieldMapper .Resolution .MILLISECONDS ,
815-                             dateTimeFormatter ,
816-                             ignoreMalformed ,
817-                             IndexMetadata .indexCreated (context .indexSettings ().getSettings ())
818-                         );
821+                         return  handleNoTemplateFound (dynamic , () -> {
822+                             boolean  ignoreMalformed  = IGNORE_MALFORMED_SETTING .get (context .indexSettings ().getSettings ());
823+                             return  new  DateFieldMapper .Builder (
824+                                 currentFieldName ,
825+                                 DateFieldMapper .Resolution .MILLISECONDS ,
826+                                 dateTimeFormatter ,
827+                                 ignoreMalformed ,
828+                                 IndexMetadata .indexCreated (context .indexSettings ().getSettings ())
829+                             );
830+                         });
819831                    }
820832                    return  builder ;
821833
@@ -824,8 +836,11 @@ private static Mapper.Builder<?> createBuilderFromDynamicValue(
824836
825837            Mapper .Builder  builder  = findTemplateBuilder (context , currentFieldName , XContentFieldType .STRING , dynamic , fullPath );
826838            if  (builder  == null ) {
827-                 builder  = new  TextFieldMapper .Builder (currentFieldName , context .mapperService ().getIndexAnalyzers ()).addMultiField (
828-                     new  KeywordFieldMapper .Builder ("keyword" ).ignoreAbove (256 )
839+                 return  handleNoTemplateFound (
840+                     dynamic ,
841+                     () -> new  TextFieldMapper .Builder (currentFieldName , context .mapperService ().getIndexAnalyzers ()).addMultiField (
842+                         new  KeywordFieldMapper .Builder ("keyword" ).ignoreAbove (256 )
843+                     )
829844                );
830845            }
831846            return  builder ;
@@ -836,7 +851,7 @@ private static Mapper.Builder<?> createBuilderFromDynamicValue(
836851                || numberType  == XContentParser .NumberType .BIG_INTEGER ) {
837852                Mapper .Builder  builder  = findTemplateBuilder (context , currentFieldName , XContentFieldType .LONG , dynamic , fullPath );
838853                if  (builder  == null ) {
839-                     builder  =  newLongBuilder (currentFieldName , context .indexSettings ().getSettings ());
854+                     return   handleNoTemplateFound ( dynamic , () ->  newLongBuilder (currentFieldName , context .indexSettings ().getSettings () ));
840855                }
841856                return  builder ;
842857            } else  if  (numberType  == XContentParser .NumberType .FLOAT 
@@ -847,34 +862,48 @@ private static Mapper.Builder<?> createBuilderFromDynamicValue(
847862                        // no templates are defined, we use float by default instead of double 
848863                        // since this is much more space-efficient and should be enough most of 
849864                        // the time 
850-                         builder  = newFloatBuilder (currentFieldName , context .indexSettings ().getSettings ());
865+                         return  handleNoTemplateFound (
866+                             dynamic ,
867+                             () -> newFloatBuilder (currentFieldName , context .indexSettings ().getSettings ())
868+                         );
851869                    }
852870                    return  builder ;
853871                }
854872        } else  if  (token  == XContentParser .Token .VALUE_BOOLEAN ) {
855873            Mapper .Builder  builder  = findTemplateBuilder (context , currentFieldName , XContentFieldType .BOOLEAN , dynamic , fullPath );
856874            if  (builder  == null ) {
857-                 builder  =  new  BooleanFieldMapper .Builder (currentFieldName );
875+                 return   handleNoTemplateFound ( dynamic , () ->  new  BooleanFieldMapper .Builder (currentFieldName ) );
858876            }
859877            return  builder ;
860878        } else  if  (token  == XContentParser .Token .VALUE_EMBEDDED_OBJECT ) {
861879            Mapper .Builder  builder  = findTemplateBuilder (context , currentFieldName , XContentFieldType .BINARY , dynamic , fullPath );
862880            if  (builder  == null ) {
863-                 builder  =  new  BinaryFieldMapper .Builder (currentFieldName );
881+                 return   handleNoTemplateFound ( dynamic , () ->  new  BinaryFieldMapper .Builder (currentFieldName ) );
864882            }
865883            return  builder ;
866884        } else  {
867885            Mapper .Builder  builder  = findTemplateBuilder (context , currentFieldName , XContentFieldType .STRING , dynamic , fullPath );
868886            if  (builder  != null ) {
869887                return  builder ;
870888            }
889+             return  handleNoTemplateFound (dynamic , () -> null );
871890        }
872891        // TODO how do we identify dynamically that its a binary value? 
873892        throw  new  IllegalStateException (
874893            "Can't handle serializing a dynamic type with content token ["  + token  + "] and field name ["  + currentFieldName  + "]" 
875894        );
876895    }
877896
897+     private  static  Mapper .Builder <?> handleNoTemplateFound (
898+         ObjectMapper .Dynamic  dynamic ,
899+         java .util .function .Supplier <Mapper .Builder <?>> builderSupplier 
900+     ) {
901+         if  (dynamic  == ObjectMapper .Dynamic .FALSE_ALLOW_TEMPLATES ) {
902+             return  null ;
903+         }
904+         return  builderSupplier .get ();
905+     }
906+ 
878907    private  static  void  parseDynamicValue (
879908        final  ParseContext  context ,
880909        ObjectMapper  parentMapper ,
@@ -888,8 +917,16 @@ private static void parseDynamicValue(
888917        if  (dynamic  == ObjectMapper .Dynamic .FALSE ) {
889918            return ;
890919        }
891-         final  Mapper .BuilderContext  builderContext  = new  Mapper .BuilderContext (context .indexSettings ().getSettings (), context .path ());
892920        final  Mapper .Builder <?> builder  = createBuilderFromDynamicValue (context , token , currentFieldName , dynamic , parentMapper .fullPath ());
921+         if  (dynamic  == ObjectMapper .Dynamic .FALSE_ALLOW_TEMPLATES  && builder  == null ) {
922+             // For FALSE_ALLOW_TEMPLATES, if no template matches, we still need to consume the token 
923+             // to maintain proper JSON parsing state 
924+             if  (token  == XContentParser .Token .START_OBJECT  || token  == XContentParser .Token .START_ARRAY ) {
925+                 context .parser ().skipChildren ();
926+             }
927+             return ;
928+         }
929+         final  Mapper .BuilderContext  builderContext  = new  Mapper .BuilderContext (context .indexSettings ().getSettings (), context .path ());
893930        Mapper  mapper  = builder .build (builderContext );
894931        context .addDynamicMapper (mapper );
895932
@@ -978,8 +1015,9 @@ private static Tuple<Integer, ObjectMapper> getDynamicParentMapper(
9781015                switch  (dynamic ) {
9791016                    case  STRICT :
9801017                        throw  new  StrictDynamicMappingException (dynamic .name ().toLowerCase (Locale .ROOT ), parent .fullPath (), paths [i ]);
981-                     case  STRICT_ALLOW_TEMPLATES :
9821018                    case  TRUE :
1019+                     case  STRICT_ALLOW_TEMPLATES :
1020+                     case  FALSE_ALLOW_TEMPLATES :
9831021                        Mapper .Builder  builder  = findTemplateBuilder (
9841022                            context ,
9851023                            paths [i ],
@@ -988,6 +1026,9 @@ private static Tuple<Integer, ObjectMapper> getDynamicParentMapper(
9881026                            parent .fullPath ()
9891027                        );
9901028                        if  (builder  == null ) {
1029+                             if  (dynamic  == ObjectMapper .Dynamic .FALSE_ALLOW_TEMPLATES ) {
1030+                                 return  new  Tuple <>(pathsAdded , parent );
1031+                             }
9911032                            builder  = new  ObjectMapper .Builder (paths [i ]).enabled (true );
9921033                        }
9931034                        Mapper .BuilderContext  builderContext  = new  Mapper .BuilderContext (
0 commit comments