From b15b83c2557f0d9e08bf1287b36fffbf7640c893 Mon Sep 17 00:00:00 2001 From: chiranSachintha Date: Wed, 12 Mar 2025 17:14:00 +0530 Subject: [PATCH 1/7] Generate JSON schema for union types --- ballerina/main.bal | 7 +-- .../main/java/io/ballerina/lib/np/Native.java | 45 ++++++++++++++++++- 2 files changed, 48 insertions(+), 4 deletions(-) diff --git a/ballerina/main.bal b/ballerina/main.bal index 244ec0f..3e47e24 100644 --- a/ballerina/main.bal +++ b/ballerina/main.bal @@ -87,10 +87,11 @@ isolated function getPromptWithExpectedResponseSchema(string prompt, map e Schema: ${expectedResponseSchema.toJsonString()}`; -isolated function callLlmGeneric(Prompt prompt, Context context, typedesc targetType) returns json|error { +isolated function callLlmGeneric(Prompt prompt, Context context, typedesc targetType, + map? jsonSchema) returns json|error { Model model = context.model; - json resp = - check model->call(buildPromptString(prompt), generateJsonSchemaForTypedescAsJson(targetType)); + json resp = + check model->call(buildPromptString(prompt), jsonSchema ?: generateJsonSchemaForTypedescAsJson(targetType)); return parseResponseAsType(resp, targetType); } diff --git a/native/src/main/java/io/ballerina/lib/np/Native.java b/native/src/main/java/io/ballerina/lib/np/Native.java index 1adea1b..9bb8e5a 100644 --- a/native/src/main/java/io/ballerina/lib/np/Native.java +++ b/native/src/main/java/io/ballerina/lib/np/Native.java @@ -17,10 +17,13 @@ import io.ballerina.runtime.api.Environment; import io.ballerina.runtime.api.Module; +import io.ballerina.runtime.api.creators.TypeCreator; import io.ballerina.runtime.api.creators.ValueCreator; import io.ballerina.runtime.api.flags.SymbolFlags; +import io.ballerina.runtime.api.types.AnnotatableType; import io.ballerina.runtime.api.types.ArrayType; import io.ballerina.runtime.api.types.Field; +import io.ballerina.runtime.api.types.PredefinedTypes; import io.ballerina.runtime.api.types.RecordType; import io.ballerina.runtime.api.types.Type; import io.ballerina.runtime.api.types.TypeTags; @@ -30,8 +33,14 @@ import io.ballerina.runtime.api.values.BArray; import io.ballerina.runtime.api.values.BMap; import io.ballerina.runtime.api.values.BObject; +import io.ballerina.runtime.api.values.BString; import io.ballerina.runtime.api.values.BTypedesc; +import java.util.List; +import java.util.Map; + +import static io.ballerina.runtime.api.creators.ValueCreator.createMapValue; + /** * Native implementation of natural programming functions. * @@ -40,9 +49,43 @@ public class Native { public static Object callLlm(Environment env, BObject prompt, BMap context, BTypedesc targetType) { return env.getRuntime().callFunction( - new Module("ballerinax", "np", "0"), "callLlmGeneric", null, prompt, context, targetType); + new Module("ballerinax", "np", "0"), "callLlmGeneric", null, prompt, context, targetType, + generateJsonSchemaForUnionType(targetType)); + } + + public static Object generateJsonSchemaForUnionType(BTypedesc td) { + Type type = td.getDescribingType(); + + if (type instanceof UnionType bUnionType) { + List memberTypes = bUnionType.getMemberTypes(); + + for (Type bType : memberTypes) { + bType = TypeUtils.getReferredType(bType); + + if (bType instanceof AnnotatableType annotatableType) { + BMap schemaMap = + createMapValue(TypeCreator.createMapType(PredefinedTypes.TYPE_JSON)); + schemaMap.put(StringUtils.fromString("type"), StringUtils.fromString("object")); + BMap annotations = annotatableType.getAnnotations(); + BArray annotationArray = + ValueCreator.createArrayValue(TypeCreator.createArrayType(PredefinedTypes.TYPE_JSON)); + int index = 0; + for (Map.Entry entry : annotations.entrySet()) { + if (entry.getKey().getValue().equals("ballerinax/np:0:Schema")) { + annotationArray.add(index++, entry.getValue()); + } + } + + schemaMap.put(StringUtils.fromString("anyOf"), annotationArray); + return schemaMap; + } + } + } + + return null; } + // Simple, simple, SIMPLE implementation for now. public static void populateFieldInfo(BTypedesc typedesc, BArray names, BArray required, BArray types, BArray nilable) { From b535d5f716e0ae6b65e6ca34c883cda4daa13e6b Mon Sep 17 00:00:00 2001 From: chiranSachintha Date: Thu, 13 Mar 2025 13:49:24 +0530 Subject: [PATCH 2/7] Generate JSON schema dynamically at runtime --- ballerina/main.bal | 3 +- .../PromptAsCodeCodeModificationTask.java | 7 +- gradle.properties | 2 +- .../main/java/io/ballerina/lib/np/Native.java | 103 +++++++++++++----- 4 files changed, 79 insertions(+), 36 deletions(-) diff --git a/ballerina/main.bal b/ballerina/main.bal index 3e47e24..ce76502 100644 --- a/ballerina/main.bal +++ b/ballerina/main.bal @@ -90,8 +90,7 @@ isolated function getPromptWithExpectedResponseSchema(string prompt, map e isolated function callLlmGeneric(Prompt prompt, Context context, typedesc targetType, map? jsonSchema) returns json|error { Model model = context.model; - json resp = - check model->call(buildPromptString(prompt), jsonSchema ?: generateJsonSchemaForTypedescAsJson(targetType)); + json resp = check model->call(buildPromptString(prompt), jsonSchema ?: {}); return parseResponseAsType(resp, targetType); } diff --git a/compiler-plugin/src/main/java/io/ballerina/lib/np/compilerplugin/PromptAsCodeCodeModificationTask.java b/compiler-plugin/src/main/java/io/ballerina/lib/np/compilerplugin/PromptAsCodeCodeModificationTask.java index 1cb01ff..340f6db 100644 --- a/compiler-plugin/src/main/java/io/ballerina/lib/np/compilerplugin/PromptAsCodeCodeModificationTask.java +++ b/compiler-plugin/src/main/java/io/ballerina/lib/np/compilerplugin/PromptAsCodeCodeModificationTask.java @@ -442,17 +442,16 @@ private void getTypeSchema(TypeSymbol memberType, TypeMapper typeMapper, Map typeSchemas.put(typeReference.definition().getName().get(), getJsonSchema(typeMapper.getSchema(typeReference))); - case ArrayTypeSymbol arrayType -> - getTypeSchema(arrayType.memberTypeDescriptor(), typeMapper, typeSchemas); - + getTypeSchema(arrayType.memberTypeDescriptor(), typeMapper, typeSchemas); case TupleTypeSymbol tupleType -> tupleType.members().forEach(member -> getTypeSchema(member.typeDescriptor(), typeMapper, typeSchemas)); - case RecordTypeSymbol recordType -> recordType.fieldDescriptors().values().forEach(field -> getTypeSchema(field.typeDescriptor(), typeMapper, typeSchemas)); + case UnionTypeSymbol unionTypeSymbol -> unionTypeSymbol.memberTypeDescriptors().forEach(member -> + getTypeSchema(member, typeMapper, typeSchemas)); default -> { } } } diff --git a/gradle.properties b/gradle.properties index 867fc0d..ab41ef9 100644 --- a/gradle.properties +++ b/gradle.properties @@ -14,5 +14,5 @@ downloadPluginVersion=4.0.4 releasePluginVersion=2.8.0 ballerinaGradlePluginVersion=2.3.0 gsonVersion=2.10.1 -ballerinaToOpenApiVersion=2.2.1-20250221-180600-8db6bba +ballerinaToOpenApiVersion=2.3.0 swaggerVersion=2.2.9 diff --git a/native/src/main/java/io/ballerina/lib/np/Native.java b/native/src/main/java/io/ballerina/lib/np/Native.java index 9bb8e5a..4f6f710 100644 --- a/native/src/main/java/io/ballerina/lib/np/Native.java +++ b/native/src/main/java/io/ballerina/lib/np/Native.java @@ -20,11 +20,11 @@ import io.ballerina.runtime.api.creators.TypeCreator; import io.ballerina.runtime.api.creators.ValueCreator; import io.ballerina.runtime.api.flags.SymbolFlags; -import io.ballerina.runtime.api.types.AnnotatableType; import io.ballerina.runtime.api.types.ArrayType; import io.ballerina.runtime.api.types.Field; import io.ballerina.runtime.api.types.PredefinedTypes; import io.ballerina.runtime.api.types.RecordType; +import io.ballerina.runtime.api.types.TupleType; import io.ballerina.runtime.api.types.Type; import io.ballerina.runtime.api.types.TypeTags; import io.ballerina.runtime.api.types.UnionType; @@ -36,7 +36,6 @@ import io.ballerina.runtime.api.values.BString; import io.ballerina.runtime.api.values.BTypedesc; -import java.util.List; import java.util.Map; import static io.ballerina.runtime.api.creators.ValueCreator.createMapValue; @@ -50,41 +49,87 @@ public class Native { public static Object callLlm(Environment env, BObject prompt, BMap context, BTypedesc targetType) { return env.getRuntime().callFunction( new Module("ballerinax", "np", "0"), "callLlmGeneric", null, prompt, context, targetType, - generateJsonSchemaForUnionType(targetType)); + generateJsonSchemaForType(targetType.getDescribingType())); } - public static Object generateJsonSchemaForUnionType(BTypedesc td) { - Type type = td.getDescribingType(); - - if (type instanceof UnionType bUnionType) { - List memberTypes = bUnionType.getMemberTypes(); - - for (Type bType : memberTypes) { - bType = TypeUtils.getReferredType(bType); - - if (bType instanceof AnnotatableType annotatableType) { - BMap schemaMap = - createMapValue(TypeCreator.createMapType(PredefinedTypes.TYPE_JSON)); - schemaMap.put(StringUtils.fromString("type"), StringUtils.fromString("object")); - BMap annotations = annotatableType.getAnnotations(); - BArray annotationArray = - ValueCreator.createArrayValue(TypeCreator.createArrayType(PredefinedTypes.TYPE_JSON)); - int index = 0; - for (Map.Entry entry : annotations.entrySet()) { - if (entry.getKey().getValue().equals("ballerinax/np:0:Schema")) { - annotationArray.add(index++, entry.getValue()); - } - } + public static Object generateJsonSchemaForType(Type td) { + Type type = TypeUtils.getReferredType(td); + if (isSimpleType(type)) { + return createSimpleTypeSchema(type); + } - schemaMap.put(StringUtils.fromString("anyOf"), annotationArray); - return schemaMap; - } - } + return switch (type) { + case RecordType recordType -> generateJsonSchemaForRecordType(recordType); + case ArrayType arrayType -> generateJsonSchemaForArrayType(arrayType); + case TupleType tupleType -> generateJsonSchemaForTupleType(tupleType); + case UnionType unionType -> generateJsonSchemaForUnionType(unionType); + default -> null; + }; + } + + private static BMap createSimpleTypeSchema(Type type) { + BMap schemaMap = createMapValue(TypeCreator.createMapType(PredefinedTypes.TYPE_JSON)); + schemaMap.put(StringUtils.fromString("type"), StringUtils.fromString(getStringRepresentation(type))); + return schemaMap; + } + + private static Object generateJsonSchemaForArrayType(ArrayType arrayType) { + BMap schemaMap = createMapValue(TypeCreator.createMapType(PredefinedTypes.TYPE_JSON)); + Type elementType = TypeUtils.getReferredType(arrayType.getElementType()); + schemaMap.put(StringUtils.fromString("type"), StringUtils.fromString("array")); + schemaMap.put(StringUtils.fromString("items"), generateJsonSchemaForType(elementType)); + return schemaMap; + } + + private static Object generateJsonSchemaForTupleType(TupleType tupleType) { + BMap schemaMap = createMapValue(TypeCreator.createMapType(PredefinedTypes.TYPE_JSON)); + schemaMap.put(StringUtils.fromString("type"), StringUtils.fromString("array")); + BArray annotationArray = ValueCreator.createArrayValue(TypeCreator.createArrayType(PredefinedTypes.TYPE_JSON)); + int index = 0; + for (Type type : tupleType.getTupleTypes()) { + annotationArray.add(index++, generateJsonSchemaForType(type)); } + schemaMap.put(StringUtils.fromString("items"), annotationArray); + return schemaMap; + } + private static boolean isSimpleType(Type type) { + return type.getBasicType().all() <= 0b100000; + } + + private static String getStringRepresentation(Type type) { + return switch (type.getBasicType().all()) { + case 0b000000 -> "null"; + case 0b000010 -> "boolean"; + case 0b000100 -> "integer"; + case 0b001000, 0b010000 -> "number"; + case 0b100000 -> "string"; + default -> null; + }; + } + + private static Object generateJsonSchemaForRecordType(RecordType recordType) { + for (Map.Entry entry : recordType.getAnnotations().entrySet()) { + if ("ballerinax/np:0:Schema".equals(entry.getKey().getValue())) { + return entry.getValue(); + } + } return null; } + private static Object generateJsonSchemaForUnionType(UnionType unionType) { + BMap schemaMap = createMapValue(TypeCreator.createMapType(PredefinedTypes.TYPE_JSON)); + schemaMap.put(StringUtils.fromString("type"), StringUtils.fromString("object")); + BArray annotationArray = ValueCreator.createArrayValue(TypeCreator.createArrayType(PredefinedTypes.TYPE_JSON)); + + int index = 0; + for (Type type : unionType.getMemberTypes()) { + annotationArray.add(index++, generateJsonSchemaForType(type)); + } + + schemaMap.put(StringUtils.fromString("anyOf"), annotationArray); + return schemaMap; + } // Simple, simple, SIMPLE implementation for now. public static void populateFieldInfo(BTypedesc typedesc, BArray names, BArray required, From 4f0bea77e05802d755e8df7e32eaa28a167a307a Mon Sep 17 00:00:00 2001 From: chiranSachintha Date: Thu, 13 Mar 2025 14:28:21 +0530 Subject: [PATCH 3/7] [Automated] Update the native jar versions --- ballerina/Dependencies.toml | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/ballerina/Dependencies.toml b/ballerina/Dependencies.toml index 1d15e94..53742da 100644 --- a/ballerina/Dependencies.toml +++ b/ballerina/Dependencies.toml @@ -5,7 +5,7 @@ [ballerina] dependencies-toml-version = "2" -distribution-version = "2201.12.0-20250226-081700-17d84e0f" +distribution-version = "2201.12.0" [[package]] org = "ballerina" @@ -103,11 +103,14 @@ modules = [ [[package]] org = "ballerina" name = "io" -version = "1.7.0" +version = "1.8.0" dependencies = [ {org = "ballerina", name = "jballerina.java"}, {org = "ballerina", name = "lang.value"} ] +modules = [ + {org = "ballerina", packageName = "io", moduleName = "io"} +] [[package]] org = "ballerina" @@ -253,7 +256,7 @@ dependencies = [ [[package]] org = "ballerina" name = "observe" -version = "1.4.0" +version = "1.5.0" dependencies = [ {org = "ballerina", name = "jballerina.java"} ] @@ -338,6 +341,7 @@ name = "np" version = "0.1.3" dependencies = [ {org = "ballerina", name = "http"}, + {org = "ballerina", name = "io"}, {org = "ballerina", name = "jballerina.java"}, {org = "ballerina", name = "test"}, {org = "ballerinai", name = "observe"}, @@ -351,7 +355,7 @@ modules = [ [[package]] org = "ballerinax" name = "openai.chat" -version = "3.0.1" +version = "3.0.2" dependencies = [ {org = "ballerina", name = "constraint"}, {org = "ballerina", name = "http"}, From c78b2c008175ef6bef7e0283d211b4b7878c56ce Mon Sep 17 00:00:00 2001 From: chiranSachintha Date: Mon, 17 Mar 2025 20:01:41 +0530 Subject: [PATCH 4/7] Generate JSON schema dynamically for np:callLlm --- ballerina/tests/tests.bal | 5 +-- .../PromptAsCodeCodeModificationTask.java | 43 ++++++++++++++++--- 2 files changed, 40 insertions(+), 8 deletions(-) diff --git a/ballerina/tests/tests.bal b/ballerina/tests/tests.bal index 9b3ced8..13e1784 100644 --- a/ballerina/tests/tests.bal +++ b/ballerina/tests/tests.bal @@ -47,11 +47,10 @@ function testJsonConversionError() { test:assertTrue(( rating).message().includes(ERROR_MESSAGE)); } +type Foo record{| string name; |}; @test:Config function testJsonConversionError2() { - record{| - string name; - |}[]|error rating = callLlm(`Tell me name and the age of the top 10 world class cricketers`); + Foo[]|error rating = callLlm(`Tell me name and the age of the top 10 world class cricketers`); test:assertTrue(rating is error); test:assertTrue(( rating).message().includes(ERROR_MESSAGE)); } diff --git a/compiler-plugin/src/main/java/io/ballerina/lib/np/compilerplugin/PromptAsCodeCodeModificationTask.java b/compiler-plugin/src/main/java/io/ballerina/lib/np/compilerplugin/PromptAsCodeCodeModificationTask.java index 340f6db..7d1458a 100644 --- a/compiler-plugin/src/main/java/io/ballerina/lib/np/compilerplugin/PromptAsCodeCodeModificationTask.java +++ b/compiler-plugin/src/main/java/io/ballerina/lib/np/compilerplugin/PromptAsCodeCodeModificationTask.java @@ -110,7 +110,7 @@ public class PromptAsCodeCodeModificationTask implements ModifierTask typeSymbol = + semanticModel.expectedType(document, functionCallExpressionNode.lineRange().startLine()); + if (typeSymbol.isEmpty()) { + return functionCallExpressionNode; + } + getTypeSchema(typeSymbol.get(), analysisData.typeMapper, modifierData.typeSchemas); + return functionCallExpressionNode; + } + } + private static class FunctionModifier extends TreeModifier { private final ModifierData modifierData; @@ -437,7 +470,7 @@ private void extractAndStoreSchemas(SemanticModel semanticModel, FunctionDefinit } } - private void getTypeSchema(TypeSymbol memberType, TypeMapper typeMapper, Map typeSchemas) { + private static void getTypeSchema(TypeSymbol memberType, TypeMapper typeMapper, Map typeSchemas) { switch (memberType) { case TypeReferenceTypeSymbol typeReference -> typeSchemas.put(typeReference.definition().getName().get(), From dae51752f9b6c018ac417bda4df398f98e78fe6c Mon Sep 17 00:00:00 2001 From: chiranSachintha Date: Mon, 17 Mar 2025 20:57:11 +0530 Subject: [PATCH 5/7] Process import declarations and external functions for test documents --- .../np/compilerplugin/PromptAsCodeCodeModificationTask.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/compiler-plugin/src/main/java/io/ballerina/lib/np/compilerplugin/PromptAsCodeCodeModificationTask.java b/compiler-plugin/src/main/java/io/ballerina/lib/np/compilerplugin/PromptAsCodeCodeModificationTask.java index 7d1458a..8c0476b 100644 --- a/compiler-plugin/src/main/java/io/ballerina/lib/np/compilerplugin/PromptAsCodeCodeModificationTask.java +++ b/compiler-plugin/src/main/java/io/ballerina/lib/np/compilerplugin/PromptAsCodeCodeModificationTask.java @@ -140,6 +140,12 @@ public void modify(SourceModifierContext modifierContext) { documentId); } + for (DocumentId documentId: module.testDocumentIds()) { + Document document = module.document(documentId); + processImportDeclarations(document, modifierData); + processExternalFunctions(document, module, modifierData, modifierContext); + } + for (DocumentId documentId: module.testDocumentIds()) { Document document = module.document(documentId); modifierContext.modifyTestSourceFile(modifyDocument(document, modifierData, modifierContext, moduleId), From bdfa730861e5d4460e4f7a6b15f784fec7899740 Mon Sep 17 00:00:00 2001 From: chiranSachintha Date: Mon, 17 Mar 2025 23:11:08 +0530 Subject: [PATCH 6/7] Generate schema on runtime --- ballerina/main.bal | 3 ++- native/src/main/java/io/ballerina/lib/np/Native.java | 8 +++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/ballerina/main.bal b/ballerina/main.bal index 6cc1da6..bf60ef5 100644 --- a/ballerina/main.bal +++ b/ballerina/main.bal @@ -94,7 +94,8 @@ isolated function getPromptWithExpectedResponseSchema(string prompt, map e isolated function callLlmGeneric(Prompt prompt, Context context, typedesc targetType, map? jsonSchema) returns json|error { Model model = context.model; - json resp = check model->call(buildPromptString(prompt), jsonSchema ?: {}); + json resp = + check model->call(buildPromptString(prompt), jsonSchema ?: generateJsonSchemaForTypedescAsJson(targetType)); return parseResponseAsType(resp, targetType); } diff --git a/native/src/main/java/io/ballerina/lib/np/Native.java b/native/src/main/java/io/ballerina/lib/np/Native.java index 4f6f710..d504e64 100644 --- a/native/src/main/java/io/ballerina/lib/np/Native.java +++ b/native/src/main/java/io/ballerina/lib/np/Native.java @@ -46,10 +46,15 @@ * @since 0.3.0 */ public class Native { + + static Boolean isSchemaGeneratedAtCompileTime; + public static Object callLlm(Environment env, BObject prompt, BMap context, BTypedesc targetType) { + isSchemaGeneratedAtCompileTime = true; + Object jsonSchema = generateJsonSchemaForType(targetType.getDescribingType()); return env.getRuntime().callFunction( new Module("ballerinax", "np", "0"), "callLlmGeneric", null, prompt, context, targetType, - generateJsonSchemaForType(targetType.getDescribingType())); + isSchemaGeneratedAtCompileTime ? jsonSchema : null); } public static Object generateJsonSchemaForType(Type td) { @@ -114,6 +119,7 @@ private static Object generateJsonSchemaForRecordType(RecordType recordType) { return entry.getValue(); } } + isSchemaGeneratedAtCompileTime = false; return null; } From a1d8dde93378f847e65f4d52aab9da67204010c9 Mon Sep 17 00:00:00 2001 From: chiranSachintha Date: Tue, 18 Mar 2025 02:22:52 +0530 Subject: [PATCH 7/7] Generate schema for json type --- .../src/main/java/io/ballerina/lib/np/Native.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/native/src/main/java/io/ballerina/lib/np/Native.java b/native/src/main/java/io/ballerina/lib/np/Native.java index d504e64..f8e1d60 100644 --- a/native/src/main/java/io/ballerina/lib/np/Native.java +++ b/native/src/main/java/io/ballerina/lib/np/Native.java @@ -22,6 +22,7 @@ import io.ballerina.runtime.api.flags.SymbolFlags; import io.ballerina.runtime.api.types.ArrayType; import io.ballerina.runtime.api.types.Field; +import io.ballerina.runtime.api.types.JsonType; import io.ballerina.runtime.api.types.PredefinedTypes; import io.ballerina.runtime.api.types.RecordType; import io.ballerina.runtime.api.types.TupleType; @@ -65,6 +66,7 @@ public static Object generateJsonSchemaForType(Type td) { return switch (type) { case RecordType recordType -> generateJsonSchemaForRecordType(recordType); + case JsonType ignored -> generateJsonSchemaForJson(); case ArrayType arrayType -> generateJsonSchemaForArrayType(arrayType); case TupleType tupleType -> generateJsonSchemaForTupleType(tupleType); case UnionType unionType -> generateJsonSchemaForUnionType(unionType); @@ -78,6 +80,19 @@ private static BMap createSimpleTypeSchema(Type type) { return schemaMap; } + private static BMap generateJsonSchemaForJson() { + BString[] bStringValues = new BString[6]; + bStringValues[0] = StringUtils.fromString("object"); + bStringValues[1] = StringUtils.fromString("array"); + bStringValues[2] = StringUtils.fromString("string"); + bStringValues[3] = StringUtils.fromString("number"); + bStringValues[4] = StringUtils.fromString("boolean"); + bStringValues[5] = StringUtils.fromString("null"); + BMap schemaMap = createMapValue(TypeCreator.createMapType(PredefinedTypes.TYPE_JSON)); + schemaMap.put(StringUtils.fromString("type"), ValueCreator.createArrayValue(bStringValues)); + return schemaMap; + } + private static Object generateJsonSchemaForArrayType(ArrayType arrayType) { BMap schemaMap = createMapValue(TypeCreator.createMapType(PredefinedTypes.TYPE_JSON)); Type elementType = TypeUtils.getReferredType(arrayType.getElementType());