From 41cbfae077c5bcbad84bd3277003a7476fea2acd Mon Sep 17 00:00:00 2001 From: Bogdan Kobylynskyi <92bogdan@gmail.com> Date: Thu, 5 Dec 2019 10:39:03 -0600 Subject: [PATCH] Introduce model annotations (for Lombok) #10 --- README.md | 1 + .../InputDefinitionToDataModelMapper.java | 2 +- .../TypeDefinitionToDataModelMapper.java | 10 +-- .../codegen/model/DataModelFields.java | 1 + .../graphql/codegen/model/MappingConfig.java | 13 ++- .../templates/javaClassGraphqlType.ftl | 3 + .../graphql/codegen/GraphqlCodegenTest.java | 13 +++ .../Event_with_lombok_annotations.java.txt | 88 +++++++++++++++++++ 8 files changed, 124 insertions(+), 7 deletions(-) create mode 100644 src/test/resources/expected-classes/Event_with_lombok_annotations.java.txt diff --git a/README.md b/README.md index d893318b8..37db4cff1 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,7 @@ Please refer to: | modelValidationAnnotation | String | @javax.validation.
constraints.NotNull | Annotation for mandatory (NonNull) fields. Can be null/empty. | | modelNamePrefix | String | Empty | Sets the prefix for GraphQL model classes (type, input, interface, enum, union). | | modelNameSuffix | String | Empty | Sets the suffix for GraphQL model classes (type, input, interface, enum, union). | +| modelAnnotations | String | Empty | Annotations that will be added to model classes (type, input). | | generateEqualsAndHashCode | Boolean | False | Specifies whether generated model classes should have equals and hashCode methods defined. | | generateToString | Boolean | False | Specifies whether generated model classes should have toString method defined. | diff --git a/src/main/java/com/kobylynskyi/graphql/codegen/mapper/InputDefinitionToDataModelMapper.java b/src/main/java/com/kobylynskyi/graphql/codegen/mapper/InputDefinitionToDataModelMapper.java index b8d715858..6d9c7bddb 100644 --- a/src/main/java/com/kobylynskyi/graphql/codegen/mapper/InputDefinitionToDataModelMapper.java +++ b/src/main/java/com/kobylynskyi/graphql/codegen/mapper/InputDefinitionToDataModelMapper.java @@ -28,11 +28,11 @@ public static Map map(MappingConfig mappingConfig, InputObjectTy dataModel.put(PACKAGE, packageName); dataModel.put(IMPORTS, MapperUtils.getImports(mappingConfig, packageName)); dataModel.put(CLASS_NAME, MapperUtils.getClassNameWithPrefixAndSuffix(mappingConfig, typeDefinition)); + dataModel.put(ANNOTATIONS, mappingConfig.getModelAnnotations()); dataModel.put(NAME, typeDefinition.getName()); dataModel.put(FIELDS, InputValueDefinitionToParameterMapper.map(mappingConfig, typeDefinition.getInputValueDefinitions(), typeDefinition.getName())); dataModel.put(EQUALS_AND_HASH_CODE, mappingConfig.getGenerateEqualsAndHashCode()); dataModel.put(TO_STRING, mappingConfig.getGenerateToString()); - return dataModel; } diff --git a/src/main/java/com/kobylynskyi/graphql/codegen/mapper/TypeDefinitionToDataModelMapper.java b/src/main/java/com/kobylynskyi/graphql/codegen/mapper/TypeDefinitionToDataModelMapper.java index f5734bd6c..d65c9571b 100644 --- a/src/main/java/com/kobylynskyi/graphql/codegen/mapper/TypeDefinitionToDataModelMapper.java +++ b/src/main/java/com/kobylynskyi/graphql/codegen/mapper/TypeDefinitionToDataModelMapper.java @@ -33,16 +33,17 @@ public static Map map(MappingConfig mappingConfig, ObjectTypeDef dataModel.put(PACKAGE, packageName); dataModel.put(IMPORTS, MapperUtils.getImports(mappingConfig, packageName)); dataModel.put(CLASS_NAME, MapperUtils.getClassNameWithPrefixAndSuffix(mappingConfig, typeDefinition)); - Set allInterfaces = new LinkedHashSet<>(); - allInterfaces.addAll(MapperUtils.getUnionsHavingType(mappingConfig, typeDefinition, document)); + dataModel.put(ANNOTATIONS, mappingConfig.getModelAnnotations()); + Set allInterfaces = new LinkedHashSet<>( + MapperUtils.getUnionsHavingType(mappingConfig, typeDefinition, document)); typeDefinition.getImplements().stream() .map(anImplement -> GraphqlTypeToJavaTypeMapper.getJavaType(mappingConfig, anImplement)) .forEach(allInterfaces::add); dataModel.put(IMPLEMENTS, allInterfaces); - Set allParameters = new LinkedHashSet<>(); // Merge attributes from the type and attributes from the interface - allParameters.addAll(FieldDefinitionToParameterMapper.map(mappingConfig, typeDefinition.getFieldDefinitions(), typeDefinition.getName())); + Set allParameters = new LinkedHashSet<>(FieldDefinitionToParameterMapper + .map(mappingConfig, typeDefinition.getFieldDefinitions(), typeDefinition.getName())); List interfaces = getInterfacesOfType(mappingConfig, typeDefinition, document); interfaces.stream() .map(i -> FieldDefinitionToParameterMapper.map(mappingConfig, i.getFieldDefinitions(), i.getName())) @@ -51,7 +52,6 @@ public static Map map(MappingConfig mappingConfig, ObjectTypeDef dataModel.put(EQUALS_AND_HASH_CODE, mappingConfig.getGenerateEqualsAndHashCode()); dataModel.put(TO_STRING, mappingConfig.getGenerateToString()); - return dataModel; } diff --git a/src/main/java/com/kobylynskyi/graphql/codegen/model/DataModelFields.java b/src/main/java/com/kobylynskyi/graphql/codegen/model/DataModelFields.java index 08b8d733e..d748b8eea 100644 --- a/src/main/java/com/kobylynskyi/graphql/codegen/model/DataModelFields.java +++ b/src/main/java/com/kobylynskyi/graphql/codegen/model/DataModelFields.java @@ -13,6 +13,7 @@ public final class DataModelFields { public static final String NAME = "name"; public static final String FIELDS = "fields"; public static final String IMPLEMENTS = "implements"; + public static final String ANNOTATIONS = "annotations"; public static final String OPERATIONS = "operations"; public static final String EQUALS_AND_HASH_CODE = "equalsAndHashCode"; public static final String TO_STRING = "toString"; diff --git a/src/main/java/com/kobylynskyi/graphql/codegen/model/MappingConfig.java b/src/main/java/com/kobylynskyi/graphql/codegen/model/MappingConfig.java index 1d787d1c2..83c910a4e 100644 --- a/src/main/java/com/kobylynskyi/graphql/codegen/model/MappingConfig.java +++ b/src/main/java/com/kobylynskyi/graphql/codegen/model/MappingConfig.java @@ -1,7 +1,9 @@ package com.kobylynskyi.graphql.codegen.model; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; +import java.util.Set; import lombok.Data; @@ -27,6 +29,11 @@ public class MappingConfig implements Combinable { */ private Map customAnnotationsMapping = new HashMap<>(); + /** + * Custom annotations for model classes. + */ + private Set modelAnnotations = new HashSet<>(); + private Boolean generateApis; private String packageName; private String apiPackageName; @@ -67,6 +74,11 @@ public void combine(MappingConfig source) { } else if (this.customAnnotationsMapping == null && source.customAnnotationsMapping != null) { this.customAnnotationsMapping = source.customAnnotationsMapping; } + if (this.modelAnnotations != null && source.modelAnnotations != null) { + this.modelAnnotations.addAll(source.modelAnnotations); + } else if (this.modelAnnotations == null && source.modelAnnotations != null) { + this.modelAnnotations = source.modelAnnotations; + } this.generateApis = source.generateApis != null ? source.generateApis : this.generateApis; this.packageName = source.packageName != null ? source.packageName : this.packageName; this.apiPackageName = source.apiPackageName != null ? source.apiPackageName : this.apiPackageName; @@ -76,7 +88,6 @@ public void combine(MappingConfig source) { this.modelValidationAnnotation = source.modelValidationAnnotation != null ? source.modelValidationAnnotation : this.modelValidationAnnotation; this.generateEqualsAndHashCode = source.generateEqualsAndHashCode != null ? source.generateEqualsAndHashCode : this.generateEqualsAndHashCode; this.generateToString = source.generateToString != null ? source.generateToString : this.generateToString; - } } } diff --git a/src/main/resources/templates/javaClassGraphqlType.ftl b/src/main/resources/templates/javaClassGraphqlType.ftl index 3ec9dfc67..769edbf17 100644 --- a/src/main/resources/templates/javaClassGraphqlType.ftl +++ b/src/main/resources/templates/javaClassGraphqlType.ftl @@ -6,6 +6,9 @@ package ${package}; import ${import}.*; +<#list annotations as annotation> +@${annotation} + public class ${className} <#if implements?has_content>implements <#list implements as interface>${interface}<#if interface_has_next>, { <#list fields as field> diff --git a/src/test/java/com/kobylynskyi/graphql/codegen/GraphqlCodegenTest.java b/src/test/java/com/kobylynskyi/graphql/codegen/GraphqlCodegenTest.java index 8d2b74fa0..0f278f017 100644 --- a/src/test/java/com/kobylynskyi/graphql/codegen/GraphqlCodegenTest.java +++ b/src/test/java/com/kobylynskyi/graphql/codegen/GraphqlCodegenTest.java @@ -143,6 +143,19 @@ void generate_CustomAnnotationMappings() throws Exception { System.lineSeparator() + " private org.joda.time.DateTime createdDateTime;")); } + @Test + void generate_ModelAnnotations() throws Exception { + mappingConfig.setModelAnnotations(new HashSet<>(Arrays.asList("lombok.Builder", "lombok.Builder", "lombok.Data"))); + + generator.generate(); + + File eventFile = Arrays.stream(Objects.requireNonNull(outputJavaClassesDir.listFiles())) + .filter(file -> file.getName().equalsIgnoreCase("Event.java")) + .findFirst().orElseThrow(FileNotFoundException::new); + assertEquals(Utils.getFileContent(new File("src/test/resources/expected-classes/Event_with_lombok_annotations.java.txt").getPath()), + Utils.getFileContent(eventFile.getPath())); + } + @Test void generate_CustomAnnotationMappings_FieldType() throws Exception { mappingConfig.setCustomTypesMapping(new HashMap<>(Collections.singletonMap( diff --git a/src/test/resources/expected-classes/Event_with_lombok_annotations.java.txt b/src/test/resources/expected-classes/Event_with_lombok_annotations.java.txt new file mode 100644 index 000000000..7b0502e46 --- /dev/null +++ b/src/test/resources/expected-classes/Event_with_lombok_annotations.java.txt @@ -0,0 +1,88 @@ +package com.kobylynskyi.graphql.test1; + +import java.util.*; + +@lombok.Builder +@lombok.Data +public class Event { + + private String id; + private String categoryId; + private Collection properties; + private EventStatus status; + private String createdBy; + private String createdDateTime; + private Boolean active; + private Integer rating; + + public Event() { + } + + public Event(String id, String categoryId, Collection properties, EventStatus status, String createdBy, String createdDateTime, Boolean active, Integer rating) { + this.id = id; + this.categoryId = categoryId; + this.properties = properties; + this.status = status; + this.createdBy = createdBy; + this.createdDateTime = createdDateTime; + this.active = active; + this.rating = rating; + } + + public String getId() { + return id; + } + public void setId(String id) { + this.id = id; + } + + public String getCategoryId() { + return categoryId; + } + public void setCategoryId(String categoryId) { + this.categoryId = categoryId; + } + + public Collection getProperties() { + return properties; + } + public void setProperties(Collection properties) { + this.properties = properties; + } + + public EventStatus getStatus() { + return status; + } + public void setStatus(EventStatus status) { + this.status = status; + } + + public String getCreatedBy() { + return createdBy; + } + public void setCreatedBy(String createdBy) { + this.createdBy = createdBy; + } + + public String getCreatedDateTime() { + return createdDateTime; + } + public void setCreatedDateTime(String createdDateTime) { + this.createdDateTime = createdDateTime; + } + + public Boolean getActive() { + return active; + } + public void setActive(Boolean active) { + this.active = active; + } + + public Integer getRating() { + return rating; + } + public void setRating(Integer rating) { + this.rating = rating; + } + +} \ No newline at end of file