88
99package org .elasticsearch .index .mapper ;
1010
11+ import org .elasticsearch .common .logging .DeprecationCategory ;
12+ import org .elasticsearch .common .logging .DeprecationLogger ;
13+ import org .elasticsearch .common .xcontent .ToXContent ;
1114import org .elasticsearch .common .xcontent .ToXContentFragment ;
1215import org .elasticsearch .common .xcontent .XContentBuilder ;
16+ import org .elasticsearch .index .mapper .FieldMapper .Parameter ;
1317
1418import java .io .IOException ;
1519import java .util .Collection ;
@@ -58,51 +62,69 @@ default XContentBuilder toXContent(XContentBuilder builder, Params params) throw
5862 */
5963 Collection <MappedFieldType > asMappedFieldTypes ();
6064
61- /**
62- * For runtime fields the {@link RuntimeField.Parser} returns directly the {@link MappedFieldType}.
63- * Internally we still create a {@link RuntimeField.Builder} so we reuse the {@link FieldMapper.Parameter} infrastructure,
64- * but {@link RuntimeField.Builder#init(FieldMapper)} and {@link RuntimeField.Builder#build(ContentPath)} are never called as
65- * {@link RuntimeField.Parser#parse(String, Map, Mapper.TypeParser.ParserContext)} calls
66- * {@link RuntimeField.Builder#parse(String, Mapper.TypeParser.ParserContext, Map)} and returns the corresponding
67- * {@link MappedFieldType}.
68- */
69- abstract class Builder extends FieldMapper .Builder {
70- final FieldMapper .Parameter <Map <String , String >> meta = FieldMapper .Parameter .metaParam ();
65+ abstract class Builder implements ToXContent {
66+ final String name ;
67+ final Parameter <Map <String , String >> meta = Parameter .metaParam ();
68+
69+ private static final DeprecationLogger deprecationLogger = DeprecationLogger .getLogger (RuntimeField .class );
7170
7271 protected Builder (String name ) {
73- super ( name ) ;
72+ this . name = name ;
7473 }
7574
7675 public Map <String , String > meta () {
7776 return meta .getValue ();
7877 }
7978
80- @ Override
81- protected List <FieldMapper .Parameter <?>> getParameters () {
79+ protected List <Parameter <?>> getParameters () {
8280 return Collections .singletonList (meta );
8381 }
8482
85- @ Override
86- public FieldMapper .Builder init (FieldMapper initializer ) {
87- throw new UnsupportedOperationException ();
88- }
83+ protected abstract RuntimeField createRuntimeField (Mapper .TypeParser .ParserContext parserContext );
8984
9085 @ Override
91- public final FieldMapper build (ContentPath context ) {
92- throw new UnsupportedOperationException ();
86+ public final XContentBuilder toXContent (XContentBuilder builder , Params params ) throws IOException {
87+ boolean includeDefaults = params .paramAsBoolean ("include_defaults" , false );
88+ for (Parameter <?> parameter : getParameters ()) {
89+ parameter .toXContent (builder , includeDefaults );
90+ }
91+ return builder ;
9392 }
9493
95- protected abstract RuntimeField createRuntimeField (Mapper .TypeParser .ParserContext parserContext );
96-
97- private void validate () {
98- ContentPath contentPath = parentPath (name ());
99- FieldMapper .MultiFields multiFields = multiFieldsBuilder .build (this , contentPath );
100- if (multiFields .iterator ().hasNext ()) {
101- throw new IllegalArgumentException ("runtime field [" + name + "] does not support [fields]" );
94+ public final void parse (String name , Mapper .TypeParser .ParserContext parserContext , Map <String , Object > fieldNode ) {
95+ Map <String , Parameter <?>> paramsMap = new HashMap <>();
96+ for (Parameter <?> param : getParameters ()) {
97+ paramsMap .put (param .name , param );
10298 }
103- FieldMapper .CopyTo copyTo = this .copyTo .build ();
104- if (copyTo .copyToFields ().isEmpty () == false ) {
105- throw new IllegalArgumentException ("runtime field [" + name + "] does not support [copy_to]" );
99+ String type = (String ) fieldNode .remove ("type" );
100+ for (Iterator <Map .Entry <String , Object >> iterator = fieldNode .entrySet ().iterator (); iterator .hasNext ();) {
101+ Map .Entry <String , Object > entry = iterator .next ();
102+ final String propName = entry .getKey ();
103+ final Object propNode = entry .getValue ();
104+ Parameter <?> parameter = paramsMap .get (propName );
105+ if (parameter == null ) {
106+ if (parserContext .isFromDynamicTemplate ()) {
107+ // The parameter is unknown, but this mapping is from a dynamic template.
108+ // Until 7.x it was possible to use unknown parameters there, so for bwc we need to ignore it
109+ deprecationLogger .deprecate (DeprecationCategory .API , propName ,
110+ "Parameter [{}] is used in a dynamic template mapping and has no effect on type [{}]. "
111+ + "Usage will result in an error in future major versions and should be removed." ,
112+ propName ,
113+ type
114+ );
115+ iterator .remove ();
116+ continue ;
117+ }
118+ throw new MapperParsingException (
119+ "unknown parameter [" + propName + "] on runtime field [" + name + "] of type [" + type + "]"
120+ );
121+ }
122+ if (propNode == null && parameter .canAcceptNull () == false ) {
123+ throw new MapperParsingException ("[" + propName + "] on runtime field [" + name
124+ + "] of type [" + type + "] must not have a [null] value" );
125+ }
126+ parameter .parse (name , parserContext , propNode );
127+ iterator .remove ();
106128 }
107129 }
108130 }
@@ -123,7 +145,6 @@ RuntimeField parse(String name, Map<String, Object> node, Mapper.TypeParser.Pars
123145
124146 RuntimeField .Builder builder = builderFunction .apply (name );
125147 builder .parse (name , parserContext , node );
126- builder .validate ();
127148 return builder .createRuntimeField (parserContext );
128149 }
129150 }
0 commit comments