From 35b4e4011b2da1bcdc55c007fdc3b80042fdd8a3 Mon Sep 17 00:00:00 2001 From: Ivan Garcia Sainz-Aja Date: Sun, 31 Mar 2024 00:09:43 +0100 Subject: [PATCH 1/7] adds support for 'includeKafkaCommonHeaders' --- .../java/io/zenwave360/sdk/plugins/ZDLToAsyncAPIGenerator.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/plugins/zdl-to-asyncapi/src/main/java/io/zenwave360/sdk/plugins/ZDLToAsyncAPIGenerator.java b/plugins/zdl-to-asyncapi/src/main/java/io/zenwave360/sdk/plugins/ZDLToAsyncAPIGenerator.java index 1b2d755b..32c179f7 100644 --- a/plugins/zdl-to-asyncapi/src/main/java/io/zenwave360/sdk/plugins/ZDLToAsyncAPIGenerator.java +++ b/plugins/zdl-to-asyncapi/src/main/java/io/zenwave360/sdk/plugins/ZDLToAsyncAPIGenerator.java @@ -58,6 +58,9 @@ enum SchemaFormat { public String defaultSchemaFormat = "application/vnd.aai.asyncapi;version=3.0.0"; public String avroSchemaFormat = "application/vnd.apache.avro+json;version=1.9.0"; + @DocumentedOption(description = "Include Kafka common headers (kafka_messageKey)") + public boolean includeKafkaCommonHeaders = false; + private HandlebarsEngine handlebarsEngine = new HandlebarsEngine(); From 9e0cf8680acfc8c07778008ccde505b5febacbb0 Mon Sep 17 00:00:00 2001 From: Ivan Garcia Sainz-Aja Date: Wed, 27 Mar 2024 12:37:35 +0100 Subject: [PATCH 2/7] adds support for java.util.Map --- ...estCustomerAddressPostgresJsonProject.java | 108 ++++++++ .../customer-address-postgres-json.zdl | 123 +++++++++ .../customer-address-postgres-json/pom.xml | 251 ++++++++++++++++++ .../src/main/docker/docker-compose.yml | 23 ++ .../io/zenwave360/example/Application.java | 13 + .../example/config/DatabaseConfiguration.java | 84 ++++++ .../example/config/SecurityConfiguration.java | 49 ++++ .../config/SpringSecurityAuditorAware.java | 44 +++ .../src/main/resources/application-local.yml | 1 + .../src/main/resources/application.yml | 67 +++++ .../src/test/resources/application-test.yml | 1 + .../main/java/core/domain/jpa/Entity.java.hbs | 18 +- pom.xml | 2 +- .../generators/EntitiesToAvroConverter.java | 2 + .../EntitiesToSchemasConverter.java | 7 +- .../sdk/processors/OpenApiProcessor.java | 4 +- .../sdk/zdl/ZDLJavaSignatureUtils.java | 8 + 17 files changed, 797 insertions(+), 8 deletions(-) create mode 100644 e2e/src/test/java/io/zenwave360/sdk/e2e/TestCustomerAddressPostgresJsonProject.java create mode 100644 e2e/src/test/resources/projects/customer-address-postgres-json/customer-address-postgres-json.zdl create mode 100644 e2e/src/test/resources/projects/customer-address-postgres-json/pom.xml create mode 100644 e2e/src/test/resources/projects/customer-address-postgres-json/src/main/docker/docker-compose.yml create mode 100644 e2e/src/test/resources/projects/customer-address-postgres-json/src/main/java/io/zenwave360/example/Application.java create mode 100644 e2e/src/test/resources/projects/customer-address-postgres-json/src/main/java/io/zenwave360/example/config/DatabaseConfiguration.java create mode 100644 e2e/src/test/resources/projects/customer-address-postgres-json/src/main/java/io/zenwave360/example/config/SecurityConfiguration.java create mode 100644 e2e/src/test/resources/projects/customer-address-postgres-json/src/main/java/io/zenwave360/example/config/SpringSecurityAuditorAware.java create mode 100644 e2e/src/test/resources/projects/customer-address-postgres-json/src/main/resources/application-local.yml create mode 100644 e2e/src/test/resources/projects/customer-address-postgres-json/src/main/resources/application.yml create mode 100644 e2e/src/test/resources/projects/customer-address-postgres-json/src/test/resources/application-test.yml diff --git a/e2e/src/test/java/io/zenwave360/sdk/e2e/TestCustomerAddressPostgresJsonProject.java b/e2e/src/test/java/io/zenwave360/sdk/e2e/TestCustomerAddressPostgresJsonProject.java new file mode 100644 index 00000000..d49ac546 --- /dev/null +++ b/e2e/src/test/java/io/zenwave360/sdk/e2e/TestCustomerAddressPostgresJsonProject.java @@ -0,0 +1,108 @@ +package io.zenwave360.sdk.e2e; + +import java.io.File; + +import org.apache.commons.io.FileUtils; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +import io.zenwave360.sdk.MainGenerator; +import io.zenwave360.sdk.Plugin; +import io.zenwave360.sdk.options.DatabaseType; +import io.zenwave360.sdk.options.PersistenceType; +import io.zenwave360.sdk.options.ProgrammingStyle; +import io.zenwave360.sdk.plugins.BackendApplicationDefaultPlugin; +import io.zenwave360.sdk.plugins.OpenAPIControllersPlugin; +import io.zenwave360.sdk.plugins.ZDLToAsyncAPIPlugin; +import io.zenwave360.sdk.plugins.ZDLToOpenAPIPlugin; +import io.zenwave360.sdk.testutils.MavenCompiler; + +@TestMethodOrder(MethodOrderer.OrderAnnotation.class) +public class TestCustomerAddressPostgresJsonProject { + private String basePackage = "io.zenwave360.example"; + + @Test + public void testCustomerAddressPostgresJson() throws Exception { + String sourceFolder = "src/test/resources/projects/customer-address-postgres-json/"; + String targetFolder = "target/customer-address-postgres-json/"; + String zdlFile = targetFolder + "/customer-address-postgres-json.zdl"; + + // copy whole dir from sourceFolder to targetFolder + FileUtils.deleteDirectory(new File(targetFolder)); + FileUtils.forceMkdir(new File(targetFolder)); + FileUtils.copyDirectory(new File(sourceFolder), new File(targetFolder)); + Assertions.assertTrue(new File(targetFolder).exists()); + + Plugin plugin = null; + int exitCode = 0; + + plugin = new ZDLToOpenAPIPlugin() + .withSpecFile(zdlFile) + .withOption("idType", "integer") + .withOption("idTypeFormat", "int64") + .withOption("targetFile", "/src/main/resources/apis/openapi.yml") + .withTargetFolder(targetFolder); + new MainGenerator().generate(plugin); + + plugin = new ZDLToAsyncAPIPlugin() + .withSpecFile(zdlFile) + .withOption("asyncapiVersion", "v3") + .withOption("idType", "integer") + .withOption("idTypeFormat", "int64") + .withOption("targetFile", "/src/main/resources/apis/asyncapi.yml") + .withTargetFolder(targetFolder); + new MainGenerator().generate(plugin); + + plugin = new BackendApplicationDefaultPlugin() + .withSpecFile(zdlFile) + .withTargetFolder(targetFolder) + .withOption("basePackage", basePackage) + .withOption("persistence", PersistenceType.jpa) + .withOption("databaseType", DatabaseType.postgresql) + .withOption("style", ProgrammingStyle.imperative) + .withOption("useLombok", true) + .withOption("includeEmitEventsImplementation", true) + .withOption("forceOverwrite", true) + .withOption("haltOnFailFormatting", false); + + new MainGenerator().generate(plugin); + + TextUtils.replaceInFile(new File(targetFolder + "/src/main/java/io/zenwave360/example/core/implementation/mappers/EventsMapper.java"), + "io.zenwave360.example.core.outbound.events.dtos.Customer asCustomer\\(Customer customer\\);", + """ + @org.mapstruct.Mapping(target = "extraProperties", ignore = true) + io.zenwave360.example.core.outbound.events.dtos.Customer asCustomer(Customer customer); + """); + + exitCode = MavenCompiler.compile(new File(targetFolder)); + Assertions.assertEquals(0, exitCode); + + plugin = new OpenAPIControllersPlugin() + .withSpecFile(targetFolder + "/src/main/resources/apis/openapi.yml") + .withOption("zdlFile", zdlFile) + .withOption("basePackage", basePackage) + .withOption("controllersPackage", "{{basePackage}}.adapters.web") + .withOption("openApiApiPackage", "{{basePackage}}.adapters.web") + .withOption("openApiModelPackage", "{{basePackage}}.adapters.web.model") + .withOption("openApiModelNameSuffix", "DTO") + // .withOption("operationIds", List.of("addPet", "updatePet")) + .withOption("style", ProgrammingStyle.imperative) + .withTargetFolder(targetFolder); + new MainGenerator().generate(plugin); + + TextUtils.replaceInFile(new File(targetFolder + "/src/main/java/io/zenwave360/example/adapters/web/mappers/CustomerDTOsMapper.java"), + "// request mappings", + """ + // request mappings + default Map map(Object value) { return new HashMap();} + """); + + exitCode = MavenCompiler.compile(new File(targetFolder)); + Assertions.assertEquals(0, exitCode); + } + +} diff --git a/e2e/src/test/resources/projects/customer-address-postgres-json/customer-address-postgres-json.zdl b/e2e/src/test/resources/projects/customer-address-postgres-json/customer-address-postgres-json.zdl new file mode 100644 index 00000000..0d8e7f98 --- /dev/null +++ b/e2e/src/test/resources/projects/customer-address-postgres-json/customer-address-postgres-json.zdl @@ -0,0 +1,123 @@ +/** + * Simple Event-Driven CRUD for Customer/Addresses. + */ +config { + title "ZenWave Playground Customer-Address MariaDB" + basePackage "io.zenwave360.example" + persistence jpa + databaseType mariadb +// haltOnFailFormatting false + + plugins { + + ZDLToOpenAPIPlugin { + idType integer + idTypeFormat int64 + targetFile "src/main/resources/apis/openapi.yml" + } + + ZDLToAsyncAPIPlugin { + asyncapiVersion v3 + idType integer + idTypeFormat int64 + targetFile "src/main/resources/apis/asyncapi.yml" + } + + BackendApplicationDefaultPlugin { + useLombok true + includeEmitEventsImplementation true + // --force // overwite all files + } + + OpenAPIControllersPlugin { + formatter google // comments in one line are better for demos + specFile "src/main/resources/apis/openapi.yml" + zdlFile "customer-address-relational.zdl" + + // thse should match the values of openapi-generator-maven-plugin + openApiApiPackage "{{basePackage}}.adapters.web" + openApiModelPackage "{{basePackage}}.adapters.web.model" + openApiModelNameSuffix DTO + } + } +} + + +// == Entities ============================= +/** +* Customer javadoc comment +*/ +@aggregate +entity Customer { + username String required unique /** username javadoc comment */ + email String required unique /** email javadoc comment */ + @jsonb + address Address { + street String required /** street javadoc comment */ + city String /** city javadoc comment */ + state String /** state javadoc comment */ + zip String /** zip javadoc comment */ + type AddressType required /** address type is an enum */ + } + @jsonb extraProperties Map = "new HashMap()" +} + +enum AddressType { HOME(1) /** home description */, WORK(1) /** work description */ } + + +// == Services ============================= + +@inline +input AddressInput { + identifier String required /** Description identifier for this Address */ + address Address +} + +/** + Service javadoc comment + */ +@rest("/customers") +service CustomerService for (Customer) { + /** + * Create customer javadoc comment + */ + @post + createCustomer(Customer) Customer withEvents CustomerEvent + + @put("/{customerId}") + updateCustomer(id, Customer) Customer? withEvents CustomerEvent + + /** Updates a the customer address identified by address.identifier */ + @put({path: "/{customerId}/address/{identifier}", params: {identifier: String}}) + updateCustomerAddress(id, AddressInput) Customer? withEvents CustomerEvent CustomerAddressUpdated + + @delete("/{customerId}") + deleteCustomer(id) withEvents CustomerEvent + + @get("/{customerId}") + getCustomer(id) Customer? + + @get({params: {search: "string"}}) + @paginated + listCustomers() Customer[] +} + +// == Events ============================= + +@skip // skip generating this domain enum, it will genereate by asyncapi code generator. +enum EventType { CREATED(1) /** created description */, UPDATED(1) /** updated description */, DELETED(1) /** deleted description */ } + +@asyncapi({channel: "CustomerEventsChannel", topic: "customer.events"}) +event CustomerEvent { + customerId String + eventType EventType + customer Customer +} + +@asyncapi({channel: "CustomerAddressEventsChannel", topic: "customer.address-events"}) +event CustomerAddressUpdated { + customerId String + addressDescription String + originalAddress Address + newAddress Address +} diff --git a/e2e/src/test/resources/projects/customer-address-postgres-json/pom.xml b/e2e/src/test/resources/projects/customer-address-postgres-json/pom.xml new file mode 100644 index 00000000..3a5c3ea2 --- /dev/null +++ b/e2e/src/test/resources/projects/customer-address-postgres-json/pom.xml @@ -0,0 +1,251 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 3.1.4 + + + io.zenwave360.example + zenwave-playground + 0.0.1-SNAPSHOT + ${project.groupId}:${project.artifactId} + ZenWave-SDK Examples Playground + + 17 + ${project.parent.version} + 2022.0.4 + + 1.4.0-SNAPSHOT + + 3.0.2 + 1.5.3.Final + 1.0.1 + 2.2.1.RELEASE + 3.7.3 + + + + + + org.springframework.cloud + spring-cloud-dependencies + ${spring-cloud.version} + pom + import + + + + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-security + + + org.springframework.cloud + spring-cloud-starter-stream-kafka + + + org.springframework.cloud + spring-cloud-stream-schema + ${spring-cloud-stream-schema.version} + + + + org.projectlombok + lombok + true + + + jakarta.validation + jakarta.validation-api + ${jakarta.validation-api.version} + + + org.mapstruct + mapstruct + ${mapstruct.version} + + + org.mapstruct + mapstruct-processor + ${mapstruct.version} + + + org.projectlombok + lombok-mapstruct-binding + 0.2.0 + + + org.apache.commons + commons-lang3 + + + + com.zaxxer + HikariCP + + + io.hypersistence + hypersistence-utils-hibernate-63 + ${hypersistence-utils-hibernate-63.version} + + + org.postgresql + postgresql + runtime + + + + org.springframework.boot + spring-boot-starter-test + test + + + org.testcontainers + junit-jupiter + test + + + com.tngtech.archunit + archunit-junit5-api + ${archunit-junit5.version} + test + + + + + com.tngtech.archunit + archunit-junit5-engine + ${archunit-junit5.version} + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + org.projectlombok + lombok + + + + + + org.openapitools + openapi-generator-maven-plugin + 6.6.0 + + + + generate + + generate-sources + + ${project.basedir}/src/main/resources/apis/openapi.yml + spring + io.zenwave360.example.adapters.web + io.zenwave360.example.adapters.web.model + DTO + true + + ApiUtil.java + + + Double=java.math.BigDecimal + + + true + none + false + true + true + true + false + + + + + + + io.github.zenwave360.zenwave-sdk + zenwave-sdk-maven-plugin + ${zenwave.version} + + ${pom.basedir}/src/main/resources/apis/asyncapi.yml + false + true + true + + + + + generate-asyncapi-dtos + generate-sources + + generate + + + jsonschema2pojo + + io.zenwave360.example.core.outbound.events.dtos + + true + true + true + + + + + + generate-asyncapi + generate-sources + + generate + + + spring-cloud-streams3 + + provider + + + io.zenwave360.example.core.outbound.events.dtos + io.zenwave360.example.core.outbound.events + io.zenwave360.example.adapters.commands + + + + + + + io.github.zenwave360.zenwave-sdk.plugins + asyncapi-spring-cloud-streams3 + ${zenwave.version} + + + io.github.zenwave360.zenwave-sdk.plugins + asyncapi-jsonschema2pojo + ${zenwave.version} + + + + + + + diff --git a/e2e/src/test/resources/projects/customer-address-postgres-json/src/main/docker/docker-compose.yml b/e2e/src/test/resources/projects/customer-address-postgres-json/src/main/docker/docker-compose.yml new file mode 100644 index 00000000..89ea55b9 --- /dev/null +++ b/e2e/src/test/resources/projects/customer-address-postgres-json/src/main/docker/docker-compose.yml @@ -0,0 +1,23 @@ +version: '3.8' +services: + postgresql: + image: postgres:16.2 + # volumes: + # - ~/volumes/zenwave/postgresql/:/var/lib/postgresql/data/ + environment: + - POSTGRES_USER=zenwave + - POSTGRES_PASSWORD= + - POSTGRES_HOST_AUTH_METHOD=trust + healthcheck: + test: ['CMD-SHELL', 'pg_isready -U $${POSTGRES_USER}'] + interval: 5s + timeout: 5s + retries: 10 + # If you want to expose these ports outside your dev PC, + # remove the "127.0.0.1:" prefix + ports: + - 127.0.0.1:5432:5432 + kafka: + image: bashj79/kafka-kraft + ports: + - '9092:9092' diff --git a/e2e/src/test/resources/projects/customer-address-postgres-json/src/main/java/io/zenwave360/example/Application.java b/e2e/src/test/resources/projects/customer-address-postgres-json/src/main/java/io/zenwave360/example/Application.java new file mode 100644 index 00000000..9e6f9c94 --- /dev/null +++ b/e2e/src/test/resources/projects/customer-address-postgres-json/src/main/java/io/zenwave360/example/Application.java @@ -0,0 +1,13 @@ +package io.zenwave360.example; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } + +} diff --git a/e2e/src/test/resources/projects/customer-address-postgres-json/src/main/java/io/zenwave360/example/config/DatabaseConfiguration.java b/e2e/src/test/resources/projects/customer-address-postgres-json/src/main/java/io/zenwave360/example/config/DatabaseConfiguration.java new file mode 100644 index 00000000..b76c0f8e --- /dev/null +++ b/e2e/src/test/resources/projects/customer-address-postgres-json/src/main/java/io/zenwave360/example/config/DatabaseConfiguration.java @@ -0,0 +1,84 @@ +package io.zenwave360.example.config; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; +import org.springframework.core.env.Environment; +import org.springframework.data.jpa.repository.config.EnableJpaAuditing; +import org.springframework.data.jpa.repository.config.EnableJpaRepositories; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.sql.SQLException; + + +@Configuration +@EnableJpaRepositories({ "io.zenwave360.example.core.outbound.jpa" }) +@EnableJpaAuditing(auditorAwareRef = "springSecurityAuditorAware") +@EnableTransactionManagement +public class DatabaseConfiguration { + + private final Logger log = LoggerFactory.getLogger(DatabaseConfiguration.class); + + private final Environment env; + + public DatabaseConfiguration(Environment env) { + this.env = env; + } + + /** + * Open the TCP port for the H2 database, so it is available remotely. + * + * @return the H2 database TCP server. + * @throws SQLException if the server failed to start. + */ + @Bean(initMethod = "start", destroyMethod = "stop") + @Profile("dev") + public Object h2TCPServer() throws SQLException { + String port = getValidPortForH2(); + log.debug("H2 database is available on port {}", port); + return createServer(port); + } + + private Object createServer(String port) throws SQLException { + try { + ClassLoader loader = Thread.currentThread().getContextClassLoader(); + Class serverClass = Class.forName("org.h2.tools.Server", true, loader); + Method createServer = serverClass.getMethod("createTcpServer", String[].class); + return createServer.invoke(null, new Object[]{new String[]{"-tcp", "-tcpAllowOthers", "-tcpPort", port}}); + + } catch (ClassNotFoundException | LinkageError e) { + throw new RuntimeException("Failed to load and initialize org.h2.tools.Server", e); + + } catch (SecurityException | NoSuchMethodException e) { + throw new RuntimeException("Failed to get method org.h2.tools.Server.createTcpServer()", e); + + } catch (IllegalAccessException | IllegalArgumentException e) { + throw new RuntimeException("Failed to invoke org.h2.tools.Server.createTcpServer()", e); + + } catch (InvocationTargetException e) { + Throwable t = e.getTargetException(); + if (t instanceof SQLException) { + throw (SQLException) t; + } + throw new RuntimeException("Unchecked exception in org.h2.tools.Server.createTcpServer()", t); + } + } + + private String getValidPortForH2() { + int port = Integer.parseInt(env.getProperty("server.port")); + if (port < 10000) { + port = 10000 + port; + } else { + if (port < 63536) { + port = port + 2000; + } else { + port = port - 2000; + } + } + return String.valueOf(port); + } +} diff --git a/e2e/src/test/resources/projects/customer-address-postgres-json/src/main/java/io/zenwave360/example/config/SecurityConfiguration.java b/e2e/src/test/resources/projects/customer-address-postgres-json/src/main/java/io/zenwave360/example/config/SecurityConfiguration.java new file mode 100644 index 00000000..107ef960 --- /dev/null +++ b/e2e/src/test/resources/projects/customer-address-postgres-json/src/main/java/io/zenwave360/example/config/SecurityConfiguration.java @@ -0,0 +1,49 @@ +package io.zenwave360.example.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.Customizer; +import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configurers.CsrfConfigurer; +import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer.FrameOptionsConfig; +import org.springframework.security.web.SecurityFilterChain; +import org.springframework.web.cors.CorsConfiguration; +import org.springframework.web.cors.CorsConfigurationSource; +import org.springframework.web.cors.UrlBasedCorsConfigurationSource; + +import java.util.List; + +@Configuration +@EnableWebSecurity +@EnableMethodSecurity(prePostEnabled = true, securedEnabled = true) +public class SecurityConfiguration { + + @Bean + public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { + // @formatter:off + http + .csrf(CsrfConfigurer::disable) + .authorizeHttpRequests(auth -> + auth.anyRequest().authenticated() + ) + .cors(Customizer.withDefaults()) + .headers(headers -> headers.frameOptions(FrameOptionsConfig::disable)) + .httpBasic(Customizer.withDefaults()); + // @formatter:on + return http.build(); + } + + @Bean + CorsConfigurationSource corsConfigurationSource() { + CorsConfiguration configuration = new CorsConfiguration(); + configuration.setAllowCredentials(true); + configuration.addAllowedHeader("Authorization"); + configuration.setAllowedOrigins(List.of("*")); + configuration.setAllowedMethods(List.of("*")); + UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); + source.registerCorsConfiguration("/**", configuration); + return source; + } +} diff --git a/e2e/src/test/resources/projects/customer-address-postgres-json/src/main/java/io/zenwave360/example/config/SpringSecurityAuditorAware.java b/e2e/src/test/resources/projects/customer-address-postgres-json/src/main/java/io/zenwave360/example/config/SpringSecurityAuditorAware.java new file mode 100644 index 00000000..fceb72f2 --- /dev/null +++ b/e2e/src/test/resources/projects/customer-address-postgres-json/src/main/java/io/zenwave360/example/config/SpringSecurityAuditorAware.java @@ -0,0 +1,44 @@ +package io.zenwave360.example.config; + +import java.util.Optional; +import org.springframework.data.domain.AuditorAware; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.stereotype.Component; + +/** + * Implementation of {@link AuditorAware} based on Spring Security. + */ +@Component("springSecurityAuditorAware") +public class SpringSecurityAuditorAware implements AuditorAware { + + @Override + public Optional getCurrentAuditor() { + return Optional.of(getCurrentUserLogin().orElse("system")); + } + + /** + * Get the login of the current user. + * + * @return the login of the current user. + */ + public static Optional getCurrentUserLogin() { + SecurityContext securityContext = SecurityContextHolder.getContext(); + return Optional.ofNullable(extractPrincipal(securityContext.getAuthentication())); + } + + private static String extractPrincipal(Authentication authentication) { + if (authentication == null) { + return null; + } else if (authentication.getPrincipal() instanceof UserDetails) { + UserDetails springSecurityUser = (UserDetails) authentication.getPrincipal(); + return springSecurityUser.getUsername(); + } else if (authentication.getPrincipal() instanceof String) { + return (String) authentication.getPrincipal(); + } + return null; + } + +} diff --git a/e2e/src/test/resources/projects/customer-address-postgres-json/src/main/resources/application-local.yml b/e2e/src/test/resources/projects/customer-address-postgres-json/src/main/resources/application-local.yml new file mode 100644 index 00000000..8cd70bcd --- /dev/null +++ b/e2e/src/test/resources/projects/customer-address-postgres-json/src/main/resources/application-local.yml @@ -0,0 +1 @@ +MONGODB_URI: mongodb://localhost:27017/customers diff --git a/e2e/src/test/resources/projects/customer-address-postgres-json/src/main/resources/application.yml b/e2e/src/test/resources/projects/customer-address-postgres-json/src/main/resources/application.yml new file mode 100644 index 00000000..bef44c86 --- /dev/null +++ b/e2e/src/test/resources/projects/customer-address-postgres-json/src/main/resources/application.yml @@ -0,0 +1,67 @@ +logging: + level: + io.zenwave360.example: DEBUG + org.springframework.security: DEBUG + org.hibernate.SQL: DEBUG +# org.apache.kafka: DEBUG +spring: + security: + user: + name: user + password: password + roles: USER + jpa: + open-in-view: false + hibernate: + ddl-auto: update + datasource: + type: com.zaxxer.hikari.HikariDataSource + url: jdbc:postgresql://localhost:5432/zenwave + username: zenwave + password: + hikari: + poolName: Hikari + auto-commit: false + data-source-properties: + cachePrepStmts: true + prepStmtCacheSize: 250 + prepStmtCacheSqlLimit: 2048 + useServerPrepStmts: true + kafka: + bootstrap-servers: localhost:9092 + producer: + key-serializer: org.apache.kafka.common.serialization.StringSerializer + consumer: + key-deserializer: org.apache.kafka.common.serialization.StringDeserializer + cloud: + stream: + function: + definition: do-create-customer;on-create-customer-customer-event;on-create-customer-customer-created;on-create-customer-customer-created-failed;on-update-customer-customer-event;on-update-customer-customer-updated;on-delete-customer-customer-deleted + bindings: + on-create-customer-customer-event-in-0: + destination: customer.events + content-type: application/json + on-create-customer-customer-created-out-0: + destination: customer.events + content-type: application/json + on-create-customer-customer-created-failed-out-0: + destination: customer.events + content-type: application/json + on-update-customer-customer-event-out-0: + destination: customer.events + content-type: application/json + on-update-customer-customer-updated-out-0: + destination: customer.events + content-type: application/json + on-delete-customer-customer-deleted-out-0: + destination: customer.events + content-type: application/json + do-create-customer-in-0: + destination: customer.requests + content-type: application/json + dead-letter-queue-error-map: > + { + 'jakarta.validation.ValidationException': 'do-create-customer-validation-error-out-0', + 'java.lang.Exception': 'do-create-customer-error-out-0' + } + diff --git a/e2e/src/test/resources/projects/customer-address-postgres-json/src/test/resources/application-test.yml b/e2e/src/test/resources/projects/customer-address-postgres-json/src/test/resources/application-test.yml new file mode 100644 index 00000000..8cd70bcd --- /dev/null +++ b/e2e/src/test/resources/projects/customer-address-postgres-json/src/test/resources/application-test.yml @@ -0,0 +1 @@ +MONGODB_URI: mongodb://localhost:27017/customers diff --git a/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/main/java/core/domain/jpa/Entity.java.hbs b/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/main/java/core/domain/jpa/Entity.java.hbs index 9c0355ca..d0d6b74f 100644 --- a/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/main/java/core/domain/jpa/Entity.java.hbs +++ b/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/main/java/core/domain/jpa/Entity.java.hbs @@ -22,11 +22,13 @@ import org.springframework.data.jpa.domain.support.AuditingEntityListener; {{~#if useLombok}} @lombok.Getter @lombok.Setter {{~/if}} -{{#if entity.options.embedded}} +{{~#if (or entity.options.json entity.options.jsonb)}} +// json embedded +{{~else if entity.options.embedded}} @Embeddable -{{else if entity.options.isSuperClass}} +{{~else if entity.options.isSuperClass}} @MappedSuperclass -{{else}} +{{~else}} @Entity @Table(name = "{{snakeCase entity.tableName}}") @Cache(usage = CacheConcurrencyStrategy.READ_WRITE) @@ -53,15 +55,23 @@ public {{abstractClass entity}} class {{entity.className}} {{addExtends entity}} {{~/if}} {{{fieldValidationAnnotations field}}} {{~#if field.isEntity}} + {{~#if (or field.options.json field.options.jsonb)}} + @org.hibernate.annotations.Type(io.hypersistence.utils.hibernate.type.json.JsonType.class) + @Column(name = "{{snakeCase field.name}}", columnDefinition = "{{~#if field.options.jsonb}}jsonb{{else}}json{{/if}}") + {{~else~}} @Embedded {{~ assign 'embeddedFields' (jsonPath zdl 'entities.' field.type '.fields[*]') ~}} {{~#joinWithTemplate embeddedFields as |it|}} @AttributeOverride( name = "{{it.name}}", column = @Column(name = "{{snakeCase field.name}}_{{name}}")) {{~/joinWithTemplate~}} + {{~/if~}} + {{~else if (or field.options.json field.options.jsonb)}} + @org.hibernate.annotations.Type(io.hypersistence.utils.hibernate.type.json.JsonType.class) + @Column(name = "{{snakeCase field.name}}", columnDefinition = "{{~#if field.options.jsonb}}jsonb{{else}}json{{/if}}") {{~else~}} @Column(name = "{{snakeCase field.name}}" {{#if field.validations.required}}, nullable = false{{/if}}{{#if field.validations.unique}}, unique = true{{/if}}{{#if field.validations.maxlength}}, length = {{field.validations.maxlength.value}}{{/if}}) - {{~/if~}} {{~#if field.isEnum}} @Enumerated(EnumType.STRING){{/if}} + {{~/if~}} {{~#if field.options.transient}} @javax.persistence.Transient {{/if}} private {{{fieldType field}}} {{field.name}} {{{fieldTypeInitializer field}}}; {{/each}} diff --git a/pom.xml b/pom.xml index af6e778b..0d526e52 100644 --- a/pom.xml +++ b/pom.xml @@ -69,7 +69,7 @@ 0.10.2 4.3.1 0.8.4 - 1.1.0 + 1.2.0-SNAPSHOT 19.2 1.7 2.38.0 diff --git a/zenwave-sdk-cli/src/main/java/io/zenwave360/sdk/generators/EntitiesToAvroConverter.java b/zenwave-sdk-cli/src/main/java/io/zenwave360/sdk/generators/EntitiesToAvroConverter.java index cb1f72fe..5be9e086 100644 --- a/zenwave-sdk-cli/src/main/java/io/zenwave360/sdk/generators/EntitiesToAvroConverter.java +++ b/zenwave-sdk-cli/src/main/java/io/zenwave360/sdk/generators/EntitiesToAvroConverter.java @@ -102,6 +102,8 @@ public Map convertEntityToAvro(Map entity, Map convertEntityToSchema(Map entity, Map return schema; } - public static Map schemaTypeAndFormat(String entityType) { - var property = new LinkedHashMap(); + public static Map schemaTypeAndFormat(String entityType) { + var property = new LinkedHashMap(); if ("String".equals(entityType) || "TextBlob".equals(entityType)) { property.put("type", "string"); } else if ("Enum".equals(entityType)) { @@ -196,6 +196,9 @@ public static Map schemaTypeAndFormat(String entityType) { } else if (ZDLParser.blobTypes.contains(entityType)) { property.put("type", "string"); property.put("format", "binary"); + } else if ("Map".equals(entityType)) { + property.put("type", "object"); + property.put("additionalProperties", false); } else { property.put("type", "string"); } diff --git a/zenwave-sdk-cli/src/main/java/io/zenwave360/sdk/processors/OpenApiProcessor.java b/zenwave-sdk-cli/src/main/java/io/zenwave360/sdk/processors/OpenApiProcessor.java index 9ff7d1b5..29678aca 100644 --- a/zenwave-sdk-cli/src/main/java/io/zenwave360/sdk/processors/OpenApiProcessor.java +++ b/zenwave-sdk-cli/src/main/java/io/zenwave360/sdk/processors/OpenApiProcessor.java @@ -54,7 +54,9 @@ public Map process(Map contextModel) { List> properties = JSONPath.get(apiModel, "$.components.schemas..[?(@.properties)].properties"); for (Map property : properties) { for (Map.Entry entry : property.entrySet()) { - entry.getValue().put("x--property-name", entry.getKey()); + if(entry.getValue() instanceof Map) { + entry.getValue().put("x--property-name", entry.getKey()); + } } } diff --git a/zenwave-sdk-cli/src/main/java/io/zenwave360/sdk/zdl/ZDLJavaSignatureUtils.java b/zenwave-sdk-cli/src/main/java/io/zenwave360/sdk/zdl/ZDLJavaSignatureUtils.java index 0b754ca5..7d724a35 100644 --- a/zenwave-sdk-cli/src/main/java/io/zenwave360/sdk/zdl/ZDLJavaSignatureUtils.java +++ b/zenwave-sdk-cli/src/main/java/io/zenwave360/sdk/zdl/ZDLJavaSignatureUtils.java @@ -129,10 +129,16 @@ public static String fieldType(Map field, String prefix, String suffix) { } return String.format("List<%s%s%s>", prefix, type, suffix); } + if ("Map".equals(type)) { + return "Map"; + } return String.format("%s%s%s", prefix, type, suffix); }; public static String fieldTypeInitializer(Map field) { + if (field.get("initialValue") != null) { + return "= " + field.get("initialValue"); + } if (field.get("isArray") == Boolean.TRUE) { if("byte".equalsIgnoreCase(String.valueOf(field.get("type")))) { return ""; @@ -175,6 +181,8 @@ public static String populateField(Map field) { value = "UUID.randomUUID()"; } else if (ZDLParser.blobTypes.contains(field.get("type"))) { value = "null"; + } else if ("Map".equals(field.get("type"))) { + value = "new java.util.HashMap()"; } else { value = "new " + field.get("type") + "()"; } From 1baa15fae2cda8e668f711610c443fcd18ddd94f Mon Sep 17 00:00:00 2001 From: Ivan Garcia Sainz-Aja Date: Sun, 5 May 2024 11:14:33 +0200 Subject: [PATCH 3/7] adds support for SimpleDomainPackaging --- .../e2e/TestSimpleDomainPackagingProject.java | 100 ++++++++ ...ustomer-address-relational-one-to-many.zdl | 126 +++++++++ .../projects/simple-domain-packaging/pom.xml | 240 ++++++++++++++++++ .../src/main/docker/docker-compose.yml | 16 ++ .../io/zenwave360/example/Application.java | 13 + .../example/config/DatabaseConfiguration.java | 84 ++++++ .../example/config/SecurityConfiguration.java | 49 ++++ .../config/SpringSecurityAuditorAware.java | 44 ++++ .../src/main/resources/application-local.yml | 1 + .../src/main/resources/application.yml | 63 +++++ .../src/test/resources/application-test.yml | 1 + .../BackendApplicationDefaultPlugin.java | 3 + .../BackendDefaultApplicationGenerator.java | 14 +- ...ackendMultiModuleApplicationGenerator.java | 12 +- ...leDomainPackagingApplicationGenerator.java | 125 +++++++++ .../main/java/core/domain/jpa/Entity.java.hbs | 2 +- .../java/core/domain/mongodb/Entity.java.hbs | 2 +- .../imperative/ServiceImpl.java.hbs | 2 +- .../jpa/imperative/EntityRepository.java.hbs | 4 +- .../imperative/EntityRepository.java.hbs | 2 +- .../RepositoriesInMemoryConfig.java.hbs | 6 +- .../jpa/imperative/ServiceTest.java.hbs | 8 +- .../mongodb/imperative/ServiceTest.java.hbs | 9 +- .../EntityRepositoryIntegrationTest.java.hbs | 2 +- .../EntityRepositoryInMemory.java.hbs | 4 +- .../inmemory/InMemoryJpaRepository.java.hbs | 2 +- .../EntityRepositoryIntegrationTest.java.hbs | 2 +- .../EntityRepositoryInMemory.java.hbs | 4 +- .../InMemoryMongodbRepository.java.hbs | 2 +- .../main/java/web/mappers/BaseMapper.java.hbs | 6 +- 30 files changed, 908 insertions(+), 40 deletions(-) create mode 100644 e2e/src/test/java/io/zenwave360/sdk/e2e/TestSimpleDomainPackagingProject.java create mode 100644 e2e/src/test/resources/projects/simple-domain-packaging/customer-address-relational-one-to-many.zdl create mode 100644 e2e/src/test/resources/projects/simple-domain-packaging/pom.xml create mode 100644 e2e/src/test/resources/projects/simple-domain-packaging/src/main/docker/docker-compose.yml create mode 100644 e2e/src/test/resources/projects/simple-domain-packaging/src/main/java/io/zenwave360/example/Application.java create mode 100644 e2e/src/test/resources/projects/simple-domain-packaging/src/main/java/io/zenwave360/example/config/DatabaseConfiguration.java create mode 100644 e2e/src/test/resources/projects/simple-domain-packaging/src/main/java/io/zenwave360/example/config/SecurityConfiguration.java create mode 100644 e2e/src/test/resources/projects/simple-domain-packaging/src/main/java/io/zenwave360/example/config/SpringSecurityAuditorAware.java create mode 100644 e2e/src/test/resources/projects/simple-domain-packaging/src/main/resources/application-local.yml create mode 100644 e2e/src/test/resources/projects/simple-domain-packaging/src/main/resources/application.yml create mode 100644 e2e/src/test/resources/projects/simple-domain-packaging/src/test/resources/application-test.yml create mode 100644 plugins/backend-application-default/src/main/java/io/zenwave360/sdk/plugins/BackendSimpleDomainPackagingApplicationGenerator.java diff --git a/e2e/src/test/java/io/zenwave360/sdk/e2e/TestSimpleDomainPackagingProject.java b/e2e/src/test/java/io/zenwave360/sdk/e2e/TestSimpleDomainPackagingProject.java new file mode 100644 index 00000000..27c8e2d2 --- /dev/null +++ b/e2e/src/test/java/io/zenwave360/sdk/e2e/TestSimpleDomainPackagingProject.java @@ -0,0 +1,100 @@ +package io.zenwave360.sdk.e2e; + +import java.io.File; + +import org.apache.commons.io.FileUtils; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; + +import io.zenwave360.sdk.MainGenerator; +import io.zenwave360.sdk.Plugin; +import io.zenwave360.sdk.options.DatabaseType; +import io.zenwave360.sdk.options.PersistenceType; +import io.zenwave360.sdk.options.ProgrammingStyle; +import io.zenwave360.sdk.plugins.BackendApplicationDefaultPlugin; +import io.zenwave360.sdk.plugins.OpenAPIControllersPlugin; +import io.zenwave360.sdk.plugins.ZDLToAsyncAPIPlugin; +import io.zenwave360.sdk.plugins.ZDLToOpenAPIPlugin; +import io.zenwave360.sdk.testutils.MavenCompiler; + +@TestMethodOrder(MethodOrderer.OrderAnnotation.class) +public class TestSimpleDomainPackagingProject { + private String basePackage = "io.zenwave360.example.customer"; + + @Test + public void testCustomerAddressPostgresJson() throws Exception { + String sourceFolder = "src/test/resources/projects/simple-domain-packaging/"; + String targetFolder = "target/projects/simple-domain-packaging"; + String zdlFile = targetFolder + "/customer-address-relational-one-to-many.zdl"; + + // copy whole dir from sourceFolder to targetFolder + FileUtils.deleteDirectory(new File(targetFolder)); + FileUtils.forceMkdir(new File(targetFolder)); + FileUtils.copyDirectory(new File(sourceFolder), new File(targetFolder)); + Assertions.assertTrue(new File(targetFolder).exists()); + + Plugin plugin = null; + int exitCode = 0; + + plugin = new ZDLToOpenAPIPlugin() + .withSpecFile(zdlFile) + .withOption("idType", "integer") + .withOption("idTypeFormat", "int64") + .withOption("targetFile", "/src/main/resources/apis/openapi.yml") + .withTargetFolder(targetFolder); + new MainGenerator().generate(plugin); + + plugin = new ZDLToAsyncAPIPlugin() + .withSpecFile(zdlFile) + .withOption("asyncapiVersion", "v3") + .withOption("idType", "integer") + .withOption("idTypeFormat", "int64") + .withOption("targetFile", "/src/main/resources/apis/asyncapi.yml") + .withTargetFolder(targetFolder); + new MainGenerator().generate(plugin); + + plugin = new BackendApplicationDefaultPlugin() + .withSpecFile(zdlFile) + .withTargetFolder(targetFolder) + + .withOption("simpleDomainPackaging", true) + + .withOption("basePackage", basePackage) + .withOption("persistence", PersistenceType.jpa) + .withOption("databaseType", DatabaseType.postgresql) + .withOption("style", ProgrammingStyle.imperative) + .withOption("useLombok", true) + .withOption("includeEmitEventsImplementation", true) + .withOption("forceOverwrite", true) + .withOption("haltOnFailFormatting", false); + + new MainGenerator().generate(plugin); + + exitCode = MavenCompiler.compile(new File(targetFolder)); + Assertions.assertEquals(0, exitCode); + + plugin = new OpenAPIControllersPlugin() + .withSpecFile(targetFolder + "/src/main/resources/apis/openapi.yml") + .withOption("zdlFile", zdlFile) + .withOption("basePackage", basePackage) + .withOption("controllersPackage", "{{basePackage}}") + .withOption("openApiApiPackage", "{{basePackage}}") + .withOption("openApiModelPackage", "{{basePackage}}.dtos") + .withOption("openApiModelNameSuffix", "DTO") + + .withOption("entitiesPackage", "{{basePackage}}.model") + .withOption("inboundDtosPackage", "{{basePackage}}.dtos") + .withOption("servicesPackage", "{{basePackage}}") + + // .withOption("operationIds", List.of("addPet", "updatePet")) + .withOption("style", ProgrammingStyle.imperative) + .withTargetFolder(targetFolder); + new MainGenerator().generate(plugin); + + exitCode = MavenCompiler.compile(new File(targetFolder)); + Assertions.assertEquals(0, exitCode); + } + +} diff --git a/e2e/src/test/resources/projects/simple-domain-packaging/customer-address-relational-one-to-many.zdl b/e2e/src/test/resources/projects/simple-domain-packaging/customer-address-relational-one-to-many.zdl new file mode 100644 index 00000000..be124fe7 --- /dev/null +++ b/e2e/src/test/resources/projects/simple-domain-packaging/customer-address-relational-one-to-many.zdl @@ -0,0 +1,126 @@ +/** + * Simple Event-Driven CRUD for Customer/Addresses. + */ +config { + title "ZenWave Playground Customer-Address MariaDB" + basePackage "io.zenwave360.example" + persistence jpa + databaseType mariadb +// haltOnFailFormatting false + + plugins { + + ZDLToOpenAPIPlugin { + idType integer + idTypeFormat int64 + targetFile "src/main/resources/apis/openapi.yml" + } + + ZDLToAsyncAPIPlugin { + asyncapiVersion v3 + idType integer + idTypeFormat int64 + targetFile "src/main/resources/apis/asyncapi.yml" + } + + BackendApplicationDefaultPlugin { + useLombok true + includeEmitEventsImplementation true + // --force // overwite all files + } + + OpenAPIControllersPlugin { + formatter google // comments in one line are better for demos + specFile "src/main/resources/apis/openapi.yml" + zdlFile "customer-address-relational.zdl" + + // thse should match the values of openapi-generator-maven-plugin + openApiApiPackage "{{basePackage}}.adapters.web" + openApiModelPackage "{{basePackage}}.adapters.web.model" + openApiModelNameSuffix DTO + } + } +} + + +// == Entities ============================= +/** +* Customer javadoc comment +*/ +@aggregate +entity Customer { + username String required unique /** username javadoc comment */ + email String required unique /** email javadoc comment */ +} + +entity Address { + street String required /** street javadoc comment */ + city String /** city javadoc comment */ + state String /** state javadoc comment */ + zip String /** zip javadoc comment */ + type AddressType required /** address type is an enum */ +} + +enum AddressType { HOME(1) /** home description */, WORK(1) /** work description */ } + +relationship OneToMany { + Customer{addresses} to Address{customer} +} + + +// == Services ============================= + +@inline +input AddressInput { + identifier String required /** Description identifier for this Address */ + address Address +} + +/** + Service javadoc comment + */ +@rest("/customers") +service CustomerService for (Customer) { + /** + * Create customer javadoc comment + */ + @post + createCustomer(Customer) Customer withEvents CustomerEvent + + @put("/{customerId}") + updateCustomer(id, Customer) Customer? withEvents CustomerEvent + + /** Updates a the customer address identified by address.identifier */ + @put({path: "/{customerId}/address/{identifier}", params: {identifier: String}}) + updateCustomerAddress(id, AddressInput) Customer? withEvents CustomerEvent CustomerAddressUpdated + + @delete("/{customerId}") + deleteCustomer(id) withEvents CustomerEvent + + @get("/{customerId}") + getCustomer(id) Customer? + + @get({params: {search: "string"}}) + @paginated + listCustomers() Customer[] +} + +// == Events ============================= + +@skip // skip generating this domain enum, it will genereate by asyncapi code generator. +enum EventType { CREATED(1) /** created description */, UPDATED(1) /** updated description */, DELETED(1) /** deleted description */ } + +@asyncapi({channel: "CustomerEventsChannel", topic: "customer.events"}) +event CustomerEvent { + customerId String + eventType EventType + customer Customer +} + +@asyncapi({channel: "CustomerAddressEventsChannel", topic: "customer.address-events"}) +event CustomerAddressUpdated { + customerId String + addressDescription String + originalAddress Address + newAddress Address +} diff --git a/e2e/src/test/resources/projects/simple-domain-packaging/pom.xml b/e2e/src/test/resources/projects/simple-domain-packaging/pom.xml new file mode 100644 index 00000000..03a1d0d9 --- /dev/null +++ b/e2e/src/test/resources/projects/simple-domain-packaging/pom.xml @@ -0,0 +1,240 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 3.1.4 + + + io.zenwave360.example + zenwave-playground + 0.0.1-SNAPSHOT + ${project.groupId}:${project.artifactId} + ZenWave-SDK Examples Playground + + 17 + ${project.parent.version} + 2022.0.4 + + 1.4.0-SNAPSHOT + + 3.0.2 + 1.5.3.Final + 1.0.1 + 2.2.1.RELEASE + + + + + + org.springframework.cloud + spring-cloud-dependencies + ${spring-cloud.version} + pom + import + + + + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-security + + + org.springframework.cloud + spring-cloud-starter-stream-kafka + + + org.springframework.cloud + spring-cloud-stream-schema + ${spring-cloud-stream-schema.version} + + + + org.projectlombok + lombok + true + + + jakarta.validation + jakarta.validation-api + ${jakarta.validation-api.version} + + + org.mapstruct + mapstruct + ${mapstruct.version} + + + org.mapstruct + mapstruct-processor + ${mapstruct.version} + + + org.projectlombok + lombok-mapstruct-binding + 0.2.0 + + + org.apache.commons + commons-lang3 + + + + org.mariadb.jdbc + mariadb-java-client + runtime + + + + org.springframework.boot + spring-boot-starter-test + test + + + org.testcontainers + junit-jupiter + test + + + com.tngtech.archunit + archunit-junit5-api + ${archunit-junit5.version} + test + + + + + com.tngtech.archunit + archunit-junit5-engine + ${archunit-junit5.version} + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + org.projectlombok + lombok + + + + + + org.openapitools + openapi-generator-maven-plugin + 6.6.0 + + + + generate + + generate-sources + + ${project.basedir}/src/main/resources/apis/openapi.yml + spring + io.zenwave360.example.customer + io.zenwave360.example.customer.dtos + DTO + true + + ApiUtil.java + + + Double=java.math.BigDecimal + + + true + none + false + true + true + true + false + + + + + + + io.github.zenwave360.zenwave-sdk + zenwave-sdk-maven-plugin + ${zenwave.version} + + ${pom.basedir}/src/main/resources/apis/asyncapi.yml + false + true + true + + + + + generate-asyncapi-dtos + generate-sources + + generate + + + jsonschema2pojo + + io.zenwave360.example.customer.events.dtos + + true + true + + + + + + generate-asyncapi + generate-sources + + generate + + + spring-cloud-streams3 + + provider + + + io.zenwave360.example.customer.events.dtos + io.zenwave360.example.customer.events + io.zenwave360.example.customer.commands + + + + + + + io.github.zenwave360.zenwave-sdk.plugins + asyncapi-spring-cloud-streams3 + ${zenwave.version} + + + io.github.zenwave360.zenwave-sdk.plugins + asyncapi-jsonschema2pojo + ${zenwave.version} + + + + + + + diff --git a/e2e/src/test/resources/projects/simple-domain-packaging/src/main/docker/docker-compose.yml b/e2e/src/test/resources/projects/simple-domain-packaging/src/main/docker/docker-compose.yml new file mode 100644 index 00000000..9fcc2a6e --- /dev/null +++ b/e2e/src/test/resources/projects/simple-domain-packaging/src/main/docker/docker-compose.yml @@ -0,0 +1,16 @@ +version: '3.8' +services: + mariadb: + image: mariadb:10.7.1 + # volumes: + # - ~/volumes/mysql/:/var/lib/mysql/ + environment: + - MYSQL_ALLOW_EMPTY_PASSWORD=yes + - MYSQL_DATABASE=zenwave-playground + ports: + - 127.0.0.1:3306:3306 + command: mysqld --lower_case_table_names=1 --skip-ssl --character_set_server=utf8mb4 --explicit_defaults_for_timestamp + kafka: + image: bashj79/kafka-kraft + ports: + - '9092:9092' diff --git a/e2e/src/test/resources/projects/simple-domain-packaging/src/main/java/io/zenwave360/example/Application.java b/e2e/src/test/resources/projects/simple-domain-packaging/src/main/java/io/zenwave360/example/Application.java new file mode 100644 index 00000000..9e6f9c94 --- /dev/null +++ b/e2e/src/test/resources/projects/simple-domain-packaging/src/main/java/io/zenwave360/example/Application.java @@ -0,0 +1,13 @@ +package io.zenwave360.example; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } + +} diff --git a/e2e/src/test/resources/projects/simple-domain-packaging/src/main/java/io/zenwave360/example/config/DatabaseConfiguration.java b/e2e/src/test/resources/projects/simple-domain-packaging/src/main/java/io/zenwave360/example/config/DatabaseConfiguration.java new file mode 100644 index 00000000..b76c0f8e --- /dev/null +++ b/e2e/src/test/resources/projects/simple-domain-packaging/src/main/java/io/zenwave360/example/config/DatabaseConfiguration.java @@ -0,0 +1,84 @@ +package io.zenwave360.example.config; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; +import org.springframework.core.env.Environment; +import org.springframework.data.jpa.repository.config.EnableJpaAuditing; +import org.springframework.data.jpa.repository.config.EnableJpaRepositories; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.sql.SQLException; + + +@Configuration +@EnableJpaRepositories({ "io.zenwave360.example.core.outbound.jpa" }) +@EnableJpaAuditing(auditorAwareRef = "springSecurityAuditorAware") +@EnableTransactionManagement +public class DatabaseConfiguration { + + private final Logger log = LoggerFactory.getLogger(DatabaseConfiguration.class); + + private final Environment env; + + public DatabaseConfiguration(Environment env) { + this.env = env; + } + + /** + * Open the TCP port for the H2 database, so it is available remotely. + * + * @return the H2 database TCP server. + * @throws SQLException if the server failed to start. + */ + @Bean(initMethod = "start", destroyMethod = "stop") + @Profile("dev") + public Object h2TCPServer() throws SQLException { + String port = getValidPortForH2(); + log.debug("H2 database is available on port {}", port); + return createServer(port); + } + + private Object createServer(String port) throws SQLException { + try { + ClassLoader loader = Thread.currentThread().getContextClassLoader(); + Class serverClass = Class.forName("org.h2.tools.Server", true, loader); + Method createServer = serverClass.getMethod("createTcpServer", String[].class); + return createServer.invoke(null, new Object[]{new String[]{"-tcp", "-tcpAllowOthers", "-tcpPort", port}}); + + } catch (ClassNotFoundException | LinkageError e) { + throw new RuntimeException("Failed to load and initialize org.h2.tools.Server", e); + + } catch (SecurityException | NoSuchMethodException e) { + throw new RuntimeException("Failed to get method org.h2.tools.Server.createTcpServer()", e); + + } catch (IllegalAccessException | IllegalArgumentException e) { + throw new RuntimeException("Failed to invoke org.h2.tools.Server.createTcpServer()", e); + + } catch (InvocationTargetException e) { + Throwable t = e.getTargetException(); + if (t instanceof SQLException) { + throw (SQLException) t; + } + throw new RuntimeException("Unchecked exception in org.h2.tools.Server.createTcpServer()", t); + } + } + + private String getValidPortForH2() { + int port = Integer.parseInt(env.getProperty("server.port")); + if (port < 10000) { + port = 10000 + port; + } else { + if (port < 63536) { + port = port + 2000; + } else { + port = port - 2000; + } + } + return String.valueOf(port); + } +} diff --git a/e2e/src/test/resources/projects/simple-domain-packaging/src/main/java/io/zenwave360/example/config/SecurityConfiguration.java b/e2e/src/test/resources/projects/simple-domain-packaging/src/main/java/io/zenwave360/example/config/SecurityConfiguration.java new file mode 100644 index 00000000..107ef960 --- /dev/null +++ b/e2e/src/test/resources/projects/simple-domain-packaging/src/main/java/io/zenwave360/example/config/SecurityConfiguration.java @@ -0,0 +1,49 @@ +package io.zenwave360.example.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.Customizer; +import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configurers.CsrfConfigurer; +import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer.FrameOptionsConfig; +import org.springframework.security.web.SecurityFilterChain; +import org.springframework.web.cors.CorsConfiguration; +import org.springframework.web.cors.CorsConfigurationSource; +import org.springframework.web.cors.UrlBasedCorsConfigurationSource; + +import java.util.List; + +@Configuration +@EnableWebSecurity +@EnableMethodSecurity(prePostEnabled = true, securedEnabled = true) +public class SecurityConfiguration { + + @Bean + public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { + // @formatter:off + http + .csrf(CsrfConfigurer::disable) + .authorizeHttpRequests(auth -> + auth.anyRequest().authenticated() + ) + .cors(Customizer.withDefaults()) + .headers(headers -> headers.frameOptions(FrameOptionsConfig::disable)) + .httpBasic(Customizer.withDefaults()); + // @formatter:on + return http.build(); + } + + @Bean + CorsConfigurationSource corsConfigurationSource() { + CorsConfiguration configuration = new CorsConfiguration(); + configuration.setAllowCredentials(true); + configuration.addAllowedHeader("Authorization"); + configuration.setAllowedOrigins(List.of("*")); + configuration.setAllowedMethods(List.of("*")); + UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); + source.registerCorsConfiguration("/**", configuration); + return source; + } +} diff --git a/e2e/src/test/resources/projects/simple-domain-packaging/src/main/java/io/zenwave360/example/config/SpringSecurityAuditorAware.java b/e2e/src/test/resources/projects/simple-domain-packaging/src/main/java/io/zenwave360/example/config/SpringSecurityAuditorAware.java new file mode 100644 index 00000000..fceb72f2 --- /dev/null +++ b/e2e/src/test/resources/projects/simple-domain-packaging/src/main/java/io/zenwave360/example/config/SpringSecurityAuditorAware.java @@ -0,0 +1,44 @@ +package io.zenwave360.example.config; + +import java.util.Optional; +import org.springframework.data.domain.AuditorAware; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.stereotype.Component; + +/** + * Implementation of {@link AuditorAware} based on Spring Security. + */ +@Component("springSecurityAuditorAware") +public class SpringSecurityAuditorAware implements AuditorAware { + + @Override + public Optional getCurrentAuditor() { + return Optional.of(getCurrentUserLogin().orElse("system")); + } + + /** + * Get the login of the current user. + * + * @return the login of the current user. + */ + public static Optional getCurrentUserLogin() { + SecurityContext securityContext = SecurityContextHolder.getContext(); + return Optional.ofNullable(extractPrincipal(securityContext.getAuthentication())); + } + + private static String extractPrincipal(Authentication authentication) { + if (authentication == null) { + return null; + } else if (authentication.getPrincipal() instanceof UserDetails) { + UserDetails springSecurityUser = (UserDetails) authentication.getPrincipal(); + return springSecurityUser.getUsername(); + } else if (authentication.getPrincipal() instanceof String) { + return (String) authentication.getPrincipal(); + } + return null; + } + +} diff --git a/e2e/src/test/resources/projects/simple-domain-packaging/src/main/resources/application-local.yml b/e2e/src/test/resources/projects/simple-domain-packaging/src/main/resources/application-local.yml new file mode 100644 index 00000000..8cd70bcd --- /dev/null +++ b/e2e/src/test/resources/projects/simple-domain-packaging/src/main/resources/application-local.yml @@ -0,0 +1 @@ +MONGODB_URI: mongodb://localhost:27017/customers diff --git a/e2e/src/test/resources/projects/simple-domain-packaging/src/main/resources/application.yml b/e2e/src/test/resources/projects/simple-domain-packaging/src/main/resources/application.yml new file mode 100644 index 00000000..ab7b07fa --- /dev/null +++ b/e2e/src/test/resources/projects/simple-domain-packaging/src/main/resources/application.yml @@ -0,0 +1,63 @@ +logging: + level: + io.zenwave360.example: DEBUG + org.springframework.security: DEBUG +# org.apache.kafka: DEBUG +spring: + security: + user: + name: user + password: password + roles: USER + jpa.hibernate.ddl-auto: update + datasource: + type: com.zaxxer.hikari.HikariDataSource + url: jdbc:mariadb://localhost:3306/zenwave-playground?useLegacyDatetimeCode=false&serverTimezone=UTC + username: root + password: + hikari: + poolName: Hikari + auto-commit: false + data-source-properties: + cachePrepStmts: true + prepStmtCacheSize: 250 + prepStmtCacheSqlLimit: 2048 + useServerPrepStmts: true + kafka: + bootstrap-servers: localhost:9092 + producer: + key-serializer: org.apache.kafka.common.serialization.StringSerializer + consumer: + key-deserializer: org.apache.kafka.common.serialization.StringDeserializer + cloud: + stream: + function: + definition: do-create-customer;on-create-customer-customer-event;on-create-customer-customer-created;on-create-customer-customer-created-failed;on-update-customer-customer-event;on-update-customer-customer-updated;on-delete-customer-customer-deleted + bindings: + on-create-customer-customer-event-in-0: + destination: customer.events + content-type: application/json + on-create-customer-customer-created-out-0: + destination: customer.events + content-type: application/json + on-create-customer-customer-created-failed-out-0: + destination: customer.events + content-type: application/json + on-update-customer-customer-event-out-0: + destination: customer.events + content-type: application/json + on-update-customer-customer-updated-out-0: + destination: customer.events + content-type: application/json + on-delete-customer-customer-deleted-out-0: + destination: customer.events + content-type: application/json + do-create-customer-in-0: + destination: customer.requests + content-type: application/json + dead-letter-queue-error-map: > + { + 'jakarta.validation.ValidationException': 'do-create-customer-validation-error-out-0', + 'java.lang.Exception': 'do-create-customer-error-out-0' + } + diff --git a/e2e/src/test/resources/projects/simple-domain-packaging/src/test/resources/application-test.yml b/e2e/src/test/resources/projects/simple-domain-packaging/src/test/resources/application-test.yml new file mode 100644 index 00000000..8cd70bcd --- /dev/null +++ b/e2e/src/test/resources/projects/simple-domain-packaging/src/test/resources/application-test.yml @@ -0,0 +1 @@ +MONGODB_URI: mongodb://localhost:27017/customers diff --git a/plugins/backend-application-default/src/main/java/io/zenwave360/sdk/plugins/BackendApplicationDefaultPlugin.java b/plugins/backend-application-default/src/main/java/io/zenwave360/sdk/plugins/BackendApplicationDefaultPlugin.java index 7151e0de..b3e1d773 100644 --- a/plugins/backend-application-default/src/main/java/io/zenwave360/sdk/plugins/BackendApplicationDefaultPlugin.java +++ b/plugins/backend-application-default/src/main/java/io/zenwave360/sdk/plugins/BackendApplicationDefaultPlugin.java @@ -24,6 +24,9 @@ public T processOptions() { if (getOptions().containsKey("multiModule") && "true".equals(getOptions().get("multiModule").toString())) { replaceInChain(BackendDefaultApplicationGenerator.class, BackendMultiModuleApplicationGenerator.class); } + if (getOptions().containsKey("simpleDomainPackaging") && "true".equals(getOptions().get("simpleDomainPackaging").toString())) { + replaceInChain(BackendDefaultApplicationGenerator.class, BackendSimpleDomainPackagingApplicationGenerator.class); + } return (T) this; } diff --git a/plugins/backend-application-default/src/main/java/io/zenwave360/sdk/plugins/BackendDefaultApplicationGenerator.java b/plugins/backend-application-default/src/main/java/io/zenwave360/sdk/plugins/BackendDefaultApplicationGenerator.java index cddf3dbf..278d0713 100644 --- a/plugins/backend-application-default/src/main/java/io/zenwave360/sdk/plugins/BackendDefaultApplicationGenerator.java +++ b/plugins/backend-application-default/src/main/java/io/zenwave360/sdk/plugins/BackendDefaultApplicationGenerator.java @@ -53,8 +53,10 @@ public class BackendDefaultApplicationGenerator extends AbstractZDLProjectGenera public String inboundPackage = "{{basePackage}}.core.inbound"; public String inboundDtosPackage = "{{basePackage}}.core.inbound.dtos"; public String outboundPackage = "{{basePackage}}.core.outbound"; + public String outboundRepositoryPackage = "{{basePackage}}.core.outbound.{{persistence}}"; public String coreImplementationPackage = "{{basePackage}}.core.implementation"; public String infrastructurePackage = "{{basePackage}}.infrastructure"; + public String infrastructureRepositoryPackage = "{{basePackage}}.infrastructure.{{persistence}}"; public String adaptersPackage = "{{basePackage}}.adapters"; public String outboundEventsModelPackage = "{{basePackage}}.core.outbound.events.dtos"; @@ -112,19 +114,19 @@ protected ZDLProjectTemplates configureProjectTemplates() { ts.addTemplate(ts.entityTemplates, "src/main/java","core/domain/{{persistence}}/Entity.java", "{{asPackageFolder entitiesPackage}}/{{entity.name}}.java", JAVA, skipEntity, false); ts.addTemplate(ts.entityTemplates, "src/main/java","core/outbound/{{persistence}}/{{style}}/EntityRepository.java", - "{{asPackageFolder outboundPackage}}/{{persistence}}/{{entity.className}}Repository.java", JAVA, skipEntityRepository, true); + "{{asPackageFolder outboundRepositoryPackage}}/{{entity.className}}Repository.java", JAVA, skipEntityRepository, true); ts.addTemplate(ts.entityTemplates, "src/main/java","core/inbound/dtos/EntityInput.java", "{{asPackageFolder inboundDtosPackage}}/{{entity.className}}{{inputDTOSuffix entity}}.java", JAVA, skipEntityInput, false); ts.addTemplate(ts.entityTemplates, "src/test/java","infrastructure/{{persistence}}/{{style}}/BaseRepositoryIntegrationTest.java", - "{{asPackageFolder infrastructurePackage}}/{{persistence}}/BaseRepositoryIntegrationTest.java", JAVA, skipEntityRepository, true); + "{{asPackageFolder infrastructureRepositoryPackage}}/BaseRepositoryIntegrationTest.java", JAVA, skipEntityRepository, true); ts.addTemplate(ts.entityTemplates, "src/test/java","infrastructure/{{persistence}}/{{style}}/EntityRepositoryIntegrationTest.java", - "{{asPackageFolder infrastructurePackage}}/{{persistence}}/{{entity.className}}RepositoryIntegrationTest.java", JAVA, skipEntityRepository, true); + "{{asPackageFolder infrastructureRepositoryPackage}}/{{entity.className}}RepositoryIntegrationTest.java", JAVA, skipEntityRepository, true); ts.addTemplate(ts.entityTemplates, "src/test/java","infrastructure/{{persistence}}/{{style}}/inmemory/InMemory{{capitalizeFirst persistence}}Repository.java", - "{{asPackageFolder infrastructurePackage}}/{{persistence}}/inmemory/InMemory{{capitalizeFirst persistence}}Repository.java", JAVA, skipEntityRepository, true); + "{{asPackageFolder infrastructureRepositoryPackage}}/inmemory/InMemory{{capitalizeFirst persistence}}Repository.java", JAVA, skipEntityRepository, true); ts.addTemplate(ts.entityTemplates, "src/test/java","infrastructure/{{persistence}}/{{style}}/inmemory/EntityRepositoryInMemory.java", - "{{asPackageFolder infrastructurePackage}}/{{persistence}}/inmemory/{{entity.className}}RepositoryInMemory.java", JAVA, skipEntityRepository, true); + "{{asPackageFolder infrastructureRepositoryPackage}}/inmemory/{{entity.className}}RepositoryInMemory.java", JAVA, skipEntityRepository, true); ts.addTemplate(ts.entityTemplates, "src/test/java","infrastructure/{{persistence}}/{{style}}/inmemory/InMemory{{capitalizeFirst persistence}}Repository.java", - "{{asPackageFolder infrastructurePackage}}/{{persistence}}/inmemory/InMemory{{capitalizeFirst persistence}}Repository.java", JAVA, skipEntityRepository, true); + "{{asPackageFolder infrastructureRepositoryPackage}}/inmemory/InMemory{{capitalizeFirst persistence}}Repository.java", JAVA, skipEntityRepository, true); ts.addTemplate(ts.enumTemplates, "src/main/java", "core/domain/common/Enum.java", "{{asPackageFolder entitiesPackage}}/{{enum.name}}.java", JAVA, null, false); diff --git a/plugins/backend-application-default/src/main/java/io/zenwave360/sdk/plugins/BackendMultiModuleApplicationGenerator.java b/plugins/backend-application-default/src/main/java/io/zenwave360/sdk/plugins/BackendMultiModuleApplicationGenerator.java index 0873ce54..4e1a455c 100644 --- a/plugins/backend-application-default/src/main/java/io/zenwave360/sdk/plugins/BackendMultiModuleApplicationGenerator.java +++ b/plugins/backend-application-default/src/main/java/io/zenwave360/sdk/plugins/BackendMultiModuleApplicationGenerator.java @@ -19,19 +19,19 @@ protected ZDLProjectTemplates configureProjectTemplates() { ts.addTemplate(ts.entityTemplates, "src/main/java","core/domain/{{persistence}}/Entity.java", "{{mavenModulesPrefix}}-domain", "{{asPackageFolder entitiesPackage}}/{{entity.name}}.java", JAVA, skipEntity, false); ts.addTemplate(ts.entityTemplates, "src/main/java","core/outbound/{{persistence}}/{{style}}/EntityRepository.java", "{{mavenModulesPrefix}}-domain", - "{{asPackageFolder outboundPackage}}/{{persistence}}/{{entity.className}}Repository.java", JAVA, skipEntityRepository, true); + "{{asPackageFolder outboundRepositoryPackage}}/{{entity.className}}Repository.java", JAVA, skipEntityRepository, true); ts.addTemplate(ts.entityTemplates, "src/main/java","core/inbound/dtos/EntityInput.java", "{{mavenModulesPrefix}}-domain", "{{asPackageFolder inboundDtosPackage}}/{{entity.className}}{{inputDTOSuffix entity}}.java", JAVA, skipEntityInput, false); ts.addTemplate(ts.entityTemplates, "src/test/java","infrastructure/{{persistence}}/{{style}}/BaseRepositoryIntegrationTest.java", "{{mavenModulesPrefix}}-infra", - "{{asPackageFolder infrastructurePackage}}/{{persistence}}/BaseRepositoryIntegrationTest.java", JAVA, skipEntityRepository, true); + "{{asPackageFolder infrastructureRepositoryPackage}}/BaseRepositoryIntegrationTest.java", JAVA, skipEntityRepository, true); ts.addTemplate(ts.entityTemplates, "src/test/java","infrastructure/{{persistence}}/{{style}}/EntityRepositoryIntegrationTest.java", "{{mavenModulesPrefix}}-infra", - "{{asPackageFolder infrastructurePackage}}/{{persistence}}/{{entity.className}}RepositoryIntegrationTest.java", JAVA, skipEntityRepository, true); + "{{asPackageFolder infrastructureRepositoryPackage}}/{{entity.className}}RepositoryIntegrationTest.java", JAVA, skipEntityRepository, true); ts.addTemplate(ts.entityTemplates, "src/test/java","infrastructure/{{persistence}}/{{style}}/inmemory/InMemory{{capitalizeFirst persistence}}Repository.java", "{{mavenModulesPrefix}}-impl", - "{{asPackageFolder infrastructurePackage}}/{{persistence}}/inmemory/InMemory{{capitalizeFirst persistence}}Repository.java", JAVA, skipEntityRepository, true); + "{{asPackageFolder infrastructureRepositoryPackage}}/inmemory/InMemory{{capitalizeFirst persistence}}Repository.java", JAVA, skipEntityRepository, true); ts.addTemplate(ts.entityTemplates, "src/test/java","infrastructure/{{persistence}}/{{style}}/inmemory/EntityRepositoryInMemory.java", "{{mavenModulesPrefix}}-impl", - "{{asPackageFolder infrastructurePackage}}/{{persistence}}/inmemory/{{entity.className}}RepositoryInMemory.java", JAVA, skipEntityRepository, true); + "{{asPackageFolder infrastructureRepositoryPackage}}/inmemory/{{entity.className}}RepositoryInMemory.java", JAVA, skipEntityRepository, true); ts.addTemplate(ts.entityTemplates, "src/test/java","infrastructure/{{persistence}}/{{style}}/inmemory/InMemory{{capitalizeFirst persistence}}Repository.java", "{{mavenModulesPrefix}}-impl", - "{{asPackageFolder infrastructurePackage}}/{{persistence}}/inmemory/InMemory{{capitalizeFirst persistence}}Repository.java", JAVA, skipEntityRepository, true); + "{{asPackageFolder infrastructureRepositoryPackage}}/inmemory/InMemory{{capitalizeFirst persistence}}Repository.java", JAVA, skipEntityRepository, true); ts.addTemplate(ts.enumTemplates, "src/main/java", "core/domain/common/Enum.java", "{{mavenModulesPrefix}}-domain", "{{asPackageFolder entitiesPackage}}/{{enum.name}}.java", JAVA, null, false); diff --git a/plugins/backend-application-default/src/main/java/io/zenwave360/sdk/plugins/BackendSimpleDomainPackagingApplicationGenerator.java b/plugins/backend-application-default/src/main/java/io/zenwave360/sdk/plugins/BackendSimpleDomainPackagingApplicationGenerator.java new file mode 100644 index 00000000..a52fcba3 --- /dev/null +++ b/plugins/backend-application-default/src/main/java/io/zenwave360/sdk/plugins/BackendSimpleDomainPackagingApplicationGenerator.java @@ -0,0 +1,125 @@ +package io.zenwave360.sdk.plugins; + +import static io.zenwave360.sdk.templating.OutputFormatType.JAVA; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; + +import io.zenwave360.sdk.doc.DocumentedOption; +import io.zenwave360.sdk.generators.AbstractZDLProjectGenerator; +import io.zenwave360.sdk.generators.ZDLProjectTemplates; +import io.zenwave360.sdk.options.DatabaseType; +import io.zenwave360.sdk.options.PersistenceType; +import io.zenwave360.sdk.options.ProgrammingStyle; +import io.zenwave360.sdk.utils.JSONPath; +import io.zenwave360.sdk.zdl.ZDLFindUtils; + +/** + * Generates a backend application with the following structure: +
+📦 basePackage
+   └─ 📦 config
+   └─ 📦 model (entities and aggregates)
+   └─ 📦 dtos
+   └─ 📦 events
+   ├─ 📦 mappers
+   ├─ *EventListeners (spring-cloud-streams)
+   ├─ *RestControllers (spring mvc)
+   ├─ ServiceImplementation
+   └─ *RepositoryInterface
+
+ */ +public class BackendSimpleDomainPackagingApplicationGenerator extends BackendDefaultApplicationGenerator { + + + { + configPackage = "{{basePackage}}.config"; + entitiesPackage = "{{basePackage}}.model"; + domainEventsPackage = "{{basePackage}}"; + inboundPackage = "{{basePackage}}"; + inboundDtosPackage = "{{basePackage}}.dtos"; + outboundPackage = "{{basePackage}}"; + outboundRepositoryPackage = "{{basePackage}}"; + coreImplementationPackage = "{{basePackage}}"; + infrastructurePackage = "{{basePackage}}"; + infrastructureRepositoryPackage = "{{basePackage}}"; + adaptersPackage = "{{basePackage}}"; + + outboundEventsModelPackage = "{{basePackage}}.events.dtos"; + outboundEventsPackage = "{{basePackage}}.events"; + } + + @Override + protected ZDLProjectTemplates configureProjectTemplates() { + var ts = new ZDLProjectTemplates("io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator"); + + ts.addTemplate(ts.aggregateTemplates, "src/main/java","core/domain/common/Aggregate.java", + "{{asPackageFolder entitiesPackage}}/{{aggregate.name}}.java", JAVA, null, true); + ts.addTemplate(ts.domainEventsTemplates, "src/main/java","core/domain/common/DomainEvent.java", + "{{asPackageFolder domainEventsPackage}}/{{event.name}}.java", JAVA, null, true); + + ts.addTemplate(ts.entityTemplates, "src/main/java","core/domain/{{persistence}}/Entity.java", + "{{asPackageFolder entitiesPackage}}/{{entity.name}}.java", JAVA, skipEntity, false); + ts.addTemplate(ts.entityTemplates, "src/main/java","core/outbound/{{persistence}}/{{style}}/EntityRepository.java", + "{{asPackageFolder outboundRepositoryPackage}}/{{entity.className}}Repository.java", JAVA, skipEntityRepository, true); + ts.addTemplate(ts.entityTemplates, "src/main/java","core/inbound/dtos/EntityInput.java", + "{{asPackageFolder inboundDtosPackage}}/{{entity.className}}{{inputDTOSuffix entity}}.java", JAVA, skipEntityInput, false); + ts.addTemplate(ts.entityTemplates, "src/test/java","infrastructure/{{persistence}}/{{style}}/BaseRepositoryIntegrationTest.java", + "{{asPackageFolder infrastructurePackage}}/BaseRepositoryIntegrationTest.java", JAVA, skipEntityRepository, true); + ts.addTemplate(ts.entityTemplates, "src/test/java","infrastructure/{{persistence}}/{{style}}/EntityRepositoryIntegrationTest.java", + "{{asPackageFolder infrastructureRepositoryPackage}}/{{entity.className}}RepositoryIntegrationTest.java", JAVA, skipEntityRepository, true); + ts.addTemplate(ts.entityTemplates, "src/test/java","infrastructure/{{persistence}}/{{style}}/inmemory/InMemory{{capitalizeFirst persistence}}Repository.java", + "{{asPackageFolder infrastructureRepositoryPackage}}/inmemory/InMemory{{capitalizeFirst persistence}}Repository.java", JAVA, skipEntityRepository, true); + ts.addTemplate(ts.entityTemplates, "src/test/java","infrastructure/{{persistence}}/{{style}}/inmemory/EntityRepositoryInMemory.java", + "{{asPackageFolder infrastructureRepositoryPackage}}/inmemory/{{entity.className}}RepositoryInMemory.java", JAVA, skipEntityRepository, true); + ts.addTemplate(ts.entityTemplates, "src/test/java","infrastructure/{{persistence}}/{{style}}/inmemory/InMemory{{capitalizeFirst persistence}}Repository.java", + "{{asPackageFolder infrastructureRepositoryPackage}}/inmemory/InMemory{{capitalizeFirst persistence}}Repository.java", JAVA, skipEntityRepository, true); + + ts.addTemplate(ts.enumTemplates, "src/main/java", "core/domain/common/Enum.java", + "{{asPackageFolder entitiesPackage}}/{{enum.name}}.java", JAVA, null, false); + ts.addTemplate(ts.inputEnumTemplates, "src/main/java", "core/inbound/dtos/Enum.java", + "{{asPackageFolder inboundDtosPackage}}/{{enum.name}}.java", JAVA, skipInput, false); + + ts.addTemplate(ts.inputTemplates, "src/main/java", "core/inbound/dtos/InputOrOutput.java", + "{{asPackageFolder inboundDtosPackage}}/{{entity.className}}.java", JAVA, skipInput, false); + ts.addTemplate(ts.outputTemplates, "src/main/java", "core/inbound/dtos/InputOrOutput.java", + "{{asPackageFolder inboundDtosPackage}}/{{entity.className}}.java", JAVA, null, false); + + ts.addTemplate(ts.serviceTemplates, "src/main/java", "core/inbound/Service.java", + "{{asPackageFolder inboundPackage}}/{{service.name}}.java", JAVA, null, false); + ts.addTemplate(ts.serviceTemplates, "src/main/java", "core/implementation/{{style}}/ServiceImpl.java", + "{{asPackageFolder coreImplementationPackage}}/{{service.name}}Impl.java", JAVA, null, true); + ts.addTemplate(ts.singleTemplates, "src/main/java", "core/implementation/mappers/BaseMapper.java", + "{{asPackageFolder coreImplementationPackage}}/mappers/BaseMapper.java", JAVA, null, true); + ts.addTemplate(ts.serviceTemplates, "src/main/java","core/implementation/mappers/ServiceMapper.java", + "{{asPackageFolder coreImplementationPackage}}/mappers/{{service.name}}Mapper.java", JAVA, null, true); + ts.addTemplate(ts.serviceTemplates, "src/test/java", "core/implementation/{{persistence}}/{{style}}/ServiceTest.java", + "{{asPackageFolder coreImplementationPackage}}/{{service.name}}Test.java", JAVA, null, true); + + ts.addTemplate(ts.allServicesTemplates, "src/main/java", "core/implementation/mappers/EventsMapper.java", + "{{asPackageFolder coreImplementationPackage}}/mappers/EventsMapper.java", JAVA, skipEvents, true); + ts.addTemplate(ts.allServicesTemplates, "src/test/java", "config/RepositoriesInMemoryConfig.java", + "{{asPackageFolder configPackage}}/RepositoriesInMemoryConfig.java", JAVA, null, true); + ts.addTemplate(ts.allServicesTemplates, "src/test/java", "config/ServicesInMemoryConfig.java", + "{{asPackageFolder configPackage}}/ServicesInMemoryConfig.java", JAVA, null, true); + + ts.addTemplate(ts.singleTemplates, "src/test/java", "config/TestDataLoader-{{persistence}}.java", + "{{asPackageFolder configPackage}}/TestDataLoader.java", JAVA, null, true); + ts.addTemplate(ts.singleTemplates, "src/test/java", "config/DockerComposeInitializer-{{persistence}}.java", + "{{asPackageFolder configPackage}}/DockerComposeInitializer.java", JAVA, null, true); + + ts.addTemplate(ts.singleTemplates, "src/main/java", "core/inbound/dtos/package-info.java", + "{{asPackageFolder inboundDtosPackage}}/package-info.java", JAVA, null, true); + ts.addTemplate(ts.singleTemplates, "src/main/java", "infrastructure/package-info.java", + "{{asPackageFolder infrastructurePackage}}/package-info.java", JAVA, null, true); + ts.addTemplate(ts.singleTemplates, "src/test/java", "ArchitectureTest.java", + "{{asPackageFolder basePackage}}/ArchitectureTest.java", JAVA, null, true); + + return ts; + } + +} diff --git a/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/main/java/core/domain/jpa/Entity.java.hbs b/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/main/java/core/domain/jpa/Entity.java.hbs index d0d6b74f..4e5fdf83 100644 --- a/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/main/java/core/domain/jpa/Entity.java.hbs +++ b/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/main/java/core/domain/jpa/Entity.java.hbs @@ -204,7 +204,7 @@ public {{abstractClass entity}} class {{entity.className}} {{addExtends entity}} return false; } {{entity.className}} other = ({{entity.className}}) o; - return id != null && id.equals(other.getId()); + return id != null && id.equals(other.id); } @Override diff --git a/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/main/java/core/domain/mongodb/Entity.java.hbs b/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/main/java/core/domain/mongodb/Entity.java.hbs index 336a1464..a40a963e 100644 --- a/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/main/java/core/domain/mongodb/Entity.java.hbs +++ b/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/main/java/core/domain/mongodb/Entity.java.hbs @@ -123,7 +123,7 @@ public {{abstractClass entity}} class {{entity.className}} {{addExtends entity}} return false; } {{entity.className}} other = ({{entity.className}}) o; - return id != null && id.equals(other.getId()); + return id != null && id.equals(other.id); } @Override diff --git a/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/main/java/core/implementation/imperative/ServiceImpl.java.hbs b/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/main/java/core/implementation/imperative/ServiceImpl.java.hbs index 91444527..f542cd04 100644 --- a/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/main/java/core/implementation/imperative/ServiceImpl.java.hbs +++ b/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/main/java/core/implementation/imperative/ServiceImpl.java.hbs @@ -4,7 +4,7 @@ import {{entitiesPackage}}.*; import {{inboundPackage}}.*; import {{inboundDtosPackage}}.*; import {{coreImplementationPackage}}.mappers.*; -import {{outboundPackage}}.{{persistence}}.*; +import {{outboundRepositoryPackage}}.*; {{#if includeEmitEventsImplementation}} import {{outboundEventsPackage}}.*; {{/if}} diff --git a/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/main/java/core/outbound/jpa/imperative/EntityRepository.java.hbs b/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/main/java/core/outbound/jpa/imperative/EntityRepository.java.hbs index 7678c35a..6646d105 100644 --- a/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/main/java/core/outbound/jpa/imperative/EntityRepository.java.hbs +++ b/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/main/java/core/outbound/jpa/imperative/EntityRepository.java.hbs @@ -1,6 +1,6 @@ -package {{basePackage}}.core.outbound.jpa; +package {{outboundRepositoryPackage}}; -import {{basePackage}}.core.domain.{{entity.className}}; +import {{entitiesPackage}}.{{entity.className}}; import org.springframework.data.jpa.repository.*; import org.springframework.stereotype.Repository; diff --git a/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/main/java/core/outbound/mongodb/imperative/EntityRepository.java.hbs b/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/main/java/core/outbound/mongodb/imperative/EntityRepository.java.hbs index bf03ea91..5f97ae4c 100644 --- a/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/main/java/core/outbound/mongodb/imperative/EntityRepository.java.hbs +++ b/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/main/java/core/outbound/mongodb/imperative/EntityRepository.java.hbs @@ -1,4 +1,4 @@ -package {{outboundPackage}}.mongodb; +package {{outboundRepositoryPackage}}; {{~assign 'aggregate' (findEntityAggregate entity.name)}} import {{entitiesPackage}}.{{entity.className}}; diff --git a/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/test/java/config/RepositoriesInMemoryConfig.java.hbs b/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/test/java/config/RepositoriesInMemoryConfig.java.hbs index 4f57c970..b13c8d5a 100644 --- a/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/test/java/config/RepositoriesInMemoryConfig.java.hbs +++ b/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/test/java/config/RepositoriesInMemoryConfig.java.hbs @@ -1,10 +1,10 @@ -package {{basePackage}}.config; +package {{configPackage}}; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Primary; -import {{basePackage}}.core.outbound.{{persistence}}.*; -import {{infrastructurePackage}}.{{persistence}}.inmemory.*; +import {{outboundRepositoryPackage}}.*; +import {{infrastructureRepositoryPackage}}.inmemory.*; //@Configuration diff --git a/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/test/java/core/implementation/jpa/imperative/ServiceTest.java.hbs b/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/test/java/core/implementation/jpa/imperative/ServiceTest.java.hbs index f56c3340..64091edb 100644 --- a/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/test/java/core/implementation/jpa/imperative/ServiceTest.java.hbs +++ b/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/test/java/core/implementation/jpa/imperative/ServiceTest.java.hbs @@ -1,12 +1,12 @@ package {{coreImplementationPackage}}; -import {{basePackage}}.config.*; +import {{configPackage}}.*; import {{entitiesPackage}}.*; import {{inboundPackage}}.*; import {{inboundDtosPackage}}.*; -import {{basePackage}}.core.implementation.mappers.*; -import {{basePackage}}.core.outbound.jpa.*; -import {{infrastructurePackage}}.jpa.inmemory.*; +import {{coreImplementationPackage}}.mappers.*; +import {{outboundRepositoryPackage}}.*; +import {{infrastructureRepositoryPackage}}.inmemory.*; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.MethodOrderer; diff --git a/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/test/java/core/implementation/mongodb/imperative/ServiceTest.java.hbs b/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/test/java/core/implementation/mongodb/imperative/ServiceTest.java.hbs index c2935202..384f8882 100644 --- a/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/test/java/core/implementation/mongodb/imperative/ServiceTest.java.hbs +++ b/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/test/java/core/implementation/mongodb/imperative/ServiceTest.java.hbs @@ -1,12 +1,13 @@ package {{coreImplementationPackage}}; -import {{basePackage}}.config.*; +import {{configPackage}}.*; import {{entitiesPackage}}.*; import {{inboundPackage}}.*; import {{inboundDtosPackage}}.*; -import {{basePackage}}.core.implementation.mappers.*; -import {{basePackage}}.core.outbound.mongodb.*; -import {{infrastructurePackage}}.mongodb.inmemory.*; +import {{coreImplementationPackage}}.mappers.*; +import {{outboundRepositoryPackage}}.*; +import {{infrastructureRepositoryPackage}}.inmemory.*; + import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.MethodOrderer; diff --git a/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/test/java/infrastructure/jpa/imperative/EntityRepositoryIntegrationTest.java.hbs b/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/test/java/infrastructure/jpa/imperative/EntityRepositoryIntegrationTest.java.hbs index 7568d6b2..a8635df8 100644 --- a/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/test/java/infrastructure/jpa/imperative/EntityRepositoryIntegrationTest.java.hbs +++ b/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/test/java/infrastructure/jpa/imperative/EntityRepositoryIntegrationTest.java.hbs @@ -5,7 +5,7 @@ import java.time.*; import java.math.BigDecimal; import {{entitiesPackage}}.*; -import {{basePackage}}.core.outbound.jpa.{{entity.className}}Repository; +import {{outboundRepositoryPackage}}.{{entity.className}}Repository; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; diff --git a/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/test/java/infrastructure/jpa/imperative/inmemory/EntityRepositoryInMemory.java.hbs b/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/test/java/infrastructure/jpa/imperative/inmemory/EntityRepositoryInMemory.java.hbs index 38bc493d..a55e97ab 100644 --- a/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/test/java/infrastructure/jpa/imperative/inmemory/EntityRepositoryInMemory.java.hbs +++ b/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/test/java/infrastructure/jpa/imperative/inmemory/EntityRepositoryInMemory.java.hbs @@ -1,7 +1,7 @@ -package {{infrastructurePackage}}.jpa.inmemory; +package {{infrastructureRepositoryPackage}}.inmemory; import {{entitiesPackage}}.*; -import {{basePackage}}.core.outbound.jpa.{{entity.className}}Repository; +import {{outboundRepositoryPackage}}.{{entity.className}}Repository; public class {{entity.className}}RepositoryInMemory extends InMemoryJpaRepository<{{entity.className}}> implements {{entity.className}}Repository { } diff --git a/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/test/java/infrastructure/jpa/imperative/inmemory/InMemoryJpaRepository.java.hbs b/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/test/java/infrastructure/jpa/imperative/inmemory/InMemoryJpaRepository.java.hbs index 1657c4fd..56db5c2d 100644 --- a/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/test/java/infrastructure/jpa/imperative/inmemory/InMemoryJpaRepository.java.hbs +++ b/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/test/java/infrastructure/jpa/imperative/inmemory/InMemoryJpaRepository.java.hbs @@ -1,4 +1,4 @@ -package {{infrastructurePackage}}.jpa.inmemory; +package {{infrastructureRepositoryPackage}}.inmemory; import org.springframework.dao.EmptyResultDataAccessException; import org.springframework.data.domain.Example; diff --git a/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/test/java/infrastructure/mongodb/imperative/EntityRepositoryIntegrationTest.java.hbs b/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/test/java/infrastructure/mongodb/imperative/EntityRepositoryIntegrationTest.java.hbs index c0a6482d..a990b7ae 100644 --- a/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/test/java/infrastructure/mongodb/imperative/EntityRepositoryIntegrationTest.java.hbs +++ b/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/test/java/infrastructure/mongodb/imperative/EntityRepositoryIntegrationTest.java.hbs @@ -1,7 +1,7 @@ package {{infrastructurePackage}}.mongodb; import {{entitiesPackage}}.*; -import {{basePackage}}.core.outbound.mongodb.{{entity.className}}Repository; +import {{outboundRepositoryPackage}}.{{entity.className}}Repository; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; diff --git a/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/test/java/infrastructure/mongodb/imperative/inmemory/EntityRepositoryInMemory.java.hbs b/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/test/java/infrastructure/mongodb/imperative/inmemory/EntityRepositoryInMemory.java.hbs index afc6498d..39ded41a 100644 --- a/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/test/java/infrastructure/mongodb/imperative/inmemory/EntityRepositoryInMemory.java.hbs +++ b/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/test/java/infrastructure/mongodb/imperative/inmemory/EntityRepositoryInMemory.java.hbs @@ -1,7 +1,7 @@ -package {{infrastructurePackage}}.mongodb.inmemory; +package {{infrastructureRepositoryPackage}}.inmemory; import {{entitiesPackage}}.*; -import {{basePackage}}.core.outbound.mongodb.{{entity.className}}Repository; +import {{outboundRepositoryPackage}}.{{entity.className}}Repository; public class {{entity.className}}RepositoryInMemory extends InMemoryMongodbRepository<{{entity.className}}> implements {{entity.className}}Repository { } diff --git a/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/test/java/infrastructure/mongodb/imperative/inmemory/InMemoryMongodbRepository.java.hbs b/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/test/java/infrastructure/mongodb/imperative/inmemory/InMemoryMongodbRepository.java.hbs index 2744e024..4ed9a5d5 100644 --- a/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/test/java/infrastructure/mongodb/imperative/inmemory/InMemoryMongodbRepository.java.hbs +++ b/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/test/java/infrastructure/mongodb/imperative/inmemory/InMemoryMongodbRepository.java.hbs @@ -1,4 +1,4 @@ -package {{infrastructurePackage}}.mongodb.inmemory; +package {{infrastructureRepositoryPackage}}.inmemory; import org.springframework.dao.EmptyResultDataAccessException; import org.springframework.data.domain.Example; diff --git a/plugins/openapi-controllers/src/main/resources/io/zenwave360/sdk/plugins/OpenAPIControllersGenerator/src/main/java/web/mappers/BaseMapper.java.hbs b/plugins/openapi-controllers/src/main/resources/io/zenwave360/sdk/plugins/OpenAPIControllersGenerator/src/main/java/web/mappers/BaseMapper.java.hbs index d632adfe..1fc85181 100644 --- a/plugins/openapi-controllers/src/main/resources/io/zenwave360/sdk/plugins/OpenAPIControllersGenerator/src/main/java/web/mappers/BaseMapper.java.hbs +++ b/plugins/openapi-controllers/src/main/resources/io/zenwave360/sdk/plugins/OpenAPIControllersGenerator/src/main/java/web/mappers/BaseMapper.java.hbs @@ -7,13 +7,13 @@ import java.time.OffsetDateTime; import java.util.TimeZone; @Mapper -public abstract class BaseMapper { +public interface BaseMapper { - public Instant asInstant(OffsetDateTime date) { + default Instant asInstant(OffsetDateTime date) { return date != null? date.toInstant() : null; } - public OffsetDateTime asOffsetDateTime(Instant date) { + default OffsetDateTime asOffsetDateTime(Instant date) { return date != null? OffsetDateTime.ofInstant(date, TimeZone.getTimeZone("UTC").toZoneId()) : null; } } From 2945a6eedb05e242b0fe52a273a718d0c3e19164 Mon Sep 17 00:00:00 2001 From: Ivan Garcia Sainz-Aja Date: Sun, 5 May 2024 12:11:57 +0200 Subject: [PATCH 4/7] adds support for SimpleDomainPackaging --- ...leDomainPackagingApplicationGenerator.java | 7 +++--- ...plicationMongoImperativeGeneratorTest.java | 24 +++++++++++++++++++ .../sdk/resources/zdl/customer-address.zdl | 2 +- 3 files changed, 28 insertions(+), 5 deletions(-) diff --git a/plugins/backend-application-default/src/main/java/io/zenwave360/sdk/plugins/BackendSimpleDomainPackagingApplicationGenerator.java b/plugins/backend-application-default/src/main/java/io/zenwave360/sdk/plugins/BackendSimpleDomainPackagingApplicationGenerator.java index a52fcba3..ad3a41a2 100644 --- a/plugins/backend-application-default/src/main/java/io/zenwave360/sdk/plugins/BackendSimpleDomainPackagingApplicationGenerator.java +++ b/plugins/backend-application-default/src/main/java/io/zenwave360/sdk/plugins/BackendSimpleDomainPackagingApplicationGenerator.java @@ -114,10 +114,9 @@ protected ZDLProjectTemplates configureProjectTemplates() { ts.addTemplate(ts.singleTemplates, "src/main/java", "core/inbound/dtos/package-info.java", "{{asPackageFolder inboundDtosPackage}}/package-info.java", JAVA, null, true); - ts.addTemplate(ts.singleTemplates, "src/main/java", "infrastructure/package-info.java", - "{{asPackageFolder infrastructurePackage}}/package-info.java", JAVA, null, true); - ts.addTemplate(ts.singleTemplates, "src/test/java", "ArchitectureTest.java", - "{{asPackageFolder basePackage}}/ArchitectureTest.java", JAVA, null, true); + +// ts.addTemplate(ts.singleTemplates, "src/test/java", "ArchitectureTest.java", +// "{{asPackageFolder basePackage}}/ArchitectureTest.java", JAVA, null, true); return ts; } diff --git a/plugins/backend-application-default/src/test/java/io/zenwave360/sdk/plugins/BackendApplicationMongoImperativeGeneratorTest.java b/plugins/backend-application-default/src/test/java/io/zenwave360/sdk/plugins/BackendApplicationMongoImperativeGeneratorTest.java index fa188a3e..c2bf6804 100644 --- a/plugins/backend-application-default/src/test/java/io/zenwave360/sdk/plugins/BackendApplicationMongoImperativeGeneratorTest.java +++ b/plugins/backend-application-default/src/test/java/io/zenwave360/sdk/plugins/BackendApplicationMongoImperativeGeneratorTest.java @@ -57,6 +57,30 @@ public void test_generator_hexagonal_mongodb_customer_address() throws Exception Assertions.assertEquals(0, exitCode); } + @Test + public void test_generator_simple_packaging_mongodb_customer_address() throws Exception { + String targetFolder = "target/zdl/test_generator_simple_packaging_mongodb_customer_address"; + Plugin plugin = new BackendApplicationDefaultPlugin() + .withSpecFile("classpath:io/zenwave360/sdk/resources/zdl/customer-address.zdl") + .withTargetFolder(targetFolder) + .withOption("basePackage", "io.zenwave360.example") + .withOption("persistence", PersistenceType.mongodb) + .withOption("style", ProgrammingStyle.imperative) + .withOption("projectName", "customer-address") + .withOption("simpleDomainPackaging", true) + .withOption("forceOverwrite", true) + .withOption("haltOnFailFormatting", false); + + new MainGenerator().generate(plugin); + + List logs = logCaptor.getLogs(); + // Assertions.assertTrue(logs.contains("Writing template with targetFile: io/example/integration/test/api/provider_for_commands_reactive/DoCreateProductConsumer.java")); + // Assertions.assertTrue(logs.contains("Writing template with targetFile: io/example/integration/test/api/provider_for_commands_reactive/DoCreateProductService.java")); + + int exitCode = MavenCompiler.copyPomAndCompile("src/test/resources/mongodb-elasticsearch-scs3-pom.xml", targetFolder); + Assertions.assertEquals(0, exitCode); + } + @Test public void test_generator_hexagonal_mongodb_order_faults_attachments() throws Exception { String targetFolder = "target/zdl/test_generator_hexagonal_mongodb_order_faults_attachments"; diff --git a/zenwave-sdk-test-resources/src/main/resources/io/zenwave360/sdk/resources/zdl/customer-address.zdl b/zenwave-sdk-test-resources/src/main/resources/io/zenwave360/sdk/resources/zdl/customer-address.zdl index a6b2184c..fcdba84a 100644 --- a/zenwave-sdk-test-resources/src/main/resources/io/zenwave360/sdk/resources/zdl/customer-address.zdl +++ b/zenwave-sdk-test-resources/src/main/resources/io/zenwave360/sdk/resources/zdl/customer-address.zdl @@ -24,7 +24,7 @@ entity Customer { /** * address is a nested entity */ - address Address[] { + addresses Address[] { street String /** street javadoc comment */ city String /** city javadoc comment */ state String /** state javadoc comment */ From f5d3809d215709f2ec8e4a505701270ba5475424 Mon Sep 17 00:00:00 2001 From: Ivan Garcia Sainz-Aja Date: Wed, 27 Mar 2024 13:22:15 +0100 Subject: [PATCH 5/7] adds support for SimpleDomainPackaging --- README.md | 8 +++---- ...ackendMultiModuleApplicationGenerator.java | 24 ++++++++++--------- .../core/domain/jpa/partials/OneToOne.hbs | 2 +- .../config/ServicesInMemoryConfig.java.hbs | 5 ++-- ...plicationMongoImperativeGeneratorTest.java | 2 +- plugins/openapi-controllers/README.md | 4 ++-- .../sdk/plugins/OpenAPIControllersPlugin.java | 5 +++- .../sdk/processors/ZDLProcessor.java | 3 ++- 8 files changed, 30 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 1db07b24..90be99f5 100644 --- a/README.md +++ b/README.md @@ -37,25 +37,25 @@ ZenWave SDK is a configurable and extensible toolkit for **Domain Driven Design The easiest way to install ZenWave SDK is as a [JBang alias](https://www.jbang.dev/documentation/guide/latest/alias_catalogs.html): ```shell -jbang alias add --fresh --name=zw release@zenwave360/zenwave-sdk +jbang alias add --fresh --force --name=zw release@zenwave360/zenwave-sdk ``` or if you prefer to use the latest **snapshot** versions: ```shell -jbang alias add --fresh --name=zw snapshots@zenwave360/zenwave-sdk +jbang alias add --fresh --force --name=zw snapshots@zenwave360/zenwave-sdk ``` or if you prefer to use the _next_ experimental/unstable **snapshot** versions: ```shell -jbang alias add --fresh --name=zw next@zenwave360/zenwave-sdk +jbang alias add --fresh --force --name=zw next@zenwave360/zenwave-sdk ``` If you plan to use **custom plugins** you will need to use the command in the following format: ```shell -jbang alias add --name=zw \ +jbang alias add --name=zw --force \ -m=io.zenwave360.sdk.Main \ --repos=mavencentral,snapshots=https://s01.oss.sonatype.org/content/repositories/snapshots \ --deps=\ diff --git a/plugins/backend-application-default/src/main/java/io/zenwave360/sdk/plugins/BackendMultiModuleApplicationGenerator.java b/plugins/backend-application-default/src/main/java/io/zenwave360/sdk/plugins/BackendMultiModuleApplicationGenerator.java index 4e1a455c..9ee7741a 100644 --- a/plugins/backend-application-default/src/main/java/io/zenwave360/sdk/plugins/BackendMultiModuleApplicationGenerator.java +++ b/plugins/backend-application-default/src/main/java/io/zenwave360/sdk/plugins/BackendMultiModuleApplicationGenerator.java @@ -26,11 +26,11 @@ protected ZDLProjectTemplates configureProjectTemplates() { "{{asPackageFolder infrastructureRepositoryPackage}}/BaseRepositoryIntegrationTest.java", JAVA, skipEntityRepository, true); ts.addTemplate(ts.entityTemplates, "src/test/java","infrastructure/{{persistence}}/{{style}}/EntityRepositoryIntegrationTest.java", "{{mavenModulesPrefix}}-infra", "{{asPackageFolder infrastructureRepositoryPackage}}/{{entity.className}}RepositoryIntegrationTest.java", JAVA, skipEntityRepository, true); - ts.addTemplate(ts.entityTemplates, "src/test/java","infrastructure/{{persistence}}/{{style}}/inmemory/InMemory{{capitalizeFirst persistence}}Repository.java", "{{mavenModulesPrefix}}-impl", + ts.addTemplate(ts.entityTemplates, "src/test/java","infrastructure/{{persistence}}/{{style}}/inmemory/InMemory{{capitalizeFirst persistence}}Repository.java", "{{mavenModulesPrefix}}-core-impl", "{{asPackageFolder infrastructureRepositoryPackage}}/inmemory/InMemory{{capitalizeFirst persistence}}Repository.java", JAVA, skipEntityRepository, true); - ts.addTemplate(ts.entityTemplates, "src/test/java","infrastructure/{{persistence}}/{{style}}/inmemory/EntityRepositoryInMemory.java", "{{mavenModulesPrefix}}-impl", + ts.addTemplate(ts.entityTemplates, "src/test/java","infrastructure/{{persistence}}/{{style}}/inmemory/EntityRepositoryInMemory.java", "{{mavenModulesPrefix}}-core-impl", "{{asPackageFolder infrastructureRepositoryPackage}}/inmemory/{{entity.className}}RepositoryInMemory.java", JAVA, skipEntityRepository, true); - ts.addTemplate(ts.entityTemplates, "src/test/java","infrastructure/{{persistence}}/{{style}}/inmemory/InMemory{{capitalizeFirst persistence}}Repository.java", "{{mavenModulesPrefix}}-impl", + ts.addTemplate(ts.entityTemplates, "src/test/java","infrastructure/{{persistence}}/{{style}}/inmemory/InMemory{{capitalizeFirst persistence}}Repository.java", "{{mavenModulesPrefix}}-core-impl", "{{asPackageFolder infrastructureRepositoryPackage}}/inmemory/InMemory{{capitalizeFirst persistence}}Repository.java", JAVA, skipEntityRepository, true); ts.addTemplate(ts.enumTemplates, "src/main/java", "core/domain/common/Enum.java", "{{mavenModulesPrefix}}-domain", @@ -45,23 +45,25 @@ protected ZDLProjectTemplates configureProjectTemplates() { ts.addTemplate(ts.serviceTemplates, "src/main/java", "core/inbound/Service.java", "{{mavenModulesPrefix}}-domain", "{{asPackageFolder inboundPackage}}/{{service.name}}.java", JAVA, null, false); - ts.addTemplate(ts.serviceTemplates, "src/main/java", "core/implementation/{{style}}/ServiceImpl.java", "{{mavenModulesPrefix}}-impl", + ts.addTemplate(ts.serviceTemplates, "src/main/java", "core/implementation/{{style}}/ServiceImpl.java", "{{mavenModulesPrefix}}-core-impl", "{{asPackageFolder coreImplementationPackage}}/{{service.name}}Impl.java", JAVA, null, true); - ts.addTemplate(ts.serviceTemplates, "src/main/java","core/implementation/mappers/ServiceMapper.java", "{{mavenModulesPrefix}}-impl", + ts.addTemplate(ts.singleTemplates, "src/main/java", "core/implementation/mappers/BaseMapper.java", "{{mavenModulesPrefix}}-domain", + "{{asPackageFolder coreImplementationPackage}}/mappers/BaseMapper.java", JAVA, null, true); + ts.addTemplate(ts.serviceTemplates, "src/main/java","core/implementation/mappers/ServiceMapper.java", "{{mavenModulesPrefix}}-core-impl", "{{asPackageFolder coreImplementationPackage}}/mappers/{{service.name}}Mapper.java", JAVA, null, true); - ts.addTemplate(ts.serviceTemplates, "src/test/java", "core/implementation/{{persistence}}/{{style}}/ServiceTest.java", "{{mavenModulesPrefix}}-impl", + ts.addTemplate(ts.serviceTemplates, "src/test/java", "core/implementation/{{persistence}}/{{style}}/ServiceTest.java", "{{mavenModulesPrefix}}-core-impl", "{{asPackageFolder coreImplementationPackage}}/{{service.name}}Test.java", JAVA, null, true); - ts.addTemplate(ts.allServicesTemplates, "src/main/java", "core/implementation/mappers/EventsMapper.java", + ts.addTemplate(ts.allServicesTemplates, "src/main/java", "core/implementation/mappers/EventsMapper.java","{{mavenModulesPrefix}}-core-impl", "{{asPackageFolder coreImplementationPackage}}/mappers/EventsMapper.java", JAVA, skipEvents, true); - ts.addTemplate(ts.allServicesTemplates, "src/test/java", "config/RepositoriesInMemoryConfig.java", "{{mavenModulesPrefix}}-impl", + ts.addTemplate(ts.allServicesTemplates, "src/test/java", "config/RepositoriesInMemoryConfig.java", "{{mavenModulesPrefix}}-core-impl", "{{asPackageFolder configPackage}}/RepositoriesInMemoryConfig.java", JAVA, null, true); - ts.addTemplate(ts.allServicesTemplates, "src/test/java", "config/ServicesInMemoryConfig.java", "{{mavenModulesPrefix}}-impl", + ts.addTemplate(ts.allServicesTemplates, "src/test/java", "config/ServicesInMemoryConfig.java", "{{mavenModulesPrefix}}-core-impl", "{{asPackageFolder configPackage}}/ServicesInMemoryConfig.java", JAVA, null, true); - ts.addTemplate(ts.singleTemplates, "src/test/java", "config/TestDataLoader-{{persistence}}.java", "{{mavenModulesPrefix}}-impl", + ts.addTemplate(ts.singleTemplates, "src/test/java", "config/TestDataLoader-{{persistence}}.java", "{{mavenModulesPrefix}}-core-impl", "{{asPackageFolder configPackage}}/TestDataLoader.java", JAVA, null, true); - ts.addTemplate(ts.singleTemplates, "src/test/java", "config/DockerComposeInitializer-{{persistence}}.java", "{{mavenModulesPrefix}}-impl", + ts.addTemplate(ts.singleTemplates, "src/test/java", "config/DockerComposeInitializer-{{persistence}}.java", "{{mavenModulesPrefix}}-core-impl", "{{asPackageFolder configPackage}}/DockerComposeInitializer.java", JAVA, null, true); ts.addTemplate(ts.singleTemplates, "src/main/java", "core/inbound/dtos/package-info.java", "{{mavenModulesPrefix}}-domain", diff --git a/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/main/java/core/domain/jpa/partials/OneToOne.hbs b/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/main/java/core/domain/jpa/partials/OneToOne.hbs index 80cc51ca..055f5707 100644 --- a/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/main/java/core/domain/jpa/partials/OneToOne.hbs +++ b/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/main/java/core/domain/jpa/partials/OneToOne.hbs @@ -3,13 +3,13 @@ {{~#if relationship.required}} @NotNull {{~/if}} +{{~else~}} {{~#if relationship.mapsId}} @MapsId @JoinColumn(name = "id") {{~else}} @JoinColumn(unique = true) {{/if~}} -{{~else~}} @OneToOne(mappedBy = "{{relationship.otherEntityFieldName}}", fetch = FetchType.LAZY {{#if entity.options.aggregate}}, cascade = CascadeType.ALL, orphanRemoval = true{{/if}}) {{/if~}} diff --git a/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/test/java/config/ServicesInMemoryConfig.java.hbs b/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/test/java/config/ServicesInMemoryConfig.java.hbs index ea59afc7..044fab97 100644 --- a/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/test/java/config/ServicesInMemoryConfig.java.hbs +++ b/plugins/backend-application-default/src/main/resources/io/zenwave360/sdk/plugins/BackendApplicationDefaultGenerator/src/test/java/config/ServicesInMemoryConfig.java.hbs @@ -4,6 +4,7 @@ package {{basePackage}}.config; import {{entitiesPackage}}.*; {{/if}} {{#if services}} +import {{inboundPackage}}.*; import {{coreImplementationPackage}}.*; {{/if}} {{#if includeEmitEventsImplementation}} @@ -49,8 +50,8 @@ public class ServicesInMemoryConfig extends RepositoriesInMemoryConfig { {{~#each services as |service|}} @Bean - public {{service.name}}Impl {{asInstanceName service.name}}() { - return {{asInstanceName service.name}}; + public T {{asInstanceName service.name}}() { + return (T) {{asInstanceName service.name}}; } {{~/each}} diff --git a/plugins/backend-application-default/src/test/java/io/zenwave360/sdk/plugins/BackendApplicationMongoImperativeGeneratorTest.java b/plugins/backend-application-default/src/test/java/io/zenwave360/sdk/plugins/BackendApplicationMongoImperativeGeneratorTest.java index c2bf6804..37700449 100644 --- a/plugins/backend-application-default/src/test/java/io/zenwave360/sdk/plugins/BackendApplicationMongoImperativeGeneratorTest.java +++ b/plugins/backend-application-default/src/test/java/io/zenwave360/sdk/plugins/BackendApplicationMongoImperativeGeneratorTest.java @@ -42,7 +42,7 @@ public void test_generator_hexagonal_mongodb_customer_address() throws Exception .withOption("basePackage", "io.zenwave360.example") .withOption("persistence", PersistenceType.mongodb) .withOption("style", ProgrammingStyle.imperative) - .withOption("projectName", "customer-address") + .withOption("mavenModulesPrefix", "customer-address") .withOption("multiModule", true) .withOption("forceOverwrite", true) .withOption("haltOnFailFormatting", false); diff --git a/plugins/openapi-controllers/README.md b/plugins/openapi-controllers/README.md index 45ff6bdf..012db7fa 100644 --- a/plugins/openapi-controllers/README.md +++ b/plugins/openapi-controllers/README.md @@ -7,7 +7,7 @@ After you have generated SpringMVC interfaces and DTOs with OpenAPI generator, y ```shell jbang zw -p io.zenwave360.sdk.plugins.OpenAPIControllersPlugin - specFile=src/main/resources/model/openapi.yml \ + openapiFile=src/main/resources/model/openapi.yml \ zdlFile=src/main/resources/model/orders-model.jdl \ basePackage=io.zenwave360.example \ openApiApiPackage=io.zenwave360.example.adapters.web \ @@ -20,7 +20,7 @@ jbang zw -p io.zenwave360.sdk.plugins.OpenAPIControllersPlugin | **Option** | **Description** | **Type** | **Default** | **Values** | |-----------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------|---------------------------------------|-----------------------------------| -| `specFile` | OpenAPI Specification File | URI | | | +| `openapiFile` | OpenAPI Specification File | String | | | | `zdlFile` | ZDL file to parse | String | | | | `targetFolder` | Target folder to generate code to. If left empty, it will print to stdout. | File | | | | `style` | Programming Style | ProgrammingStyle | imperative | imperative, reactive | diff --git a/plugins/openapi-controllers/src/main/java/io/zenwave360/sdk/plugins/OpenAPIControllersPlugin.java b/plugins/openapi-controllers/src/main/java/io/zenwave360/sdk/plugins/OpenAPIControllersPlugin.java index bd07cb21..69f51531 100644 --- a/plugins/openapi-controllers/src/main/java/io/zenwave360/sdk/plugins/OpenAPIControllersPlugin.java +++ b/plugins/openapi-controllers/src/main/java/io/zenwave360/sdk/plugins/OpenAPIControllersPlugin.java @@ -28,6 +28,9 @@ @DocumentedPlugin(value = "Generates implementations based on ZDL models and OpenAPI definitions SpringMVC generated OpenAPI interfaces.", shortCode = "openapi-controllers") public class OpenAPIControllersPlugin extends Plugin { + @DocumentedOption(description = "OpenAPI file to parse", required = false) + public String openapiFile; + @DocumentedOption(description = "ZDL file to parse", required = false) public String zdlFile; @@ -46,7 +49,7 @@ public T processOptions() { } // because we have more than one model, we need to configure how they are passed around from parser to processor and generator // we use class name for passing the properties, in case one class is repeated in chain we'd use the index number in the chain - withOption("DefaultYamlParser.specFile", StringUtils.firstNonBlank(this.getSpecFile(), (String) getOptions().get("openapiFile"))); + withOption("DefaultYamlParser.specFile", StringUtils.firstNonBlank((String) getOptions().get("openapiFile"), this.getSpecFile())); withOption("ZDLParser.specFile", getOptions().get("zdlFile")); return (T) this; } diff --git a/zenwave-sdk-cli/src/main/java/io/zenwave360/sdk/processors/ZDLProcessor.java b/zenwave-sdk-cli/src/main/java/io/zenwave360/sdk/processors/ZDLProcessor.java index d21cbc6e..c7dc6a1f 100644 --- a/zenwave-sdk-cli/src/main/java/io/zenwave360/sdk/processors/ZDLProcessor.java +++ b/zenwave-sdk-cli/src/main/java/io/zenwave360/sdk/processors/ZDLProcessor.java @@ -142,7 +142,7 @@ protected Map buildRelationship(String entityName, Map relationship) { relationshipMap.put("entityName", from); relationshipMap.put("otherEntityName", to); relationshipMap.put("ownerSide", true); - relationshipMap.put("mapsId", JSONPath.get(relationship, "toOptions.Id", false)); +// relationshipMap.put("mapsId", JSONPath.get(relationship, "toOptions.Id", false)); relationshipMap.put("isCollection", relationship.get("type").toString().endsWith("Many")); if(relationship.get("injectedFieldInFrom") != null) { var fillInjectedFieldInFrom = StringUtils.replace((String) relationship.get("injectedFieldInFrom"), ")","").split("\\("); @@ -157,6 +157,7 @@ protected Map buildRelationship(String entityName, Map relationship) { relationshipMap.put("entityName", to); relationshipMap.put("otherEntityName", from); relationshipMap.put("ownerSide", false); + relationshipMap.put("mapsId", JSONPath.get(relationship, "toOptions.Id", false)); relationshipMap.put("isCollection", relationship.get("type").toString().startsWith("Many")); if(relationship.get("injectedFieldInTo") != null) { var fillInjectedFieldInFrom = StringUtils.replace((String) relationship.get("injectedFieldInTo"), ")","").split("\\("); From 3a2d25c67f6283570e43910473d1d05091d73b8c Mon Sep 17 00:00:00 2001 From: Ivan Garcia Sainz-Aja Date: Wed, 8 May 2024 13:35:59 +0200 Subject: [PATCH 6/7] asyncapi-spring-cloud-streams: adds support for tombstone records https://docs.spring.io/spring-cloud-stream/docs/current/reference/html/spring-cloud-stream-binder-kafka.html#kafka-tombstones --- .../plugins/JsonSchema2PojoConfiguration.java | 2 +- .../consumer/imperative/Consumer.java.hbs | 18 ++++++++++++------ .../consumer/imperative/IService.java.hbs | 9 +++++++++ .../consumer/reactive/Consumer.java.hbs | 5 +++++ .../consumer/reactive/IService.java.hbs | 9 +++++++++ 5 files changed, 36 insertions(+), 7 deletions(-) diff --git a/plugins/asyncapi-jsonschema2pojo/src/main/java/io/zenwave360/sdk/plugins/JsonSchema2PojoConfiguration.java b/plugins/asyncapi-jsonschema2pojo/src/main/java/io/zenwave360/sdk/plugins/JsonSchema2PojoConfiguration.java index 6797170d..babc9146 100644 --- a/plugins/asyncapi-jsonschema2pojo/src/main/java/io/zenwave360/sdk/plugins/JsonSchema2PojoConfiguration.java +++ b/plugins/asyncapi-jsonschema2pojo/src/main/java/io/zenwave360/sdk/plugins/JsonSchema2PojoConfiguration.java @@ -94,7 +94,7 @@ public class JsonSchema2PojoConfiguration implements GenerationConfig { private String customDateTimePattern = null; private String refFragmentPathDelimiters = "#/."; - private boolean isUseJakartaValidation = false; + private boolean isUseJakartaValidation = true; private SourceSortOrder sourceSortOrder = SourceSortOrder.OS; public static JsonSchema2PojoConfiguration of(Map settings) { diff --git a/plugins/asyncapi-spring-cloud-streams3/src/main/resources/io/zenwave360/sdk/plugins/SpringCloudStream3Generator/consumer/imperative/Consumer.java.hbs b/plugins/asyncapi-spring-cloud-streams3/src/main/resources/io/zenwave360/sdk/plugins/SpringCloudStream3Generator/consumer/imperative/Consumer.java.hbs index 7d2317ae..d80daf2a 100644 --- a/plugins/asyncapi-spring-cloud-streams3/src/main/resources/io/zenwave360/sdk/plugins/SpringCloudStream3Generator/consumer/imperative/Consumer.java.hbs +++ b/plugins/asyncapi-spring-cloud-streams3/src/main/resources/io/zenwave360/sdk/plugins/SpringCloudStream3Generator/consumer/imperative/Consumer.java.hbs @@ -4,7 +4,7 @@ import java.io.PrintWriter; import java.io.StringWriter; import java.util.HashMap; import java.util.Map; -import java.util.function.Consumer; +import java.util.function.Function; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -24,7 +24,7 @@ import {{modelPackage}}.*; @Component("{{bindingPrefix}}{{operation.x--operationIdKebabCase}}") @jakarta.annotation.Generated(value = "io.zenwave360.sdk.plugins.SpringCloudStreams3Plugin", date = "{{date}}") -public class {{consumerName operation.x--operationIdCamelCase}} implements Consumer> { +public class {{consumerName operation.x--operationIdCamelCase}} implements Function, Void> { protected Logger log = LoggerFactory.getLogger(getClass()); @@ -52,7 +52,7 @@ public class {{consumerName operation.x--operationIdCamelCase}} implements Consu {{~/if}} @Override - public void accept(Message<{{messageType operation}}> message) { + public Void apply(Message<{{messageType operation}}> message) { log.debug("Received message: {}", message); try { Object payload = {{#if (hasEnterpriseEnvelope operation)}}unwrap(message.getPayload()){{else}}message.getPayload(){{/if}}; @@ -65,10 +65,16 @@ public class {{consumerName operation.x--operationIdCamelCase}} implements Consu headers.putAll(message.getHeaders()); service.{{operation.operationId}}{{methodSuffix message operation}}(({{message.x--javaType}}) payload, headers); {{~/if}} - return; + return null; } {{~/each}} - log.error("Received message without any business handler: [payload: {}, message: {}]", payload.getClass().getName(), message); + log.warn("Received message without any business handler: [payload: {}, message: {}]", payload.getClass().getName(), message); + {{~#if exposeMessage}} + service.defaultHandler(MessageBuilder.createMessage(payload, message.getHeaders())); + {{~else}} + service.defaultHandler(payload, message.getHeaders()); + {{~/if}} + return null; } catch (Exception e) { if(log.isDebugEnabled()) { log.error("Error processing message: {}", message, e); @@ -86,7 +92,7 @@ public class {{consumerName operation.x--operationIdCamelCase}} implements Consu headers.put("x-exception-stacktrace ", getStackTraceAsString(e)); headers.put("x-exception-payload-type", message.getPayload().getClass().getName()); streamBridge.send(resolvedDLQ, MessageBuilder.createMessage(message.getPayload(), new MessageHeaders(headers))); - return; + return null; } catch (Exception e1) { log.error("Error sending message to dead letter queue: {}", resolvedDLQ, e1); } diff --git a/plugins/asyncapi-spring-cloud-streams3/src/main/resources/io/zenwave360/sdk/plugins/SpringCloudStream3Generator/consumer/imperative/IService.java.hbs b/plugins/asyncapi-spring-cloud-streams3/src/main/resources/io/zenwave360/sdk/plugins/SpringCloudStream3Generator/consumer/imperative/IService.java.hbs index 2f4e3595..402f4b96 100644 --- a/plugins/asyncapi-spring-cloud-streams3/src/main/resources/io/zenwave360/sdk/plugins/SpringCloudStream3Generator/consumer/imperative/IService.java.hbs +++ b/plugins/asyncapi-spring-cloud-streams3/src/main/resources/io/zenwave360/sdk/plugins/SpringCloudStream3Generator/consumer/imperative/IService.java.hbs @@ -25,6 +25,15 @@ public interface {{serviceInterfaceName operation.x--operationIdCamelCase}} { {{~/if}} {{/each~}} + /** + * Default method for handling unknown messages or tombstone records (null record values). + */ + {{~#if exposeMessage}} + default void defaultHandler(Message msg) {}; + {{~else}} + default void defaultHandler(Object payload, Map headers) {}; + {{~/if}} + {{#each messages as |message|}} {{~> (partial '../../common/Headers') isProducer=false}} {{/each}} diff --git a/plugins/asyncapi-spring-cloud-streams3/src/main/resources/io/zenwave360/sdk/plugins/SpringCloudStream3Generator/consumer/reactive/Consumer.java.hbs b/plugins/asyncapi-spring-cloud-streams3/src/main/resources/io/zenwave360/sdk/plugins/SpringCloudStream3Generator/consumer/reactive/Consumer.java.hbs index edf16e3e..9090f873 100644 --- a/plugins/asyncapi-spring-cloud-streams3/src/main/resources/io/zenwave360/sdk/plugins/SpringCloudStream3Generator/consumer/reactive/Consumer.java.hbs +++ b/plugins/asyncapi-spring-cloud-streams3/src/main/resources/io/zenwave360/sdk/plugins/SpringCloudStream3Generator/consumer/reactive/Consumer.java.hbs @@ -43,6 +43,11 @@ public class {{consumerName operation.x--operationIdCamelCase}} implements Consu {{~/if}} } {{/each}} + {{~#if exposeMessage}} + service.defaultHandler(Flux.just(MessageBuilder.createMessage(m.getPayload(), m.getHeaders()))); + {{~else}} + service.defaultHandler(Flux.just(m.getPayload())); + {{~/if}} }); } } diff --git a/plugins/asyncapi-spring-cloud-streams3/src/main/resources/io/zenwave360/sdk/plugins/SpringCloudStream3Generator/consumer/reactive/IService.java.hbs b/plugins/asyncapi-spring-cloud-streams3/src/main/resources/io/zenwave360/sdk/plugins/SpringCloudStream3Generator/consumer/reactive/IService.java.hbs index eace2f59..6a73ce95 100644 --- a/plugins/asyncapi-spring-cloud-streams3/src/main/resources/io/zenwave360/sdk/plugins/SpringCloudStream3Generator/consumer/reactive/IService.java.hbs +++ b/plugins/asyncapi-spring-cloud-streams3/src/main/resources/io/zenwave360/sdk/plugins/SpringCloudStream3Generator/consumer/reactive/IService.java.hbs @@ -22,6 +22,15 @@ public interface {{serviceInterfaceName operation.x--operationIdCamelCase}} { {{~/if}} {{/each}} + /** + * Default method for handling unknown messages or tombstone records (null record values). + */ + {{~#if exposeMessage}} + default void defaultHandler(Flux messageFlux) {}; + {{~else}} + default void defaultHandler(Flux messageFlux) {}; + {{~/if}} + {{#each messages as |message|}} {{~> (partial '../../common/Headers') isProducer=false}} {{/each}} From 1511fa0626eb68b1a00e56914fe0af7643479b73 Mon Sep 17 00:00:00 2001 From: Ivan Garcia Sainz-Aja Date: Wed, 8 May 2024 15:15:56 +0200 Subject: [PATCH 7/7] zdl-jvm.version > 1.1.1 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 0d526e52..bdfe4894 100644 --- a/pom.xml +++ b/pom.xml @@ -69,7 +69,7 @@ 0.10.2 4.3.1 0.8.4 - 1.2.0-SNAPSHOT + 1.1.1 19.2 1.7 2.38.0