From ccea54cf8d4b2306e23a496e7f7c28fa9b76ef25 Mon Sep 17 00:00:00 2001 From: Aziem Chawdhary <61746398+aziemchawdhary-gs@users.noreply.github.com> Date: Tue, 11 Jun 2024 23:14:16 +0100 Subject: [PATCH] External Formats: Add support for serialization/deserialization config (#2875) * Add internelize/externalize with config * Exec plan changes to support external format config * External formats json with config * Fix externalize processer handling of config param * Stop preeval for external format configs * Add test * Fix internalize processor of config param * Fix typo in doc * Fix test * Handle configs from variables * Add more tests --- .../executionPlan_generation.pure | 29 +++++- .../pure/binding/functions/functions.pure | 54 +++++++++++- .../core/pure/router/preeval/preeval.pure | 2 + ...internalizeExternalizeWithContentType.pure | 88 +++++++++++++++++++ .../functions/functions.pure | 15 ++++ .../metamodel/externalizeConfig.pure | 2 +- 6 files changed, 185 insertions(+), 5 deletions(-) diff --git a/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/binding/executionPlan/executionPlan_generation.pure b/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/binding/executionPlan/executionPlan_generation.pure index 1bbfb7595a8..daba5b5336f 100644 --- a/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/binding/executionPlan/executionPlan_generation.pure +++ b/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/binding/executionPlan/executionPlan_generation.pure @@ -106,6 +106,15 @@ function <> meta::external::format::shared::executionPlan::exter let inScopeVars = $state.inScopeVars; + let config = if($parameters->size() == 4, + | $parameters->at(3)->byPassValueSpecificationWrapper()->match([ + v:VariableExpression[1] | $inScopeVars->get($v.name).values->cast(@meta::external::format::shared::ExternalFormatExternalizeConfig)->toOne(), + i:InstanceValue[1] | $i.values->cast(@meta::external::format::shared::ExternalFormatExternalizeConfig)->toOne(), + a:Any[*] | [] // TODO: default config or error? + ]), + | []); + + let tree = $parameters->at(2)->byPassValueSpecificationWrapper()->match([ v:VariableExpression[1] | $inScopeVars->get($v.name).values->cast(@RootGraphFetchTree)->toOne(), i:InstanceValue[1] | $i.values->cast(@RootGraphFetchTree)->toOne(), @@ -138,7 +147,8 @@ function <> meta::external::format::shared::executionPlan::exter checked = $checked, binding = $binding, tree = $tree, - executionNodes = $children + executionNodes = $children, + config = $config ); } @@ -170,6 +180,13 @@ function <> meta::external::format::shared::executionPlan::inter let enableConstraints = $state.exeCtx.enableConstraints->isEmpty() || $state.exeCtx.enableConstraints->toOne(); let bindingArg = $fe.parametersValues->at(1); let inScopeVars = $state.inScopeVars; + let config = if($fe.parametersValues->size()==4, + | $fe.parametersValues->at(3)->byPassValueSpecificationWrapper()->match([ + v:VariableExpression[1] | $inScopeVars->get($v.name).values->cast(@meta::external::format::shared::ExternalFormatInternalizeConfig)->toOne(), + i:InstanceValue[1] | $i.values->cast(@meta::external::format::shared::ExternalFormatInternalizeConfig)->toOne(), + a:Any[*] | [] // TODO: default config or error? + ]), + | []); let classArg = $fe.parametersValues->at(0); assert($classArg->instanceOf(InstanceValue), 'Only literal class is supported'); @@ -184,6 +201,7 @@ function <> meta::external::format::shared::executionPlan::inter ^ExternalFormatInternalizeExecutionNode ( resultType = ^ClassResultType(type=$class), + config = $config, resultSizeRange = ZeroMany, binding = $binding, enableConstraints = $enableConstraints, @@ -262,7 +280,12 @@ function <> meta::external::format::shared::executionPlan::getFu ^PureFunctionToProcessFunctionPair(first = meta::external::format::shared::functions::internalize_Class_1__Binding_1__String_1__T_MANY_, second = internalizeFunctionProcessor_FunctionExpression_1__ExternalFormatPlanGenerationState_1__Extension_MANY__DebugContext_1__ExecutionNode_1_), ^PureFunctionToProcessFunctionPair(first = meta::external::format::shared::functions::internalize_Class_1__Binding_1__Byte_MANY__T_MANY_, second = internalizeFunctionProcessor_FunctionExpression_1__ExternalFormatPlanGenerationState_1__Extension_MANY__DebugContext_1__ExecutionNode_1_), ^PureFunctionToProcessFunctionPair(first = meta::external::format::shared::functions::internalize_Class_1__String_1__String_1__T_MANY_, second = internalizeFunctionProcessor_FunctionExpression_1__ExternalFormatPlanGenerationState_1__Extension_MANY__DebugContext_1__ExecutionNode_1_), - ^PureFunctionToProcessFunctionPair(first = meta::external::format::shared::functions::internalize_Class_1__String_1__Byte_MANY__T_MANY_, second = internalizeFunctionProcessor_FunctionExpression_1__ExternalFormatPlanGenerationState_1__Extension_MANY__DebugContext_1__ExecutionNode_1_) + ^PureFunctionToProcessFunctionPair(first = meta::external::format::shared::functions::internalize_Class_1__String_1__Byte_MANY__T_MANY_, second = internalizeFunctionProcessor_FunctionExpression_1__ExternalFormatPlanGenerationState_1__Extension_MANY__DebugContext_1__ExecutionNode_1_), + + ^PureFunctionToProcessFunctionPair(first = meta::external::format::shared::functions::internalize_Class_1__Binding_1__String_1__ExternalFormatInternalizeConfig_1__T_MANY_, second = internalizeFunctionProcessor_FunctionExpression_1__ExternalFormatPlanGenerationState_1__Extension_MANY__DebugContext_1__ExecutionNode_1_), + ^PureFunctionToProcessFunctionPair(first = meta::external::format::shared::functions::internalize_Class_1__Binding_1__Byte_MANY__ExternalFormatInternalizeConfig_1__T_MANY_, second = internalizeFunctionProcessor_FunctionExpression_1__ExternalFormatPlanGenerationState_1__Extension_MANY__DebugContext_1__ExecutionNode_1_), + ^PureFunctionToProcessFunctionPair(first = meta::external::format::shared::functions::internalize_Class_1__String_1__String_1__ExternalFormatInternalizeConfig_1__T_MANY_, second = internalizeFunctionProcessor_FunctionExpression_1__ExternalFormatPlanGenerationState_1__Extension_MANY__DebugContext_1__ExecutionNode_1_), + ^PureFunctionToProcessFunctionPair(first = meta::external::format::shared::functions::internalize_Class_1__String_1__Byte_MANY__ExternalFormatInternalizeConfig_1__T_MANY_, second = internalizeFunctionProcessor_FunctionExpression_1__ExternalFormatPlanGenerationState_1__Extension_MANY__DebugContext_1__ExecutionNode_1_) ]; } @@ -271,6 +294,8 @@ function <> meta::external::format::shared::executionPlan::getFu [ ^PureFunctionToProcessFunctionPair(first = meta::external::format::shared::functions::externalize_T_MANY__Binding_1__RootGraphFetchTree_1__String_1_, second = externalizeFunctionProcessor_FunctionExpression_1__ExternalFormatPlanGenerationState_1__Extension_MANY__DebugContext_1__ExecutionNode_1_), ^PureFunctionToProcessFunctionPair(first = meta::external::format::shared::functions::externalize_T_MANY__String_1__RootGraphFetchTree_1__String_1_, second = externalizeFunctionProcessor_FunctionExpression_1__ExternalFormatPlanGenerationState_1__Extension_MANY__DebugContext_1__ExecutionNode_1_), + ^PureFunctionToProcessFunctionPair(first = meta::external::format::shared::functions::externalize_T_MANY__Binding_1__RootGraphFetchTree_1__ExternalFormatExternalizeConfig_1__String_1_, second = externalizeFunctionProcessor_FunctionExpression_1__ExternalFormatPlanGenerationState_1__Extension_MANY__DebugContext_1__ExecutionNode_1_), + ^PureFunctionToProcessFunctionPair(first = meta::external::format::shared::functions::externalize_T_MANY__String_1__RootGraphFetchTree_1__ExternalFormatExternalizeConfig_1__String_1_, second = externalizeFunctionProcessor_FunctionExpression_1__ExternalFormatPlanGenerationState_1__Extension_MANY__DebugContext_1__ExecutionNode_1_), ^PureFunctionToProcessFunctionPair(first = meta::pure::graphFetch::execution::graphFetch_T_MANY__RootGraphFetchTree_1__T_MANY_, second = graphFetchFunctionProcessor_FunctionExpression_1__ExternalFormatPlanGenerationState_1__Extension_MANY__DebugContext_1__ExecutionNode_1_), ^PureFunctionToProcessFunctionPair(first = meta::pure::graphFetch::execution::graphFetch_T_MANY__RootGraphFetchTree_1__Integer_1__T_MANY_, second = graphFetchFunctionProcessor_FunctionExpression_1__ExternalFormatPlanGenerationState_1__Extension_MANY__DebugContext_1__ExecutionNode_1_), ^PureFunctionToProcessFunctionPair(first = meta::pure::graphFetch::execution::graphFetchChecked_T_MANY__RootGraphFetchTree_1__Checked_MANY_, second = graphFetchFunctionProcessor_FunctionExpression_1__ExternalFormatPlanGenerationState_1__Extension_MANY__DebugContext_1__ExecutionNode_1_), diff --git a/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/binding/functions/functions.pure b/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/binding/functions/functions.pure index a91d66847af..0581cab57fd 100644 --- a/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/binding/functions/functions.pure +++ b/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/binding/functions/functions.pure @@ -29,40 +29,84 @@ function <> meta::external::format::shared::functions::externalize(collection: T[*], binding:Binding[1], graphFetchTree: RootGraphFetchTree[1], config:meta::external::format::shared::ExternalFormatExternalizeConfig[1]):String[1] +{ + fail('Implemented by execution plans'); + 'Not impemented!'; +} + function <> meta::external::format::shared::functions::externalize(collection: T[*], contentType:String[1], graphFetchTree: RootGraphFetchTree[1]):String[1] { fail('Implemented by execution plans'); 'Not impemented!'; } +function <> meta::external::format::shared::functions::externalize(collection: T[*], contentType:String[1], graphFetchTree: RootGraphFetchTree[1], config:meta::external::format::shared::ExternalFormatExternalizeConfig[1]):String[1] +{ + fail('Implemented by execution plans'); + 'Not impemented!'; +} + function <> meta::external::format::shared::functions::internalize(toClass:Class[1], binding:Binding[1], data:String[1]):T[*] { fail('Implemented by execution plans'); []; } + +function <> meta::external::format::shared::functions::internalize(toClass:Class[1], binding:Binding[1], data:String[1], config:meta::external::format::shared::ExternalFormatInternalizeConfig[1]):T[*] +{ + fail('Implemented by execution plans'); + []; +} + function <> meta::external::format::shared::functions::externalize(collection: TabularDataSet[1], contentType:String[1]):String[1] { fail('Implemented by execution plans'); 'Not implemented!'; } + +function <> meta::external::format::shared::functions::externalize(collection: TabularDataSet[1], contentType:String[1], config:meta::external::format::shared::ExternalFormatExternalizeConfig[1]):String[1] +{ + fail('Implemented by execution plans'); + 'Not implemented!'; +} + function <> meta::external::format::shared::functions::internalize(toClass:Class[1], binding:Binding[1], data:Byte[*]):T[*] { fail('Implemented by execution plans'); []; } +function <> meta::external::format::shared::functions::internalize(toClass:Class[1], binding:Binding[1], data:Byte[*], config:meta::external::format::shared::ExternalFormatInternalizeConfig[1]):T[*] +{ + fail('Implemented by execution plans'); + []; +} + function <> meta::external::format::shared::functions::internalize(toClass:Class[1], contentType:String[1], data:String[1]):T[*] { fail('Implemented by execution plans'); []; } +function <> meta::external::format::shared::functions::internalize(toClass:Class[1], contentType:String[1], data:String[1], config:meta::external::format::shared::ExternalFormatInternalizeConfig[1]):T[*] +{ + fail('Implemented by execution plans'); + []; +} + function <> meta::external::format::shared::functions::internalize(toClass:Class[1], contentType:String[1], data:Byte[*]):T[*] { fail('Implemented by execution plans'); []; } +function <> meta::external::format::shared::functions::internalize(toClass:Class[1], contentType:String[1], data:Byte[*], config:meta::external::format::shared::ExternalFormatInternalizeConfig[1]):T[*] +{ + fail('Implemented by execution plans'); + []; +} + function <> meta::external::format::shared::functions::checked(valueTree: RootGraphFetchTree[1], binding: Binding[1]):RootGraphFetchTree>[1] { fail('To be evaluated as part of plan generation only'); @@ -81,7 +125,11 @@ function meta::external::format::shared::functions::internalizeFunctions():Funct internalize_Class_1__Binding_1__String_1__T_MANY_, internalize_Class_1__Binding_1__Byte_MANY__T_MANY_, internalize_Class_1__String_1__String_1__T_MANY_, - internalize_Class_1__String_1__Byte_MANY__T_MANY_ + internalize_Class_1__String_1__Byte_MANY__T_MANY_, + internalize_Class_1__Binding_1__String_1__ExternalFormatInternalizeConfig_1__T_MANY_, + internalize_Class_1__Binding_1__Byte_MANY__ExternalFormatInternalizeConfig_1__T_MANY_, + internalize_Class_1__String_1__String_1__ExternalFormatInternalizeConfig_1__T_MANY_, + internalize_Class_1__String_1__Byte_MANY__ExternalFormatInternalizeConfig_1__T_MANY_ ] } @@ -89,7 +137,9 @@ function meta::external::format::shared::functions::externalizeFunctions():Funct { [ externalize_T_MANY__String_1__RootGraphFetchTree_1__String_1_, - externalize_T_MANY__Binding_1__RootGraphFetchTree_1__String_1_ + externalize_T_MANY__Binding_1__RootGraphFetchTree_1__String_1_, + externalize_T_MANY__String_1__RootGraphFetchTree_1__ExternalFormatExternalizeConfig_1__String_1_, + externalize_T_MANY__Binding_1__RootGraphFetchTree_1__ExternalFormatExternalizeConfig_1__String_1_ ] } diff --git a/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/router/preeval/preeval.pure b/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/router/preeval/preeval.pure index 759cddf99cf..7de2600e5fe 100644 --- a/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/router/preeval/preeval.pure +++ b/legend-engine-core/legend-engine-core-pure/legend-engine-pure-code-compiled-core/src/main/resources/core/pure/router/preeval/preeval.pure @@ -851,6 +851,8 @@ function <> meta::pure::router::preeval::stopPreeval(value : Any p : TdsOlapRank[*]| true, p : TdsOlapAggregation[*]| true, p : meta::pure::graphFetch::execution::AlloySerializationConfig[1]| true, + p : meta::external::format::shared::ExternalFormatExternalizeConfig[1] | true, + p : meta::external::format::shared::ExternalFormatInternalizeConfig[1] | true, f : SimpleFunctionExpression[1]| $f.func->in([letFunction_String_1__T_m__T_m_]), a : Any[*]| $a->type() ->match([ diff --git a/legend-engine-xts-json/legend-engine-xt-json-pure/src/main/resources/core_external_format_json/executionPlan/tests/internalizeExternalizeWithContentType.pure b/legend-engine-xts-json/legend-engine-xt-json-pure/src/main/resources/core_external_format_json/executionPlan/tests/internalizeExternalizeWithContentType.pure index 1f29843b99f..575ad5b1138 100644 --- a/legend-engine-xts-json/legend-engine-xt-json-pure/src/main/resources/core_external_format_json/executionPlan/tests/internalizeExternalizeWithContentType.pure +++ b/legend-engine-xts-json/legend-engine-xt-json-pure/src/main/resources/core_external_format_json/executionPlan/tests/internalizeExternalizeWithContentType.pure @@ -29,6 +29,86 @@ function <> meta::external::format::json::executionPlan::test::withContentType::testSimpleJsonQueryWithConfigIncludeTypeInfo(): Boolean[1] +{ + + let externalizeConfig = ^meta::external::format::json::metamodel::externalize::JsonSchemaExternalizeConfig(typeKeyName='_type', + includeType=true, + includeEnumType=false, + removePropertiesWithNullValues=false, + removePropertiesWithEmptySets=false, + fullyQualifiedTypePath=true + ); + let query = {data:String[1]| Person->fromJson($data)->toJson(#{Person{firstName, lastName}}#, $externalizeConfig)}; + + let result = meta::external::format::json::executionPlan::test::executeJsonSchemaBindingQuery($query, pair('data', '{"firstName": "John", "lastName":"Doe"}')); + + assertEquals('{"_type":"meta::external::format::json::executionPlan::test::withContentType::Person","firstName":"John","lastName":"Doe"}', $result); +} + +function <> meta::external::format::json::executionPlan::test::withContentType::testSimpleJsonQueryWithConfigIncludeTypeInfo2(): Boolean[1] +{ + let internalizeConfig = ^meta::external::format::json::metamodel::internalize::JsonSchemaInternalizeConfig(typeKeyName='_type'); + + let externalizeConfig = ^meta::external::format::json::metamodel::externalize::JsonSchemaExternalizeConfig(typeKeyName='_type', + includeType=true, + includeEnumType=false, + removePropertiesWithNullValues=false, + removePropertiesWithEmptySets=false, + fullyQualifiedTypePath=true + ); + + let query = {data:String[1]| Person + ->fromJson($data, $internalizeConfig) + ->toJson(#{Person{firstName, lastName}}#, $externalizeConfig)}; + + let result = meta::external::format::json::executionPlan::test::executeJsonSchemaBindingQuery($query, pair('data', '{"_type": "meta::external::format::json::executionPlan::test::withContentType::Person","firstName": "John", "lastName":"Doe"}')); + assertEquals('{"_type":"meta::external::format::json::executionPlan::test::withContentType::Person","firstName":"John","lastName":"Doe"}', $result); + + let resultWithNonQualifiedTypePath = meta::external::format::json::executionPlan::test::executeJsonSchemaBindingQuery($query, pair('data', '{"_type": "Person","firstName": "John", "lastName":"Doe"}')); + assertEquals('{"_type":"meta::external::format::json::executionPlan::test::withContentType::Person","firstName":"John","lastName":"Doe"}', $resultWithNonQualifiedTypePath); +} + +function <> meta::external::format::json::executionPlan::test::withContentType::testSimpleJsonQueryRemoveEmptyValues(): Boolean[1] +{ + let internalizeConfig = ^meta::external::format::json::metamodel::internalize::JsonSchemaInternalizeConfig(typeKeyName='_type'); + + let externalizeConfig = ^meta::external::format::json::metamodel::externalize::JsonSchemaExternalizeConfig(typeKeyName='_type', + includeType=true, + includeEnumType=false, + removePropertiesWithNullValues=false, + removePropertiesWithEmptySets=true, + fullyQualifiedTypePath=true + ); + + let query = {data:String[1]| Person + ->fromJson($data, $internalizeConfig) + ->toJson(#{Person{firstName, lastName, addresses}}#, $externalizeConfig)}; + + let result = meta::external::format::json::executionPlan::test::executeJsonSchemaBindingQuery($query, pair('data', '{"_type": "meta::external::format::json::executionPlan::test::withContentType::Person","firstName": "John", "lastName":"Doe", "addresses":null}')); + assertEquals('{"_type":"meta::external::format::json::executionPlan::test::withContentType::Person","firstName":"John","lastName":"Doe"}', $result); +} + +function <> meta::external::format::json::executionPlan::test::withContentType::testSimpleJsonQueryRemoveNullValues(): Boolean[1] +{ + let internalizeConfig = ^meta::external::format::json::metamodel::internalize::JsonSchemaInternalizeConfig(typeKeyName='_type'); + + let externalizeConfig = ^meta::external::format::json::metamodel::externalize::JsonSchemaExternalizeConfig(typeKeyName='_type', + includeType=true, + includeEnumType=false, + removePropertiesWithNullValues=true, + removePropertiesWithEmptySets=true, + fullyQualifiedTypePath=true + ); + + let query = {data:String[1]| FuzzyPerson + ->fromJson($data, $internalizeConfig) + ->toJson(#{FuzzyPerson{firstName, lastName, addresses}}#, $externalizeConfig)}; + + let result = meta::external::format::json::executionPlan::test::executeJsonSchemaBindingQuery($query, pair('data', '{"_type": "meta::external::format::json::executionPlan::test::withContentType::FuzzyPerson","firstName": "John", "addresses":null}')); + assertEquals('{"_type":"meta::external::format::json::executionPlan::test::withContentType::FuzzyPerson","firstName":"John"}', $result); +} + function <> meta::external::format::json::executionPlan::test::withContentType::testSimpleJsonQueryWithByte(): Boolean[1] { let query = {data:Byte[*]| Person->fromJson($data)->toJson(#{Person{firstName, lastName}}#)}; @@ -104,6 +184,14 @@ Class meta::external::format::json::executionPlan::test::withContentType::Person addresses : Address[*]; } +Class meta::external::format::json::executionPlan::test::withContentType::FuzzyPerson +{ + firstName : String[0..1]; + lastName : String[0..1]; + firm : Firm[0..1]; + addresses : Address[*]; +} + Class meta::external::format::json::executionPlan::test::withContentType::Firm { legalName : String[1]; diff --git a/legend-engine-xts-json/legend-engine-xt-json-pure/src/main/resources/core_external_format_json/functions/functions.pure b/legend-engine-xts-json/legend-engine-xt-json-pure/src/main/resources/core_external_format_json/functions/functions.pure index 45576ee2758..08cf37387c7 100644 --- a/legend-engine-xts-json/legend-engine-xt-json-pure/src/main/resources/core_external_format_json/functions/functions.pure +++ b/legend-engine-xts-json/legend-engine-xt-json-pure/src/main/resources/core_external_format_json/functions/functions.pure @@ -25,7 +25,22 @@ function <> meta::external::format::json internalize($class, 'application/json', $data) } +function <> meta::external::format::json::functions::fromJson(class:Class[1], data:String[1], config:meta::external::format::json::metamodel::internalize::JsonSchemaInternalizeConfig[1]): T[*] +{ + internalize($class, 'application/json', $data, $config) +} + +function <> meta::external::format::json::functions::fromJson(class:Class[1], data:Byte[*], config:meta::external::format::json::metamodel::internalize::JsonSchemaInternalizeConfig[1]): T[*] +{ + internalize($class, 'application/json', $data, $config) +} + function <> meta::external::format::json::functions::toJson(collection: T[*], graphFetchTree: RootGraphFetchTree[1]): String[1] { externalize($collection, 'application/json', $graphFetchTree) +} + +function <> meta::external::format::json::functions::toJson(collection: T[*], graphFetchTree: RootGraphFetchTree[1], config:meta::external::format::json::metamodel::externalize::JsonSchemaExternalizeConfig[1]): String[1] +{ + externalize($collection, 'application/json', $graphFetchTree, $config) } \ No newline at end of file diff --git a/legend-engine-xts-json/legend-engine-xt-json-pure/src/main/resources/core_external_format_json/metamodel/externalizeConfig.pure b/legend-engine-xts-json/legend-engine-xt-json-pure/src/main/resources/core_external_format_json/metamodel/externalizeConfig.pure index c2c66a7ce90..3ed78bdec22 100644 --- a/legend-engine-xts-json/legend-engine-xt-json-pure/src/main/resources/core_external_format_json/metamodel/externalizeConfig.pure +++ b/legend-engine-xts-json/legend-engine-xt-json-pure/src/main/resources/core_external_format_json/metamodel/externalizeConfig.pure @@ -18,7 +18,7 @@ import meta::external::format::json::metamodel::externalize::*; Class meta::external::format::json::metamodel::externalize::JsonSchemaExternalizeConfig extends ExternalFormatExternalizeConfig { - {doc.doc = 'Give a custom typeKey name. Defaults to @Type'} + {doc.doc = 'Give a custom typeKey name. Defaults to @type'} typeKeyName : String[1] = '@type'; {doc.doc = 'Set to true to include type info of the serialized class'}