Skip to content

Commit 871e5d5

Browse files
committed
fix: several fixes and improvements
1 parent 54fa3c9 commit 871e5d5

File tree

31 files changed

+230
-143
lines changed

31 files changed

+230
-143
lines changed

plugins/backend-application-default/src/main/java/io/zenwave360/sdk/plugins/BackendApplicationProjectTemplates.java

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import io.zenwave360.sdk.doc.DocumentedOption;
44
import io.zenwave360.sdk.generators.Generator;
5+
import io.zenwave360.sdk.options.PersistenceType;
56
import io.zenwave360.sdk.utils.JSONPath;
67
import io.zenwave360.sdk.zdl.ProjectTemplates;
78
import io.zenwave360.sdk.zdl.layouts.CleanArchitectureProjectLayout;
@@ -15,14 +16,16 @@
1516
import java.util.Map;
1617
import java.util.function.Function;
1718

18-
import static io.zenwave360.sdk.templating.OutputFormatType.JAVA;
19+
import static io.zenwave360.sdk.templating.OutputFormatType.*;
1920
import static io.zenwave360.sdk.zdl.utils.ZDLFindUtils.is;
2021

2122
public class BackendApplicationProjectTemplates extends ProjectTemplates {
2223

2324
@DocumentedOption(description = "Whether to use Spring Modulith annotations and features")
2425
public boolean useSpringModulith = false;
2526

27+
public PersistenceType persistence = PersistenceType.mongodb;
28+
2629
public boolean includeEmitEventsImplementation = true;
2730

2831
protected Function<Map<String, Object>, Boolean> skipEntityRepository = (model) -> is(model, "persistence") // if polyglot persistence -> skip
@@ -31,6 +34,8 @@ public class BackendApplicationProjectTemplates extends ProjectTemplates {
3134
protected Function<Map<String, Object>, Boolean> skipEntity = (model) -> is(model, "vo", "input");
3235
// protected Function<Map<String, Object>, Boolean> skipEntityInput = (model) -> inputDTOSuffix == null || inputDTOSuffix.isEmpty();
3336

37+
protected Function<Map<String, Object>, Boolean> skipDataSql = (model) -> persistence != PersistenceType.jpa;
38+
3439
protected Function<Map<String, Object>, Boolean> skipEvents = (model) -> !includeEmitEventsImplementation;
3540
protected Function<Map<String, Object>, Boolean> skipEventsBus = (model) -> ((Collection) model.get("events")).isEmpty();
3641
protected Function<Map<String, Object>, Boolean> skipInput = (model) -> is(model, "inline");
@@ -79,6 +84,9 @@ public BackendApplicationProjectTemplates() {
7984
this.addTemplate(this.entityTemplates, "src/test/java", "infrastructure/{{persistence}}/{{style}}/inmemory/InMemory{{capitalizeFirst persistence}}Repository.java",
8085
layoutNames.infrastructureRepositoryPackage, "inmemory/InMemory{{capitalizeFirst persistence}}Repository.java", JAVA, skipEntityRepository, true);
8186

87+
this.addTemplate(this.entityTemplates, "src/test/resources", "data/{{persistence}}/entity/1.json",
88+
"", "data/{{persistence}}/{{entity.name}}/1.json", JSON, skipEntity, true);
89+
8290
this.addTemplate(this.enumTemplates, "src/main/java", "core/domain/common/DomainEnum.java",
8391
layoutNames.entitiesPackage, "{{enum.name}}.java", JAVA, null, false);
8492
this.addTemplate(this.inputEnumTemplates, "src/main/java", "core/domain/common/InputEnum.java",
@@ -117,10 +125,13 @@ public BackendApplicationProjectTemplates() {
117125
layoutNames.infrastructureEventsPackage, "InMemoryEventPublisher.java", JAVA, skipEventsBus, false);
118126

119127
this.addTemplate(this.singleTemplates, "src/test/java", "config/TestDataLoader-{{persistence}}.java",
120-
layoutNames.moduleConfigPackage, "TestDataLoader.java", JAVA, null, true);
128+
layoutNames.configPackage, "TestDataLoader.java", JAVA, null, true);
121129
this.addTemplate(this.singleTemplates, "src/test/java", "config/DockerComposeInitializer-{{persistence}}.java",
122130
layoutNames.configPackage, "DockerComposeInitializer.java", JAVA, null, true);
123131

132+
this.addTemplate(this.singleTemplates, "src/test/resources", "data.sql",
133+
"", "data.sql", SQL, skipDataSql, true);
134+
124135
this.addTemplate(this.singleTemplates, "src/main/java", "core/inbound/dtos/package-info.java",
125136
layoutNames.inboundDtosPackage, "package-info.java", JAVA, null, true);
126137
this.addTemplate(this.singleTemplates, "src/main/java", "infrastructure/package-info.java",

plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/test/java/ArchitectureTest.java.hbs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ class ArchitectureTest {
3232
.layer("Config").definedBy("..config..")
3333
.layer("Core").definedBy("..core..")
3434
.layer("Domain").definedBy("..core.domain..")
35-
.layer("Models").definedBy("..core.domain..", "..core.inbound.dtos..")
35+
.optionalLayer("Models").definedBy("..core.domain..", "..core.inbound.dtos..")
3636
.optionalLayer("SearchModel").definedBy("..core.domain.search..")
3737
.optionalLayer("InfrastructureSearch").definedBy("..core.outbound.search..")
3838
.layer("CoreImplementation").definedBy("..core.implementation..")

plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/test/java/config/ServicesInMemoryConfig.java.hbs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import {{layout.domainEventsPackage}}.*;
1818
{{~#if (needsEventBus service)}}
1919
import {{layout.infrastructureEventsPackage}}.*;
2020
{{~/if}}
21+
import {{layout.configPackage}}.TestDataLoader;
2122
import org.springframework.context.annotation.Bean;
2223
import org.springframework.context.annotation.Configuration;
2324
import org.springframework.context.annotation.Profile;

plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/test/java/config/TestDataLoader-jpa.java.hbs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package {{layout.moduleConfigPackage}};
1+
package {{layout.configPackage}};
22

33
import com.fasterxml.jackson.core.JsonProcessingException;
44
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;

plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/test/java/config/TestDataLoader-mongodb.java.hbs

Lines changed: 20 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,12 @@
1-
package {{layout.moduleConfigPackage}};
1+
package {{layout.configPackage}};
22

3-
4-
import org.springframework.beans.BeanUtils;
5-
import org.springframework.boot.autoconfigure.mongo.MongoProperties;
6-
import org.springframework.boot.context.properties.PropertyMapper;
73
import org.springframework.core.convert.support.DefaultConversionService;
84
import org.springframework.data.convert.Jsr310Converters;
9-
import org.springframework.data.mapping.model.FieldNamingStrategy;
105
import org.springframework.data.mongodb.MongoManagedTypes;
116
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
127
import org.springframework.data.mongodb.core.convert.MongoCustomConversions;
138
import org.springframework.data.mongodb.core.convert.NoOpDbRefResolver;
14-
import org.springframework.data.mongodb.core.mapping.Document;
159
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
16-
import org.springframework.data.util.NullableWrapperConverters;
1710

1811
import java.io.File;
1912
import java.nio.file.Files;
@@ -36,18 +29,8 @@ public class TestDataLoader {
3629
return jsonList.stream().map(json -> read(collectionClass, json)).collect(Collectors.toList());
3730
}
3831

39-
public List<String> loadCollectionTestDataAsJson(Class collectionClass) {
40-
var annotation = (Document) collectionClass.getAnnotation(Document.class);
41-
var collection = annotation.collection();
42-
return readDirectoryFilesAsString("src/test/resources/data/mongodb/" + collection);
43-
}
44-
45-
public List<String> loadCollectionTestDataAsJson(String collection) {
46-
return readDirectoryFilesAsString("src/test/resources/data/mongodb/" + collection);
47-
}
48-
49-
public List<String> listAllMongodbCollectionsWithTestData() {
50-
return listFolders("src/test/resources/data/mongodb");
32+
public List<String> loadCollectionTestDataAsJson(Class<?> collectionClass) {
33+
return readDirectoryFilesAsString("src/test/resources/data/mongodb/" + collectionClass.getSimpleName());
5134
}
5235

5336
protected List<String> listFolders(String directory) {
@@ -74,22 +57,31 @@ public class TestDataLoader {
7457
MappingMongoConverter mappingConverter = new MappingMongoConverter(NoOpDbRefResolver.INSTANCE, mongoMappingContext());
7558
DefaultConversionService conversionService = (DefaultConversionService) mappingConverter.getConversionService();
7659
Jsr310Converters.getConvertersToRegister().forEach(conversionService::addConverter);
77-
NullableWrapperConverters.registerConvertersIn(conversionService);
60+
61+
// Handle NullableWrapperConverters for different Spring Boot versions
62+
try {
63+
Class<?> nullableWrapperConverters = Class.forName("org.springframework.data.convert.NullableWrapperConverters");
64+
java.lang.reflect.Method registerMethod = nullableWrapperConverters.getMethod("registerConvertersIn", org.springframework.core.convert.ConversionService.class);
65+
registerMethod.invoke(null, conversionService);
66+
} catch (Exception e) {
67+
try {
68+
Class<?> nullableWrapperConverters = Class.forName("org.springframework.data.core.NullableWrapperConverters");
69+
java.lang.reflect.Method registerMethod = nullableWrapperConverters.getMethod("registerConvertersIn", org.springframework.core.convert.ConversionService.class);
70+
registerMethod.invoke(null, conversionService);
71+
} catch (Exception ignored) {
72+
// NullableWrapperConverters not available in this version
73+
}
74+
}
75+
7876
conversionService.removeConvertible(Object.class, Object.class);
7977
return mappingConverter;
8078
}
8179

8280
MongoMappingContext mongoMappingContext() {
83-
var properties = new MongoProperties();
8481
var managedTypes = MongoManagedTypes.fromIterable(mongoManagedTypes);
85-
PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull();
8682
MongoMappingContext context = new MongoMappingContext();
87-
map.from(properties.isAutoIndexCreation()).to(context::setAutoIndexCreation);
8883
context.setManagedTypes(managedTypes);
89-
Class<?> strategyClass = properties.getFieldNamingStrategy();
90-
if (strategyClass != null) {
91-
context.setFieldNamingStrategy((FieldNamingStrategy) BeanUtils.instantiateClass(strategyClass));
92-
}
84+
9385
var conversions = new MongoCustomConversions(Collections.emptyList());
9486
context.setSimpleTypeHolder(conversions.getSimpleTypeHolder());
9587
context.afterPropertiesSet();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
-- ============================================================================
2+
-- SQL Data Script for Clinical Tool JPA Project
3+
-- ============================================================================
4+
--
5+
-- PROMPT TO GENERATE THIS FILE:
6+
--
7+
-- Create an SQL data script (data.sql) that inserts exactly one sample record
8+
-- per table for all entities in the project.
9+
--
10+
-- Requirements:
11+
-- - Use nextval('sequence_name') for all ID columns to properly call the database sequences
12+
-- - Respect foreign key dependencies and insert parent records before child records
13+
-- - Populate ALL required fields (NOT NULL columns) with realistic sample data
14+
-- - Include optional fields where it makes sense for a complete example
15+
-- - Use proper SQL syntax for:
16+
-- * JSON/JSONB columns (use valid JSON strings)
17+
-- * Array columns (use PostgreSQL array syntax)
18+
-- * LOB/BLOB columns (use appropriate data)
19+
-- * Embedded objects (map to prefixed column names)
20+
-- * Enum values (use the integer representation from converters)
21+
-- * Timestamp fields (use CURRENT_TIMESTAMP where appropriate)
22+
-- * Auditing fields (created_by, created_date, last_modified_by, last_modified_date)
23+
-- - Organize the script by module with clear section comments
24+
-- - Ensure referential integrity (all foreign keys reference valid parent IDs)
25+
-- - Use consistent test data (e.g., user_id=1, hospital_id=1, patient_id=1)
26+
--
27+
-- Format:
28+
-- - Add section headers for each module
29+
-- - Comment each table insertion
30+
-- - Use readable formatting with proper indentation
31+
-- - Include a header comment explaining the script's purpose
32+
--
33+
-- Entity tables in this project:
34+
-- You can find all entities and tables running: grep @Table -R src/main/java/
35+
--
36+
-- ============================================================================
37+
38+
-- example:
39+
-- INSERT INTO application_user (id, version, name, username, email, password, roles, enabled, credentials_non_expired, account_non_expired, account_non_locked, additional_properties, created_by, created_date, last_modified_by, last_modified_date)
40+
-- VALUES (nextval('application_user_seq'), 0, 'Admin User', 'admin', 'user@email.com', '$2a$10$I86fM/OvHg8ounuxGq2oBufCecu3NFO4vT1SWIvd4hnM72lrzdXBG', ARRAY['USER', 'ADMIN'], true, true, true, true, '{"theme": "dark", "notifications": true}', 'user', '2024-08-02 13:36:47.389586', 'system', '2024-08-02 13:36:47.389586');
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"id": 1,
3+
"version": 0
4+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"_id": "1",
3+
"version": 0
4+
}

plugins/customizations/kotlin-backend-application/src/main/java/io/zenwave360/sdk/plugins/kotlin/BackendApplicationKotlinTemplates.java

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

33
import io.zenwave360.sdk.doc.DocumentedOption;
44
import io.zenwave360.sdk.generators.Generator;
5+
import io.zenwave360.sdk.options.PersistenceType;
56
import io.zenwave360.sdk.plugins.BackendApplicationDefaultGenerator;
67
import io.zenwave360.sdk.plugins.BackendApplicationDefaultHelpers;
78
import io.zenwave360.sdk.plugins.BackendApplicationDefaultJpaHelpers;
89
import io.zenwave360.sdk.utils.JSONPath;
910
import io.zenwave360.sdk.zdl.ProjectTemplates;
10-
import io.zenwave360.sdk.zdl.layouts.CleanArchitectureProjectLayout;
1111
import io.zenwave360.sdk.zdl.layouts.CleanHexagonalProjectLayout;
1212
import io.zenwave360.sdk.zdl.layouts.ProjectLayout;
1313
import io.zenwave360.sdk.zdl.utils.ZDLFindUtils;
@@ -18,14 +18,16 @@
1818
import java.util.Map;
1919
import java.util.function.Function;
2020

21-
import static io.zenwave360.sdk.templating.OutputFormatType.KOTLIN;
21+
import static io.zenwave360.sdk.templating.OutputFormatType.*;
2222
import static io.zenwave360.sdk.zdl.utils.ZDLFindUtils.is;
2323

2424
public class BackendApplicationKotlinTemplates extends ProjectTemplates {
2525

2626
@DocumentedOption(description = "Whether to use Spring Modulith annotations and features")
2727
public boolean useSpringModulith = false;
2828

29+
public PersistenceType persistence = PersistenceType.mongodb;
30+
2931
@DocumentedOption(description = "Whether to add AsyncAPI/ApplicationEventPublisher as service dependencies. Depends on the naming convention of zenwave-asyncapi plugin to work.")
3032
public boolean includeEmitEventsImplementation = true;
3133

@@ -35,6 +37,9 @@ public class BackendApplicationKotlinTemplates extends ProjectTemplates {
3537
protected Function<Map<String, Object>, Boolean> skipEntity = (model) -> is(model, "vo", "input");
3638
// protected Function<Map<String, Object>, Boolean> skipEntityInput = (model) -> inputDTOSuffix == null || inputDTOSuffix.isEmpty();
3739

40+
protected Function<Map<String, Object>, Boolean> skipDataSql = (model) -> persistence != PersistenceType.jpa;
41+
42+
3843
protected Function<Map<String, Object>, Boolean> skipEvents = (model) -> !includeEmitEventsImplementation;
3944
protected Function<Map<String, Object>, Boolean> skipEventsBus = (model) -> ((Collection) model.get("events")).isEmpty();
4045
protected Function<Map<String, Object>, Boolean> skipInput = (model) -> is(model, "inline");
@@ -85,6 +90,9 @@ public BackendApplicationKotlinTemplates() {
8590
this.addTemplate(this.entityTemplates, "src/test/kotlin", "infrastructure/{{persistence}}/{{style}}/inmemory/InMemory{{capitalizeFirst persistence}}Repository.kt",
8691
layoutNames.infrastructureRepositoryPackage, "inmemory/InMemory{{capitalizeFirst persistence}}Repository.kt", KOTLIN, skipEntityRepository, true);
8792

93+
this.addTemplate(this.entityTemplates, "src/test/resources", "data/{{persistence}}/entity/1.json",
94+
"", "data/{{persistence}}/{{entity.name}}/1.json", JSON, skipEntity, true);
95+
8896
this.addTemplate(this.enumTemplates, "src/main/kotlin", "core/domain/common/DomainEnum.kt",
8997
layoutNames.entitiesPackage, "{{enum.name}}.kt", KOTLIN, null, false);
9098
this.addTemplate(this.inputEnumTemplates, "src/main/kotlin", "core/domain/common/InputEnum.kt",
@@ -123,10 +131,13 @@ public BackendApplicationKotlinTemplates() {
123131
layoutNames.infrastructureEventsPackage, "InMemoryEventPublisher.kt", KOTLIN, skipEventsBus, false);
124132

125133
this.addTemplate(this.singleTemplates, "src/test/kotlin", "config/TestDataLoader-{{persistence}}.kt",
126-
layoutNames.moduleConfigPackage, "TestDataLoader.kt", KOTLIN, null, true);
134+
layoutNames.configPackage, "TestDataLoader.kt", KOTLIN, null, true);
127135
this.addTemplate(this.singleTemplates, "src/test/kotlin", "config/DockerComposeInitializer-{{persistence}}.kt",
128136
layoutNames.configPackage, "DockerComposeInitializer.kt", KOTLIN, null, true);
129137

138+
this.addTemplate(this.singleTemplates, "src/test/resources", "data.sql",
139+
"", "data.sql", SQL, skipDataSql, true);
140+
130141
this.addTemplate(this.singleTemplates, "src/main/kotlin", "core/inbound/dtos/package-info.kt",
131142
layoutNames.inboundDtosPackage, "package-info.kt", KOTLIN, null, true);
132143
this.addTemplate(this.singleTemplates, "src/main/kotlin", "infrastructure/package-info.kt",

plugins/customizations/kotlin-backend-application/src/main/resources/io/zenwave360/sdk/plugins/kotlin/BackendApplicationDefaultGenerator/src/main/kotlin/core/implementation/partials/jpa/entities-crud-methodBody.hbs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,7 @@
3838
{{~else if (and (isCrudMethod 'delete' method=method entity=_entity ) hasNaturalId)}}
3939
{{{logMethodCall method}}}
4040
val {{_entity.instanceName}} = {{_entity.instanceName}}Repository.{{{naturalIdsRepoMethodCallSignature _entity}}}
41-
?.let { {{_entity.instanceName}}Repository.delete(it))
42-
{{~> (partial '../withEvents')}}
43-
}
41+
?.let { {{_entity.instanceName}}Repository.delete(it) }
42+
{{~> (partial '../withEvents')}}
4443
{{~/if}}
4544

0 commit comments

Comments
 (0)