Skip to content

Commit 7552eba

Browse files
committed
#1 Support advanced mapping of custom types
1 parent 26f4395 commit 7552eba

9 files changed

+80
-37
lines changed

src/main/java/com/kobylynskyi/graphql/codegen/mapper/FieldDefinitionToDataModelMapper.java

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,34 +23,36 @@ public class FieldDefinitionToDataModelMapper {
2323
*
2424
* @param mappingConfig Global mapping configuration
2525
* @param fieldDefinition GraphQL field definition
26-
* @param objectType Object type (e.g.: "Query", "Mutation" or "Subscription")
26+
* @param objectTypeName Object type (e.g.: "Query", "Mutation" or "Subscription")
2727
* @return Freemarker data model of the GraphQL field
2828
*/
2929
public static Map<String, Object> map(MappingConfig mappingConfig, FieldDefinition fieldDefinition,
30-
String objectType) {
30+
String objectTypeName) {
3131
Map<String, Object> dataModel = new HashMap<>();
3232
String packageName = MapperUtils.getApiPackageName(mappingConfig);
3333
dataModel.put(PACKAGE, packageName);
3434
dataModel.put(IMPORTS, MapperUtils.getImports(mappingConfig, packageName));
35-
dataModel.put(CLASS_NAME, getClassName(fieldDefinition.getName(), objectType));
36-
Operation operation = mapFieldDefinition(mappingConfig, fieldDefinition);
35+
dataModel.put(CLASS_NAME, getClassName(fieldDefinition.getName(), objectTypeName));
36+
Operation operation = mapFieldDefinition(mappingConfig, fieldDefinition, objectTypeName);
3737
dataModel.put(OPERATIONS, Collections.singletonList(operation));
3838
return dataModel;
3939
}
4040

4141
/**
4242
* Map GraphQL's FieldDefinition to a Freemarker-understandable format of operation
4343
*
44-
* @param mappingConfig Global mapping configuration
45-
* @param fieldDefinition GraphQL field definition
44+
* @param mappingConfig Global mapping configuration
45+
* @param fieldDef GraphQL field definition
46+
* @param parentTypeName Name of the parent type
4647
* @return Freemarker-understandable format of operation
4748
*/
48-
static Operation mapFieldDefinition(MappingConfig mappingConfig, FieldDefinition fieldDefinition) {
49+
static Operation mapFieldDefinition(MappingConfig mappingConfig, FieldDefinition fieldDef, String parentTypeName) {
4950
Operation operation = new Operation();
50-
operation.setName(fieldDefinition.getName());
51-
operation.setType(GraphqlTypeToJavaTypeMapper.mapToJavaType(mappingConfig, fieldDefinition.getType()));
51+
operation.setName(fieldDef.getName());
52+
operation.setType(GraphqlTypeToJavaTypeMapper.mapToJavaType(mappingConfig,
53+
fieldDef.getType(), fieldDef.getName(), parentTypeName));
5254
operation.setParameters(
53-
InputValueDefinitionToParameterMapper.map(mappingConfig, fieldDefinition.getInputValueDefinitions()));
55+
InputValueDefinitionToParameterMapper.map(mappingConfig, fieldDef.getInputValueDefinitions()));
5456
return operation;
5557
}
5658

src/main/java/com/kobylynskyi/graphql/codegen/mapper/FieldDefinitionToParameterMapper.java

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,19 +15,30 @@
1515
*/
1616
public class FieldDefinitionToParameterMapper {
1717

18-
public static List<Parameter> map(MappingConfig mappingConfig, List<FieldDefinition> fieldDefinitions) {
18+
/**
19+
* Map field definition to a Freemarker-understandable data model type
20+
*
21+
* @param mappingConfig Global mapping configuration
22+
* @param fieldDefinitions List of GraphQL field definitions
23+
* @param parentTypeName Name of the parent GraphQL type
24+
* @return Freemarker data model of the GraphQL interface
25+
*/
26+
public static List<Parameter> map(MappingConfig mappingConfig,
27+
List<FieldDefinition> fieldDefinitions,
28+
String parentTypeName) {
1929
if (fieldDefinitions == null) {
2030
return Collections.emptyList();
2131
}
2232
return fieldDefinitions.stream()
23-
.map(fieldDefinition -> map(mappingConfig, fieldDefinition))
33+
.map(fieldDefinition -> map(mappingConfig, fieldDefinition, parentTypeName))
2434
.collect(Collectors.toList());
2535
}
2636

27-
private static Parameter map(MappingConfig mappingConfig, FieldDefinition fieldDefinition) {
37+
private static Parameter map(MappingConfig mappingConfig, FieldDefinition fieldDef, String parentTypeName) {
2838
Parameter parameter = new Parameter();
29-
parameter.setName(MapperUtils.capitalizeIfRestricted(fieldDefinition.getName()));
30-
parameter.setType(GraphqlTypeToJavaTypeMapper.mapToJavaType(mappingConfig, fieldDefinition.getType()));
39+
parameter.setName(MapperUtils.capitalizeIfRestricted(fieldDef.getName()));
40+
parameter.setType(GraphqlTypeToJavaTypeMapper.mapToJavaType(mappingConfig,
41+
fieldDef.getType(), fieldDef.getName(), parentTypeName));
3142
return parameter;
3243
}
3344

src/main/java/com/kobylynskyi/graphql/codegen/mapper/GraphqlTypeToJavaTypeMapper.java

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,24 +16,27 @@
1616
class GraphqlTypeToJavaTypeMapper {
1717

1818
static String mapToJavaType(MappingConfig mappingConfig, Type type) {
19+
return mapToJavaType(mappingConfig, type, null, null);
20+
}
21+
22+
static String mapToJavaType(MappingConfig mappingConfig, Type type, String name, String parentTypeName) {
1923
if (type instanceof TypeName) {
20-
return mapToJavaType(mappingConfig, ((TypeName) type).getName());
24+
return mapToJavaType(mappingConfig, ((TypeName) type).getName(), name, parentTypeName);
2125
} else if (type instanceof ListType) {
22-
return wrapIntoJavaCollection(mapToJavaType(mappingConfig, ((ListType) type).getType()));
26+
String mappedCollectionType = mapToJavaType(mappingConfig, ((ListType) type).getType(), name, parentTypeName);
27+
return wrapIntoJavaCollection(mappedCollectionType);
2328
} else if (type instanceof NonNullType) {
24-
return mapToJavaType(mappingConfig, ((NonNullType) type).getType());
29+
return mapToJavaType(mappingConfig, ((NonNullType) type).getType(), name, parentTypeName);
2530
}
2631
return null;
2732
}
2833

29-
private static String wrapIntoJavaCollection(String type) {
30-
return String.format("Collection<%s>", type);
31-
}
32-
33-
private static String mapToJavaType(MappingConfig mappingConfig, String graphlType) {
34-
Map<String, String> graphqlScalarsMapping = mappingConfig.getCustomTypesMapping();
35-
if (graphqlScalarsMapping.containsKey(graphlType)) {
36-
return graphqlScalarsMapping.get(graphlType);
34+
private static String mapToJavaType(MappingConfig mappingConfig, String graphlType, String name, String parentTypeName) {
35+
Map<String, String> customTypesMapping = mappingConfig.getCustomTypesMapping();
36+
if (name != null && parentTypeName != null && customTypesMapping.containsKey(parentTypeName + "." + name)) {
37+
return customTypesMapping.get(parentTypeName + "." + name);
38+
} else if (customTypesMapping.containsKey(graphlType)) {
39+
return customTypesMapping.get(graphlType);
3740
}
3841
switch (graphlType) {
3942
case "ID":
@@ -50,4 +53,8 @@ private static String mapToJavaType(MappingConfig mappingConfig, String graphlTy
5053
}
5154
}
5255

56+
private static String wrapIntoJavaCollection(String type) {
57+
return String.format("Collection<%s>", type);
58+
}
59+
5360
}

src/main/java/com/kobylynskyi/graphql/codegen/mapper/InterfaceDefinitionToDataModelMapper.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,17 @@ public class InterfaceDefinitionToDataModelMapper {
1818
/**
1919
* Map interface definition to a Freemarker data model
2020
*
21-
* @param mappingConfig Global mapping configuration
22-
* @param typeDefinition GraphQL interface definition
21+
* @param mappingConfig Global mapping configuration
22+
* @param typeDef GraphQL interface definition
2323
* @return Freemarker data model of the GraphQL interface
2424
*/
25-
public static Map<String, Object> map(MappingConfig mappingConfig, InterfaceTypeDefinition typeDefinition) {
25+
public static Map<String, Object> map(MappingConfig mappingConfig, InterfaceTypeDefinition typeDef) {
2626
Map<String, Object> dataModel = new HashMap<>();
2727
String packageName = MapperUtils.getModelPackageName(mappingConfig);
2828
dataModel.put(PACKAGE, packageName);
2929
dataModel.put(IMPORTS, MapperUtils.getImports(mappingConfig, packageName));
30-
dataModel.put(CLASS_NAME, MapperUtils.getClassNameWithPrefixAndSuffix(mappingConfig, typeDefinition));
31-
dataModel.put(FIELDS, FieldDefinitionToParameterMapper.map(mappingConfig, typeDefinition.getFieldDefinitions()));
30+
dataModel.put(CLASS_NAME, MapperUtils.getClassNameWithPrefixAndSuffix(mappingConfig, typeDef));
31+
dataModel.put(FIELDS, FieldDefinitionToParameterMapper.map(mappingConfig, typeDef.getFieldDefinitions(), typeDef.getName()));
3232
return dataModel;
3333
}
3434

src/main/java/com/kobylynskyi/graphql/codegen/mapper/ObjectDefinitionToDataModelMapper.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ public static Map<String, Object> map(MappingConfig mappingConfig, ObjectTypeDef
3232
dataModel.put(IMPORTS, MapperUtils.getImports(mappingConfig, packageName));
3333
dataModel.put(CLASS_NAME, Utils.capitalize(typeDefinition.getName()));
3434
List<Object> operations = typeDefinition.getFieldDefinitions().stream()
35-
.map(fieldDef -> FieldDefinitionToDataModelMapper.mapFieldDefinition(mappingConfig, fieldDef))
35+
.map(fieldDef ->
36+
FieldDefinitionToDataModelMapper.mapFieldDefinition(mappingConfig, fieldDef, typeDefinition.getName()))
3637
.collect(Collectors.toList());
3738
dataModel.put(OPERATIONS, operations);
3839
return dataModel;

src/main/java/com/kobylynskyi/graphql/codegen/mapper/TypeDefinitionToDataModelMapper.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,10 @@ public static Map<String, Object> map(MappingConfig mappingConfig, ObjectTypeDef
4242

4343
Set<Parameter> allParameters = new LinkedHashSet<>();
4444
// Merge attributes from the type and attributes from the interface
45-
allParameters.addAll(FieldDefinitionToParameterMapper.map(mappingConfig, typeDefinition.getFieldDefinitions()));
45+
allParameters.addAll(FieldDefinitionToParameterMapper.map(mappingConfig, typeDefinition.getFieldDefinitions(), typeDefinition.getName()));
4646
List<InterfaceTypeDefinition> interfaces = getInterfacesOfType(mappingConfig, typeDefinition, document);
4747
interfaces.stream()
48-
.map(i -> FieldDefinitionToParameterMapper.map(mappingConfig, i.getFieldDefinitions()))
48+
.map(i -> FieldDefinitionToParameterMapper.map(mappingConfig, i.getFieldDefinitions(), i.getName()))
4949
.forEach(allParameters::addAll);
5050
dataModel.put(FIELDS, allParameters);
5151

src/main/java/com/kobylynskyi/graphql/codegen/model/DefinitionTypeDeterminer.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,11 @@
22

33
import com.kobylynskyi.graphql.codegen.utils.Utils;
44
import graphql.language.*;
5-
6-
import javax.annotation.Nonnull;
5+
import lombok.NonNull;
76

87
public class DefinitionTypeDeterminer {
98

10-
public static DefinitionType determine(@Nonnull Definition definition) {
9+
public static DefinitionType determine(@NonNull Definition definition) {
1110
if (definition instanceof ObjectTypeDefinition) {
1211
ObjectTypeDefinition typeDef = (ObjectTypeDefinition) definition;
1312
if (Utils.isGraphqlOperation(typeDef.getName())) {

src/main/java/com/kobylynskyi/graphql/codegen/model/MappingConfig.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ public class MappingConfig {
1111
/**
1212
* Scalars mapping can be defined here.
1313
* e.g.: DateTime -> String
14+
* e.g.: Price.Float -> java.math.BigDecimal
1415
*/
1516
private Map<String, String> customTypesMapping = new HashMap<>();
1617
private String packageName;

src/test/java/com/kobylynskyi/graphql/codegen/GraphqlCodegenTest.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,28 @@ void generate_CustomMappings() throws Exception {
7676
assertThat(Utils.getFileContent(eventFile.getPath()), StringContains.containsString("java.util.Date createdDateTime;"));
7777
}
7878

79+
@Test
80+
void generate_CustomMappings_Nested() throws Exception {
81+
mappingConfig.setCustomTypesMapping(new HashMap<>(
82+
Collections.singletonMap("EventProperty.intVal", "java.math.BigInteger")));
83+
84+
generator.generate();
85+
86+
File[] files = Objects.requireNonNull(outputJavaClassesDir.listFiles());
87+
88+
// As per mapping, only EventProperty.intVal should be mapped to java.math.BigInteger
89+
File eventPropertyFile = Arrays.stream(files)
90+
.filter(file -> file.getName().equalsIgnoreCase("EventProperty.java"))
91+
.findFirst().orElseThrow(FileNotFoundException::new);
92+
assertThat(Utils.getFileContent(eventPropertyFile.getPath()),
93+
StringContains.containsString("private java.math.BigInteger intVal;"));
94+
File eventFile = Arrays.stream(files)
95+
.filter(file -> file.getName().equalsIgnoreCase("Event.java"))
96+
.findFirst().orElseThrow(FileNotFoundException::new);
97+
assertThat(Utils.getFileContent(eventFile.getPath()),
98+
StringContains.containsString("private Integer rating;"));
99+
}
100+
79101
@Test
80102
void generate_NoCustomMappings() throws Exception {
81103
generator.generate();

0 commit comments

Comments
 (0)