diff --git a/.github/workflows/ci-for-example.yaml b/.github/workflows/ci-for-example.yaml index d098f31..1ef12eb 100644 --- a/.github/workflows/ci-for-example.yaml +++ b/.github/workflows/ci-for-example.yaml @@ -29,4 +29,4 @@ jobs: restore-keys: | ${{ runner.os }}-maven- - name: Build with Maven - run: mvn clean verify -ntp + run: mvn clean verify -ntp \ No newline at end of file diff --git a/.github/workflows/ci-from-template.yaml b/.github/workflows/ci-from-template.yaml index 0c84762..718c0d7 100644 --- a/.github/workflows/ci-from-template.yaml +++ b/.github/workflows/ci-from-template.yaml @@ -4,7 +4,7 @@ on: branches: - main paths: - - '{{cookiecutter.app_name}}/**' + - '{{app_name}}/**' workflow_dispatch: jobs: generate-from-template: @@ -20,14 +20,14 @@ jobs: uses: actions/setup-python@v5 with: python-version: '3.x' - - name: Install cookiecutter + - name: Install copier run: | - pip install --upgrade pip cookiecutter - - name: Generate from default context (cookiecutter.json) + pip install --upgrade pip copier + - name: Generate from default context (copier) run: | - # Generate using the config file test-config.yml from the repo root. - # Use the repo root as the template directory (.) and overwrite any existing generated output. - cookiecutter --no-input --config-file test-config.yml --overwrite-if-exists --output-dir . . + # Use the repo root as the template directory and generate into ./cart-service + # Use copier.yml as the default data file with --defaults and --force to overwrite any existing generated output. + copier copy . . --defaults --force - name: Upload generated cart-service as artifact uses: actions/upload-artifact@v4 with: @@ -59,5 +59,5 @@ jobs: restore-keys: | ${{ runner.os }}-maven- - name: Build with Maven - run: git init && mvn clean verify -Dgit-code-format.skip=true -DargLine="--add-exports jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED" -ntp - working-directory: ./cart-service + run: git init && mvn clean verify -ntp + working-directory: ./cart-service \ No newline at end of file diff --git a/.github/workflows/generate-template.yaml b/.github/workflows/generate-template.yaml index 35cb958..0bbf3d3 100644 --- a/.github/workflows/generate-template.yaml +++ b/.github/workflows/generate-template.yaml @@ -66,7 +66,7 @@ jobs: - name: Copy generated template to {{cookiecutter.app_name}} run: | - rsync -a --delete --exclude='.git' ./example-template/ ./{{cookiecutter.app_name}}/ + rsync -a --delete --exclude='.git' ./example-template/ ./{{app_name}}/ - name: Commit and push changes id: commit diff --git a/README.md b/README.md index 394f2e7..46aa9d1 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ -# Template project for hexagonal-spring-boot-java +# Template project for hexagonal-spring-boot-java [![Copier](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/copier-org/copier/master/img/badge/badge-grayscale-inverted-border-orange.json)](https://github.com/copier-org/copier) -This is a template project for hexagonal-spring-boot-java. This project is generated using [cookiecutter](https://cookiecutter.readthedocs.io/en). +This is a template project for hexagonal-spring-boot-java. This project is generated using [copier](https://copier.readthedocs.io/en/stable/) . ## Pre-requisites -- [cookiecutter](https://cookiecutter.readthedocs.io/en/stable/README.html#installation) +- [copier](https://copier.readthedocs.io/en/stable/#installation) - Jdk 21 - Maven >3.9.5 @@ -22,26 +22,41 @@ flowchart LR ### example -This directory contains the maven hexagonal-spring-boot-java template project. This will be used to generate template project for cookiecutter. This project is used for the contributors to make their changes and test it locally. +This directory contains the maven hexagonal-spring-boot-java template project. This will be used to generate template project for copier. This project is used for the contributors to make their changes and test it locally. -Following are the keywords reserved for the template project and their equivalent replacements in {{cookiecutter.app_name}} project: +Following are the keywords reserved for the template project and their equivalent replacements in {{app_name}} project: -| Keyword | Replacement | -|--------------|---------------------------------------------| -| Examples | {{cookiecutter.domain_plural_capitalized}} | -| examples | {{cookiecutter.domain_plural}} | -| Example | {{cookiecutter.domain_capitalized}} | -| example | {{cookiecutter.domain}} | -| packagename | {{cookiecutter.package_name}} | -| artifactName | {{cookiecutter.artifact_id}} | -| group-id | {{cookiecutter.group_id}} | -| EXAMPLES | {{cookiecutter.domain_plural_uppercase}} | -| EXAMPLE | {{cookiecutter.domain_uppercase}} | +| Keyword | Replacement | +|--------------|-------------------------------| +| Examples | {{domain_plural_capitalized}} | +| examples | {{domain_plural}} | +| Example | {{domain_capitalized}} | +| example | {{domain}} | +| packagename | {{package_name}} | +| artifactName | {{artifact_id}} | +| group-id | {{group_id}} | +| EXAMPLES | {{domain_plural_uppercase}} | +| EXAMPLE | {{domain_uppercase}} | -Refer script [generate-cookiecutter-template-from-example-project.sh](generate-cookiecutter-template-from-example-project.sh) which is used to generate the cookiecutter template project. This script is also being used by [`.github/workflows/ci.yaml`](.github/workflows/ci.yaml) pipeline too. +Refer script [generate-copier-template-from-example-project.sh](generate-copier-template-from-example-project.sh) which is used to generate the copier template project. This script is also being used by [generate-template.yaml](.github/workflows/generate-template.yaml) pipeline too. -### {{cookiecutter.app_name}} +### {{app_name}} -> NOTE: DO NOT MODIFY THIS DIRECTORY DIRECTLY +> [!WARNING] +> DO NOT MODIFY THIS DIRECTORY DIRECTLY -This directory contains the generated project from `example` project. The project is generated using the script [generate-cookiecutter-template-from-example-project.sh](generate-cookiecutter-template-from-example-project.sh) which is used to generate the cookiecutter template project. +This directory contains the generated project from `example` project. The project is generated using the script [generate-copier-template-from-example-project.sh](generate-copier-template-from-example-project.sh) which is used to generate the cookiecutter template project. + +## Generating a new project + +The following command can be used to generate a new project using this template: + +```bash +copier copy . +``` + +Command to generate with default values without prompt: + +```bash +copier copy . . --defaults +``` \ No newline at end of file diff --git a/cookiecutter.json b/cookiecutter.json deleted file mode 100644 index 8cd153b..0000000 --- a/cookiecutter.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "app_name": "{{cookiecutter.app_name}}", - "app_title": "{{cookiecutter.app_name.capitalize()}}", - "domain": "{{cookiecutter.domain}}", - "domain_capitalized": "{{cookiecutter.domain.capitalize()}}", - "domain_uppercase": "{{cookiecutter.domain.upper()}}", - "domain_plural": "{%- if cookiecutter.app_name.endswith('y') -%}{{cookiecutter.domain.replace('y','')}}ies{% else %}{{cookiecutter.domain.lower()}}s{% endif %}", - "domain_plural_capitalized": "{{cookiecutter.domain_plural.capitalize()}}", - "domain_plural_uppercase": "{{cookiecutter.domain_plural.upper()}}", - "group_id": "org.{{cookiecutter.domain}}", - "artifact_id": "{{cookiecutter.domain}}", - "package_name": "{{cookiecutter.domain}}", - "_copy_without_render": [".github/workflows/*.*"] -} diff --git a/copier.yml b/copier.yml new file mode 100644 index 0000000..36af3fd --- /dev/null +++ b/copier.yml @@ -0,0 +1,57 @@ +app_name: + type: str + help: "Short project name (e.g., myapp)" + default: "cart-service" + +app_title: + type: str + help: "Project title" + default: "{{ app_name|capitalize }}" + +domain: + type: str + help: "Domain name (e.g., user, order)" + default: "cart" + +domain_capitalized: + type: str + help: "Domain name, capitalized" + default: "{{ domain|capitalize }}" + +domain_uppercase: + type: str + help: "Domain name, uppercase" + default: "{{ domain|upper }}" + +domain_plural: + type: str + help: "Plural form of domain" + default: "{% if domain.endswith('y') %}{{ domain.replace('y', '') }}ies{% else %}{{ domain.lower() }}s{% endif %}" + +domain_plural_capitalized: + type: str + help: "Plural domain, capitalized" + default: "{{ domain_plural|capitalize }}" + +domain_plural_uppercase: + type: str + help: "Plural domain, uppercase" + default: "{{ domain_plural|upper }}" + +group_id: + type: str + help: "Maven groupId" + default: "org.{{ domain }}" + +artifact_id: + type: str + help: "Maven artifactId" + default: "{{ domain }}" + +package_name: + type: str + help: "Base package name" + default: "{{ group_id }}" + +_copy_without_render: + - .github \ No newline at end of file diff --git a/generate-cookiecutter-template-from-example-project.sh b/generate-cookiecutter-template-from-example-project.sh deleted file mode 100755 index 719b1ea..0000000 --- a/generate-cookiecutter-template-from-example-project.sh +++ /dev/null @@ -1,37 +0,0 @@ -#!/bin/bash -# This script is used to rename files and directories in the example project to that of the cookiecutter template. - -# Remove previous example-template directory if it exists -if [ -d "example-template" ]; then - rm -rf "example-template" -fi -# Create a new example-template directory and copy the example project into it -mkdir "example-template" -rsync -a ./example/ ./example-template/ -cd ./example-template - -# sets the locale for all commands run in the current shell session to the "C" locale, which is the default POSIX locale. This makes programs like sed and find treat files as raw bytes, ignoring any character encoding issues. It helps avoid errors like illegal byte sequence when processing files with mixed or unknown encodings. -export LC_ALL=C - -# Detect OS and set sed inline flag -if [[ "$(uname)" == "Darwin" ]]; then - SED_INPLACE=(-i '') -else - SED_INPLACE=(-i) -fi - -find . -type f -exec sed "${SED_INPLACE[@]}" -e s/Examples/{{cookiecutter.domain_plural_capitalized}}/g '{}' ';' -find . -depth -name '*Examples*' -print0|while IFS= read -rd '' f; do mv -i "$f" "$(echo "$f"|sed -E 's/(.*)Examples/\1{{cookiecutter.domain_plural_capitalized}}/')"; done -find . -type f -exec sed "${SED_INPLACE[@]}" -e s/examples/{{cookiecutter.domain_plural}}/g '{}' ';' -find . -depth -name '*examples*' -print0|while IFS= read -rd '' f; do mv -i "$f" "$(echo "$f"|sed -E 's/(.*)examples/\1{{cookiecutter.domain_plural}}/')"; done -find . -type f -exec sed "${SED_INPLACE[@]}" -e s/Example/{{cookiecutter.domain_capitalized}}/g '{}' ';' -find . -depth -name '*Example*' -print0|while IFS= read -rd '' f; do mv -i "$f" "$(echo "$f"|sed -E 's/(.*)Example/\1{{cookiecutter.domain_capitalized}}/')"; done -find . -type f -exec sed "${SED_INPLACE[@]}" -e s/example/{{cookiecutter.domain}}/g '{}' ';' -find . -depth -name '*example*' -print0|while IFS= read -rd '' f; do mv -i "$f" "$(echo "$f"|sed -E 's/(.*)example/\1{{cookiecutter.domain}}/')"; done -find . -type f -exec sed "${SED_INPLACE[@]}" -e s/packagename/{{cookiecutter.package_name}}/g '{}' ';' -find . -depth -name '*packagename*' -print0|while IFS= read -rd '' f; do mv -i "$f" "$(echo "$f"|sed -E 's/(.*)packagename/\1{{cookiecutter.package_name}}/')"; done -find . -type f -exec sed "${SED_INPLACE[@]}" -e s/artifactName/{{cookiecutter.artifact_id}}/g '{}' ';' -find . -type f -exec sed "${SED_INPLACE[@]}" -e s/group-id/{{cookiecutter.group_id}}/g '{}' ';' -## For the following, we need to replace EXAMPLES and EXAMPLE with the domain name -find . -type f -exec sed "${SED_INPLACE[@]}" -e s/EXAMPLES/{{cookiecutter.domain_plural_uppercase}}/g '{}' ';' -find . -type f -exec sed "${SED_INPLACE[@]}" -e s/EXAMPLE/{{cookiecutter.domain_uppercase}}/g '{}' ';' diff --git a/generate-copier-template-from-example-project.sh b/generate-copier-template-from-example-project.sh new file mode 100755 index 0000000..b7fb60b --- /dev/null +++ b/generate-copier-template-from-example-project.sh @@ -0,0 +1,46 @@ +#!/bin/bash +# This script is used to rename files and directories in the example project to that of the cookiecutter template. + +# Remove previous example-template directory if it exists +if [ -d "example-template" ]; then + rm -rf "example-template" +fi +# Create a new example-template directory and copy the example project into it +mkdir "example-template" +rsync -a ./example/ ./example-template/ +cd ./example-template + +# sets the locale for all commands run in the current shell session to the "C" locale, which is the default POSIX locale. This makes programs like sed and find treat files as raw bytes, ignoring any character encoding issues. It helps avoid errors like illegal byte sequence when processing files with mixed or unknown encodings. +export LC_ALL=C + +# Detect OS and set sed inline flag +if [[ "$(uname)" == "Darwin" ]]; then + SED_INPLACE=(-i '') +else + SED_INPLACE=(-i) +fi + +find . -type f -exec sed "${SED_INPLACE[@]}" -e s/Examples/{{domain_plural_capitalized}}/g '{}' ';' +find . -depth -name '*Examples*' -print0|while IFS= read -rd '' f; do mv -i "$f" "$(echo "$f"|sed -E 's/(.*)Examples/\1{{domain_plural_capitalized}}/')"; done +find . -type f -exec sed "${SED_INPLACE[@]}" -e s/examples/{{domain_plural}}/g '{}' ';' +find . -depth -name '*examples*' -print0|while IFS= read -rd '' f; do mv -i "$f" "$(echo "$f"|sed -E 's/(.*)examples/\1{{domain_plural}}/')"; done +find . -type f -exec sed "${SED_INPLACE[@]}" -e s/Example/{{domain_capitalized}}/g '{}' ';' +find . -depth -name '*Example*' -print0|while IFS= read -rd '' f; do mv -i "$f" "$(echo "$f"|sed -E 's/(.*)Example/\1{{domain_capitalized}}/')"; done +find . -type f -exec sed "${SED_INPLACE[@]}" -e s/example/{{domain}}/g '{}' ';' +find . -depth -name '*example*' -print0|while IFS= read -rd '' f; do mv -i "$f" "$(echo "$f"|sed -E 's/(.*)example/\1{{domain}}/')"; done +find . -type f -exec sed "${SED_INPLACE[@]}" -e s/packagename/{{package_name}}/g '{}' ';' +find . -depth -name '*packagename*' -print0|while IFS= read -rd '' f; do mv -i "$f" "$(echo "$f"|sed -E 's/(.*)packagename/\1{{package_name}}/')"; done +find . -type f -exec sed "${SED_INPLACE[@]}" -e s/artifactName/{{artifact_id}}/g '{}' ';' +find . -type f -exec sed "${SED_INPLACE[@]}" -e s/group-id/{{group_id}}/g '{}' ';' +## For the following, we need to replace EXAMPLES and EXAMPLE with the domain name +find . -type f -exec sed "${SED_INPLACE[@]}" -e s/EXAMPLES/{{domain_plural_uppercase}}/g '{}' ';' +find . -type f -exec sed "${SED_INPLACE[@]}" -e s/EXAMPLE/{{domain_uppercase}}/g '{}' ';' + +# Rename files to add .jinja extension +# Add .jinja extension to files except those under .github +exts=(xml yml java feature sql yaml) +for ext in "${exts[@]}"; do + find . -type d -name .github -prune -o -type f -name "*.${ext}" -print0 | while IFS= read -r -d '' file; do + mv "$file" "$file.jinja" + done +done diff --git a/rename_dir.sh b/rename_dir.sh new file mode 100755 index 0000000..3a5a579 --- /dev/null +++ b/rename_dir.sh @@ -0,0 +1,18 @@ +#!/bin/bash +# Dry-run: show planned renames +find . -depth -type d -name '{{cookiecutter.*' -print0 | \ + while IFS= read -r -d '' d; do + new="$(dirname "$d")/$(basename "$d" | sed 's/^{{cookiecutter\./{{/')" + printf '%s -> %s\n' "$d" "$new" + done + +## Apply changes: actually rename (run only after verifying dry-run) +find . -depth -type d -name '{{cookiecutter.*' -print0 | \ + while IFS= read -r -d '' d; do + new="$(dirname "$d")/$(basename "$d" | sed 's/^{{cookiecutter\./{{/')" + if [ -e "$new" ]; then + printf 'Skipping %s: target exists %s\n' "$d" "$new" >&2 + continue + fi + mv -- "$d" "$new" && printf 'Renamed %s -> %s\n' "$d" "$new" + done diff --git a/test-config.yml b/test-config.yml deleted file mode 100644 index f562a3a..0000000 --- a/test-config.yml +++ /dev/null @@ -1,3 +0,0 @@ -default_context: - app_name: "cart-service" - domain: "cart" \ No newline at end of file diff --git a/{{app_name}}/.docker/Dockerfile b/{{app_name}}/.docker/Dockerfile new file mode 100644 index 0000000..ab1ceaa --- /dev/null +++ b/{{app_name}}/.docker/Dockerfile @@ -0,0 +1,7 @@ +FROM gcr.io/distroless/java21-debian12 + +WORKDIR /app + +COPY ../../bootstrap/target/{{domain}}-exec.jar . + +CMD ["{{domain}}-exec.jar"] \ No newline at end of file diff --git a/{{cookiecutter.app_name}}/.github/CODEOWNERS b/{{app_name}}/.github/CODEOWNERS similarity index 100% rename from {{cookiecutter.app_name}}/.github/CODEOWNERS rename to {{app_name}}/.github/CODEOWNERS diff --git a/{{cookiecutter.app_name}}/.github/ISSUE_TEMPLATE/bug_report.md b/{{app_name}}/.github/ISSUE_TEMPLATE/bug_report.md similarity index 100% rename from {{cookiecutter.app_name}}/.github/ISSUE_TEMPLATE/bug_report.md rename to {{app_name}}/.github/ISSUE_TEMPLATE/bug_report.md diff --git a/{{cookiecutter.app_name}}/.github/ISSUE_TEMPLATE/feature_request.md b/{{app_name}}/.github/ISSUE_TEMPLATE/feature_request.md similarity index 100% rename from {{cookiecutter.app_name}}/.github/ISSUE_TEMPLATE/feature_request.md rename to {{app_name}}/.github/ISSUE_TEMPLATE/feature_request.md diff --git a/{{cookiecutter.app_name}}/.github/PULL_REQUEST_TEMPLATE.md b/{{app_name}}/.github/PULL_REQUEST_TEMPLATE.md similarity index 100% rename from {{cookiecutter.app_name}}/.github/PULL_REQUEST_TEMPLATE.md rename to {{app_name}}/.github/PULL_REQUEST_TEMPLATE.md diff --git a/{{cookiecutter.app_name}}/.github/dependabot.yml b/{{app_name}}/.github/dependabot.yml similarity index 100% rename from {{cookiecutter.app_name}}/.github/dependabot.yml rename to {{app_name}}/.github/dependabot.yml diff --git a/{{cookiecutter.app_name}}/.github/workflows/build_workflow.yml b/{{app_name}}/.github/workflows/build_workflow.yml similarity index 100% rename from {{cookiecutter.app_name}}/.github/workflows/build_workflow.yml rename to {{app_name}}/.github/workflows/build_workflow.yml diff --git a/{{cookiecutter.app_name}}/.mvn/jvm.config b/{{app_name}}/.mvn/jvm.config similarity index 100% rename from {{cookiecutter.app_name}}/.mvn/jvm.config rename to {{app_name}}/.mvn/jvm.config diff --git a/{{cookiecutter.app_name}}/README.md b/{{app_name}}/README.md similarity index 100% rename from {{cookiecutter.app_name}}/README.md rename to {{app_name}}/README.md diff --git a/{{cookiecutter.app_name}}/acceptance-test/pom.xml b/{{app_name}}/acceptance-test/pom.xml.jinja similarity index 89% rename from {{cookiecutter.app_name}}/acceptance-test/pom.xml rename to {{app_name}}/acceptance-test/pom.xml.jinja index 2a66933..9707b05 100644 --- a/{{cookiecutter.app_name}}/acceptance-test/pom.xml +++ b/{{app_name}}/acceptance-test/pom.xml.jinja @@ -3,32 +3,32 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - {{cookiecutter.group_id}} - {{cookiecutter.artifact_id}}-parent + {{group_id}} + {{artifact_id}}-parent 1.0-SNAPSHOT 4.0.0 acceptance-test - {{cookiecutter.group_id}} + {{group_id}} bootstrap - {{cookiecutter.group_id}} + {{group_id}} rest-adapter - {{cookiecutter.group_id}} + {{group_id}} domain - {{cookiecutter.group_id}} + {{group_id}} jpa-adapter @@ -69,8 +69,8 @@ ${cukedoctor-maven-plugin.version} target/cucumber - {{cookiecutter.domain_capitalized}} - {{cookiecutter.domain_capitalized}} - Living Documentation + {{domain_capitalized}} + {{domain_capitalized}} - Living Documentation ${project.version} center diff --git a/{{cookiecutter.app_name}}/acceptance-test/src/test/java/{{cookiecutter.package_name}}/cucumber/RunCucumber{{cookiecutter.domain_capitalized}}Test.java b/{{app_name}}/acceptance-test/src/test/java/{{package_name}}/cucumber/RunCucumber{{domain_capitalized}}Test.java.jinja similarity index 69% rename from {{cookiecutter.app_name}}/acceptance-test/src/test/java/{{cookiecutter.package_name}}/cucumber/RunCucumber{{cookiecutter.domain_capitalized}}Test.java rename to {{app_name}}/acceptance-test/src/test/java/{{package_name}}/cucumber/RunCucumber{{domain_capitalized}}Test.java.jinja index 041857c..fca0985 100644 --- a/{{cookiecutter.app_name}}/acceptance-test/src/test/java/{{cookiecutter.package_name}}/cucumber/RunCucumber{{cookiecutter.domain_capitalized}}Test.java +++ b/{{app_name}}/acceptance-test/src/test/java/{{package_name}}/cucumber/RunCucumber{{domain_capitalized}}Test.java.jinja @@ -1,4 +1,4 @@ -package {{cookiecutter.package_name}}.cucumber; +package {{package_name}}.cucumber; import static io.cucumber.junit.platform.engine.Constants.*; @@ -10,12 +10,12 @@ @Suite @IncludeEngines("cucumber") -@SelectClasspathResource("features/{{cookiecutter.domain}}.feature") +@SelectClasspathResource("features/{{domain}}.feature") @ConfigurationParameters({ - @ConfigurationParameter(key = GLUE_PROPERTY_NAME, value = "{{cookiecutter.package_name}}.cucumber"), - @ConfigurationParameter(key = FILTER_TAGS_PROPERTY_NAME, value = "@{{cookiecutter.domain_capitalized}}"), + @ConfigurationParameter(key = GLUE_PROPERTY_NAME, value = "{{package_name}}.cucumber"), + @ConfigurationParameter(key = FILTER_TAGS_PROPERTY_NAME, value = "@{{domain_capitalized}}"), @ConfigurationParameter(key = JUNIT_PLATFORM_NAMING_STRATEGY_PROPERTY_NAME, value = "long"), @ConfigurationParameter(key = PLUGIN_PUBLISH_QUIET_PROPERTY_NAME, value = "true"), @ConfigurationParameter(key = PLUGIN_PROPERTY_NAME, value = "json:target/cucumber/cucumber.json") }) -public class RunCucumber{{cookiecutter.domain_capitalized}}Test {} +public class RunCucumber{{domain_capitalized}}Test {} diff --git a/{{cookiecutter.app_name}}/acceptance-test/src/test/java/{{cookiecutter.package_name}}/cucumber/SpringCucumberTestConfig.java b/{{app_name}}/acceptance-test/src/test/java/{{package_name}}/cucumber/SpringCucumberTestConfig.java.jinja similarity index 59% rename from {{cookiecutter.app_name}}/acceptance-test/src/test/java/{{cookiecutter.package_name}}/cucumber/SpringCucumberTestConfig.java rename to {{app_name}}/acceptance-test/src/test/java/{{package_name}}/cucumber/SpringCucumberTestConfig.java.jinja index f30472d..08bdb38 100644 --- a/{{cookiecutter.app_name}}/acceptance-test/src/test/java/{{cookiecutter.package_name}}/cucumber/SpringCucumberTestConfig.java +++ b/{{app_name}}/acceptance-test/src/test/java/{{package_name}}/cucumber/SpringCucumberTestConfig.java.jinja @@ -1,13 +1,13 @@ -package {{cookiecutter.package_name}}.cucumber; +package {{package_name}}.cucumber; import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT; import io.cucumber.spring.CucumberContextConfiguration; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.ActiveProfiles; -import {{cookiecutter.package_name}}.boot.{{cookiecutter.domain_capitalized}}Application; +import {{package_name}}.boot.{{domain_capitalized}}Application; -@SpringBootTest(classes = {{cookiecutter.domain_capitalized}}Application.class, webEnvironment = RANDOM_PORT) +@SpringBootTest(classes = {{domain_capitalized}}Application.class, webEnvironment = RANDOM_PORT) @CucumberContextConfiguration @ActiveProfiles("test") public class SpringCucumberTestConfig {} diff --git a/{{cookiecutter.app_name}}/acceptance-test/src/test/java/{{cookiecutter.package_name}}/cucumber/{{cookiecutter.domain_capitalized}}StepDef.java b/{{app_name}}/acceptance-test/src/test/java/{{package_name}}/cucumber/{{domain_capitalized}}StepDef.java.jinja similarity index 51% rename from {{cookiecutter.app_name}}/acceptance-test/src/test/java/{{cookiecutter.package_name}}/cucumber/{{cookiecutter.domain_capitalized}}StepDef.java rename to {{app_name}}/acceptance-test/src/test/java/{{package_name}}/cucumber/{{domain_capitalized}}StepDef.java.jinja index e6217a8..e992d5b 100644 --- a/{{cookiecutter.app_name}}/acceptance-test/src/test/java/{{cookiecutter.package_name}}/cucumber/{{cookiecutter.domain_capitalized}}StepDef.java +++ b/{{app_name}}/acceptance-test/src/test/java/{{package_name}}/cucumber/{{domain_capitalized}}StepDef.java.jinja @@ -1,4 +1,4 @@ -package {{cookiecutter.package_name}}.cucumber; +package {{package_name}}.cucumber; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.within; @@ -15,60 +15,60 @@ import org.springframework.boot.test.web.server.LocalServerPort; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; -import {{cookiecutter.package_name}}.domain.model.{{cookiecutter.domain_capitalized}}; -import {{cookiecutter.package_name}}.repository.dao.{{cookiecutter.domain_capitalized}}Dao; -import {{cookiecutter.package_name}}.repository.entity.{{cookiecutter.domain_capitalized}}Entity; -import {{cookiecutter.package_name}}.rest.generated.model.{{cookiecutter.domain_capitalized}}Info; -import {{cookiecutter.package_name}}.rest.generated.model.ProblemDetail; +import {{package_name}}.domain.model.{{domain_capitalized}}; +import {{package_name}}.repository.dao.{{domain_capitalized}}Dao; +import {{package_name}}.repository.entity.{{domain_capitalized}}Entity; +import {{package_name}}.rest.generated.model.{{domain_capitalized}}Info; +import {{package_name}}.rest.generated.model.ProblemDetail; -public class {{cookiecutter.domain_capitalized}}StepDef implements En { +public class {{domain_capitalized}}StepDef implements En { private static final String LOCALHOST = "http://localhost:"; - private static final String API_URI = "/api/v1/{{cookiecutter.domain_plural}}"; + private static final String API_URI = "/api/v1/{{domain_plural}}"; @LocalServerPort private int port; private ResponseEntity responseEntity; - public {{cookiecutter.domain_capitalized}}StepDef(TestRestTemplate restTemplate, {{cookiecutter.domain_capitalized}}Dao {{cookiecutter.domain}}Dao) { + public {{domain_capitalized}}StepDef(TestRestTemplate restTemplate, {{domain_capitalized}}Dao {{domain}}Dao) { DataTableType( (Map row) -> - {{cookiecutter.domain_capitalized}}.builder() + {{domain_capitalized}}.builder() .code(Long.parseLong(row.get("code"))) .description(row.get("description")) .build()); DataTableType( (Map row) -> - {{cookiecutter.domain_capitalized}}Entity.builder() + {{domain_capitalized}}Entity.builder() .code(Long.parseLong(row.get("code"))) .description(row.get("description")) .build()); - Before((HookNoArgsBody) {{cookiecutter.domain}}Dao::deleteAll); - After((HookNoArgsBody) {{cookiecutter.domain}}Dao::deleteAll); + Before((HookNoArgsBody) {{domain}}Dao::deleteAll); + After((HookNoArgsBody) {{domain}}Dao::deleteAll); Given( - "the following {{cookiecutter.domain_plural}} exists in the library", + "the following {{domain_plural}} exists in the library", (DataTable dataTable) -> { - List<{{cookiecutter.domain_capitalized}}Entity> poems = dataTable.asList({{cookiecutter.domain_capitalized}}Entity.class); - {{cookiecutter.domain}}Dao.saveAll(poems); + List<{{domain_capitalized}}Entity> poems = dataTable.asList({{domain_capitalized}}Entity.class); + {{domain}}Dao.saveAll(poems); }); When( - "user requests for all {{cookiecutter.domain_plural}}", + "user requests for all {{domain_plural}}", () -> { String url = LOCALHOST + port + API_URI; - responseEntity = restTemplate.getForEntity(url, {{cookiecutter.domain_capitalized}}Info.class); + responseEntity = restTemplate.getForEntity(url, {{domain_capitalized}}Info.class); }); When( - "user requests for {{cookiecutter.domain_plural}} by code {string}", + "user requests for {{domain_plural}} by code {string}", (String code) -> { String url = LOCALHOST + port + API_URI + "/" + code; - responseEntity = restTemplate.getForEntity(url, {{cookiecutter.domain_capitalized}}.class); + responseEntity = restTemplate.getForEntity(url, {{domain_capitalized}}.class); }); When( - "user requests for {{cookiecutter.domain_plural}} by id {string} that does not exists", + "user requests for {{domain_plural}} by id {string} that does not exists", (String code) -> { String url = LOCALHOST + port + API_URI + "/" + code; responseEntity = restTemplate.getForEntity(url, ProblemDetail.class); @@ -83,9 +83,9 @@ public class {{cookiecutter.domain_capitalized}}StepDef implements En { ProblemDetail.builder() .type("https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/404") .status(HttpStatus.NOT_FOUND.value()) - .detail("{{cookiecutter.domain_capitalized}} with code 10000 does not exist") - .instance("/api/v1/{{cookiecutter.domain_plural}}/10000") - .title("{{cookiecutter.domain_capitalized}} not found") + .detail("{{domain_capitalized}} with code 10000 does not exist") + .instance("/api/v1/{{domain_plural}}/10000") + .title("{{domain_capitalized}} not found") .build(); assertThat(actualResponse).isNotNull(); assertThat(actualResponse) @@ -97,25 +97,25 @@ public class {{cookiecutter.domain_capitalized}}StepDef implements En { }); Then( - "the user gets the following {{cookiecutter.domain_plural}}", + "the user gets the following {{domain_plural}}", (DataTable dataTable) -> { - List<{{cookiecutter.domain_capitalized}}> expected{{cookiecutter.domain_plural_capitalized}} = dataTable.asList({{cookiecutter.domain_capitalized}}.class); + List<{{domain_capitalized}}> expected{{domain_plural_capitalized}} = dataTable.asList({{domain_capitalized}}.class); assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK); Object body = responseEntity.getBody(); assertThat(body).isNotNull(); - if (body instanceof {{cookiecutter.domain_capitalized}}Info) { - assertThat((({{cookiecutter.domain_capitalized}}Info) body).get{{cookiecutter.domain_plural_capitalized}}()) + if (body instanceof {{domain_capitalized}}Info) { + assertThat((({{domain_capitalized}}Info) body).get{{domain_plural_capitalized}}()) .isNotEmpty() .extracting("description") .containsAll( - expected{{cookiecutter.domain_plural_capitalized}}.stream() - .map({{cookiecutter.domain_capitalized}}::getDescription) + expected{{domain_plural_capitalized}}.stream() + .map({{domain_capitalized}}::getDescription) .collect(Collectors.toList())); - } else if (body instanceof {{cookiecutter.domain_capitalized}}) { + } else if (body instanceof {{domain_capitalized}}) { assertThat(body) .isNotNull() .extracting("description") - .isEqualTo(expected{{cookiecutter.domain_plural_capitalized}}.get(0).getDescription()); + .isEqualTo(expected{{domain_plural_capitalized}}.get(0).getDescription()); } }); } diff --git a/{{cookiecutter.app_name}}/acceptance-test/src/test/resources/application-test.yml b/{{app_name}}/acceptance-test/src/test/resources/application-test.yml.jinja similarity index 100% rename from {{cookiecutter.app_name}}/acceptance-test/src/test/resources/application-test.yml rename to {{app_name}}/acceptance-test/src/test/resources/application-test.yml.jinja diff --git a/{{app_name}}/acceptance-test/src/test/resources/features/{{domain}}.feature.jinja b/{{app_name}}/acceptance-test/src/test/resources/features/{{domain}}.feature.jinja new file mode 100644 index 0000000..223ea76 --- /dev/null +++ b/{{app_name}}/acceptance-test/src/test/resources/features/{{domain}}.feature.jinja @@ -0,0 +1,24 @@ +@{{domain_capitalized}} +Feature: User would like to get {{domain_plural}} + Background: + Given the following {{domain_plural}} exists in the library + | code | description | + | 1 | Twinkle twinkle little star | + | 2 | Johnny Johnny Yes Papa | + + Scenario: User should be able to get all {{domain_plural}} + When user requests for all {{domain_plural}} + Then the user gets the following {{domain_plural}} + | code | description | + | 1 | Twinkle twinkle little star | + | 2 | Johnny Johnny Yes Papa | + + Scenario: User should be able to get {{domain_plural}} by code + When user requests for {{domain_plural}} by code "1" + Then the user gets the following {{domain_plural}} + | code | description | + | 1 | Twinkle twinkle little star | + + Scenario: User should get an appropriate NOT FOUND message while trying get {{domain_plural}} by an invalid code + When user requests for {{domain_plural}} by id "10000" that does not exists + Then the user gets an exception "{{domain_capitalized}} with code 10000 does not exist" \ No newline at end of file diff --git a/{{cookiecutter.app_name}}/bootstrap/pom.xml b/{{app_name}}/bootstrap/pom.xml.jinja similarity index 86% rename from {{cookiecutter.app_name}}/bootstrap/pom.xml rename to {{app_name}}/bootstrap/pom.xml.jinja index b99ac14..6ba8b3b 100644 --- a/{{cookiecutter.app_name}}/bootstrap/pom.xml +++ b/{{app_name}}/bootstrap/pom.xml.jinja @@ -3,29 +3,29 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - {{cookiecutter.group_id}} - {{cookiecutter.artifact_id}}-parent + {{group_id}} + {{artifact_id}}-parent 1.0-SNAPSHOT 4.0.0 bootstrap - {{cookiecutter.package_name}}.boot.{{cookiecutter.domain_capitalized}}Application + {{package_name}}.boot.{{domain_capitalized}}Application - {{cookiecutter.group_id}} + {{group_id}} rest-adapter - {{cookiecutter.group_id}} + {{group_id}} domain - {{cookiecutter.group_id}} + {{group_id}} jpa-adapter @@ -45,7 +45,7 @@ - {{cookiecutter.domain}} + {{domain}} org.springframework.boot diff --git a/{{app_name}}/bootstrap/src/main/java/{{package_name}}/boot/config/BootstrapConfig.java.jinja b/{{app_name}}/bootstrap/src/main/java/{{package_name}}/boot/config/BootstrapConfig.java.jinja new file mode 100644 index 0000000..539ac15 --- /dev/null +++ b/{{app_name}}/bootstrap/src/main/java/{{package_name}}/boot/config/BootstrapConfig.java.jinja @@ -0,0 +1,19 @@ +package {{package_name}}.boot.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import {{package_name}}.domain.{{domain_capitalized}}Domain; +import {{package_name}}.domain.port.Obtain{{domain_capitalized}}; +import {{package_name}}.domain.port.Request{{domain_capitalized}}; +import {{package_name}}.repository.config.JpaAdapterConfig; + +@Configuration +@Import(JpaAdapterConfig.class) +public class BootstrapConfig { + + @Bean + public Request{{domain_capitalized}} getRequest{{domain_capitalized}}(Obtain{{domain_capitalized}} obtain{{domain_capitalized}}) { + return new {{domain_capitalized}}Domain(obtain{{domain_capitalized}}); + } +} diff --git a/{{cookiecutter.app_name}}/bootstrap/src/main/java/{{cookiecutter.package_name}}/boot/{{cookiecutter.domain_capitalized}}Application.java b/{{app_name}}/bootstrap/src/main/java/{{package_name}}/boot/{{domain_capitalized}}Application.java.jinja similarity index 50% rename from {{cookiecutter.app_name}}/bootstrap/src/main/java/{{cookiecutter.package_name}}/boot/{{cookiecutter.domain_capitalized}}Application.java rename to {{app_name}}/bootstrap/src/main/java/{{package_name}}/boot/{{domain_capitalized}}Application.java.jinja index 856d959..7c21154 100644 --- a/{{cookiecutter.app_name}}/bootstrap/src/main/java/{{cookiecutter.package_name}}/boot/{{cookiecutter.domain_capitalized}}Application.java +++ b/{{app_name}}/bootstrap/src/main/java/{{package_name}}/boot/{{domain_capitalized}}Application.java.jinja @@ -1,14 +1,14 @@ -package {{cookiecutter.package_name}}.boot; +package {{package_name}}.boot; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.ComponentScan; @SpringBootApplication -@ComponentScan(basePackages = "{{cookiecutter.package_name}}") -public class {{cookiecutter.domain_capitalized}}Application { +@ComponentScan(basePackages = "{{package_name}}") +public class {{domain_capitalized}}Application { public static void main(String[] args) { - SpringApplication.run({{cookiecutter.domain_capitalized}}Application.class, args); + SpringApplication.run({{domain_capitalized}}Application.class, args); } } diff --git a/{{cookiecutter.app_name}}/bootstrap/src/main/resources/application.yml b/{{app_name}}/bootstrap/src/main/resources/application.yml.jinja similarity index 100% rename from {{cookiecutter.app_name}}/bootstrap/src/main/resources/application.yml rename to {{app_name}}/bootstrap/src/main/resources/application.yml.jinja diff --git a/{{cookiecutter.app_name}}/domain-api/pom.xml b/{{app_name}}/domain-api/pom.xml.jinja similarity index 92% rename from {{cookiecutter.app_name}}/domain-api/pom.xml rename to {{app_name}}/domain-api/pom.xml.jinja index c260b97..c7e673e 100644 --- a/{{cookiecutter.app_name}}/domain-api/pom.xml +++ b/{{app_name}}/domain-api/pom.xml.jinja @@ -3,8 +3,8 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - {{cookiecutter.group_id}} - {{cookiecutter.artifact_id}}-parent + {{group_id}} + {{artifact_id}}-parent 1.0-SNAPSHOT 4.0.0 diff --git a/{{app_name}}/domain-api/src/main/java/{{package_name}}/domain/exception/{{domain_capitalized}}NotFoundException.java.jinja b/{{app_name}}/domain-api/src/main/java/{{package_name}}/domain/exception/{{domain_capitalized}}NotFoundException.java.jinja new file mode 100644 index 0000000..483465d --- /dev/null +++ b/{{app_name}}/domain-api/src/main/java/{{package_name}}/domain/exception/{{domain_capitalized}}NotFoundException.java.jinja @@ -0,0 +1,8 @@ +package {{package_name}}.domain.exception; + +public class {{domain_capitalized}}NotFoundException extends RuntimeException { + + public {{domain_capitalized}}NotFoundException(Long id) { + super("{{domain_capitalized}} with code " + id + " does not exist"); + } +} diff --git a/{{cookiecutter.app_name}}/domain-api/src/main/java/{{cookiecutter.package_name}}/domain/model/{{cookiecutter.domain_capitalized}}.java b/{{app_name}}/domain-api/src/main/java/{{package_name}}/domain/model/{{domain_capitalized}}.java.jinja similarity index 68% rename from {{cookiecutter.app_name}}/domain-api/src/main/java/{{cookiecutter.package_name}}/domain/model/{{cookiecutter.domain_capitalized}}.java rename to {{app_name}}/domain-api/src/main/java/{{package_name}}/domain/model/{{domain_capitalized}}.java.jinja index 9740977..dea857b 100644 --- a/{{cookiecutter.app_name}}/domain-api/src/main/java/{{cookiecutter.package_name}}/domain/model/{{cookiecutter.domain_capitalized}}.java +++ b/{{app_name}}/domain-api/src/main/java/{{package_name}}/domain/model/{{domain_capitalized}}.java.jinja @@ -1,4 +1,4 @@ -package {{cookiecutter.package_name}}.domain.model; +package {{package_name}}.domain.model; import lombok.AllArgsConstructor; import lombok.Builder; @@ -9,7 +9,7 @@ @Builder @AllArgsConstructor @NoArgsConstructor -public class {{cookiecutter.domain_capitalized}} { +public class {{domain_capitalized}} { private Long code; private String description; diff --git a/{{app_name}}/domain-api/src/main/java/{{package_name}}/domain/port/Obtain{{domain_capitalized}}.java.jinja b/{{app_name}}/domain-api/src/main/java/{{package_name}}/domain/port/Obtain{{domain_capitalized}}.java.jinja new file mode 100644 index 0000000..3ac22e2 --- /dev/null +++ b/{{app_name}}/domain-api/src/main/java/{{package_name}}/domain/port/Obtain{{domain_capitalized}}.java.jinja @@ -0,0 +1,28 @@ +package {{package_name}}.domain.port; + +import java.util.List; +import java.util.Optional; +import lombok.NonNull; +import {{package_name}}.domain.model.{{domain_capitalized}}; + +public interface Obtain{{domain_capitalized}} { + + default List<{{domain_capitalized}}> getAll{{domain_plural_capitalized}}() { + {{domain_capitalized}} {{domain}} = + {{domain_capitalized}}.builder() + .code(1L) + .description( + "If you could read a leaf or tree\r\nyoud have no need of books.\r\n-- Alistair Cockburn (1987)") + .build(); + return List.of({{domain}}); + } + + default Optional<{{domain_capitalized}}> get{{domain_capitalized}}ByCode(@NonNull Long code) { + return Optional.of( + {{domain_capitalized}}.builder() + .code(1L) + .description( + "If you could read a leaf or tree\r\nyoud have no need of books.\r\n-- Alistair Cockburn (1987)") + .build()); + } +} diff --git a/{{app_name}}/domain-api/src/main/java/{{package_name}}/domain/port/Request{{domain_capitalized}}.java.jinja b/{{app_name}}/domain-api/src/main/java/{{package_name}}/domain/port/Request{{domain_capitalized}}.java.jinja new file mode 100644 index 0000000..2625401 --- /dev/null +++ b/{{app_name}}/domain-api/src/main/java/{{package_name}}/domain/port/Request{{domain_capitalized}}.java.jinja @@ -0,0 +1,12 @@ +package {{package_name}}.domain.port; + +import java.util.List; +import lombok.NonNull; +import {{package_name}}.domain.model.{{domain_capitalized}}; + +public interface Request{{domain_capitalized}} { + + List<{{domain_capitalized}}> get{{domain_plural_capitalized}}(); + + {{domain_capitalized}} get{{domain_capitalized}}ByCode(@NonNull Long code); +} diff --git a/{{cookiecutter.app_name}}/domain/pom.xml b/{{app_name}}/domain/pom.xml.jinja similarity index 90% rename from {{cookiecutter.app_name}}/domain/pom.xml rename to {{app_name}}/domain/pom.xml.jinja index b8c79b5..114ed5f 100644 --- a/{{cookiecutter.app_name}}/domain/pom.xml +++ b/{{app_name}}/domain/pom.xml.jinja @@ -3,15 +3,15 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - {{cookiecutter.group_id}} - {{cookiecutter.artifact_id}}-parent + {{group_id}} + {{artifact_id}}-parent 1.0-SNAPSHOT 4.0.0 domain - {{cookiecutter.group_id}} + {{group_id}} domain-api diff --git a/{{app_name}}/domain/src/main/java/{{package_name}}/domain/{{domain_capitalized}}Domain.java.jinja b/{{app_name}}/domain/src/main/java/{{package_name}}/domain/{{domain_capitalized}}Domain.java.jinja new file mode 100644 index 0000000..4ff72ec --- /dev/null +++ b/{{app_name}}/domain/src/main/java/{{package_name}}/domain/{{domain_capitalized}}Domain.java.jinja @@ -0,0 +1,32 @@ +package {{package_name}}.domain; + +import java.util.List; +import lombok.NonNull; +import {{package_name}}.domain.exception.{{domain_capitalized}}NotFoundException; +import {{package_name}}.domain.model.{{domain_capitalized}}; +import {{package_name}}.domain.port.Obtain{{domain_capitalized}}; +import {{package_name}}.domain.port.Request{{domain_capitalized}}; + +public class {{domain_capitalized}}Domain implements Request{{domain_capitalized}} { + + private final Obtain{{domain_capitalized}} obtain{{domain_capitalized}}; + + public {{domain_capitalized}}Domain() { + this(new Obtain{{domain_capitalized}}() {}); + } + + public {{domain_capitalized}}Domain(Obtain{{domain_capitalized}} obtain{{domain_capitalized}}) { + this.obtain{{domain_capitalized}} = obtain{{domain_capitalized}}; + } + + @Override + public List<{{domain_capitalized}}> get{{domain_plural_capitalized}}() { + return obtain{{domain_capitalized}}.getAll{{domain_plural_capitalized}}(); + } + + @Override + public {{domain_capitalized}} get{{domain_capitalized}}ByCode(@NonNull Long code) { + var {{domain}} = obtain{{domain_capitalized}}.get{{domain_capitalized}}ByCode(code); + return {{domain}}.orElseThrow(() -> new {{domain_capitalized}}NotFoundException(code)); + } +} diff --git a/{{app_name}}/domain/src/test/java/{{package_name}}/AcceptanceTest.java.jinja b/{{app_name}}/domain/src/test/java/{{package_name}}/AcceptanceTest.java.jinja new file mode 100644 index 0000000..cf05b89 --- /dev/null +++ b/{{app_name}}/domain/src/test/java/{{package_name}}/AcceptanceTest.java.jinja @@ -0,0 +1,92 @@ +package {{package_name}}; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.util.List; +import java.util.Optional; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; +import {{package_name}}.domain.{{domain_capitalized}}Domain; +import {{package_name}}.domain.exception.{{domain_capitalized}}NotFoundException; +import {{package_name}}.domain.model.{{domain_capitalized}}; +import {{package_name}}.domain.port.Obtain{{domain_capitalized}}; + +@ExtendWith(MockitoExtension.class) +public class AcceptanceTest { + + @Test + @DisplayName("should be able to get {{domain_plural}} when asked for {{domain_plural}} from hard coded {{domain_plural}}") + public void get{{domain_plural_capitalized}}FromHardCoded() { + /* + Request{{domain_capitalized}} - left side port + {{domain_capitalized}}Domain - hexagon (domain) + Obtain{{domain_capitalized}} - right side port + */ + var request{{domain_capitalized}} = new {{domain_capitalized}}Domain(); // the {{domain}} is hard coded + var {{domain_plural}} = request{{domain_capitalized}}.get{{domain_plural_capitalized}}(); + assertThat({{domain_plural}}) + .hasSize(1) + .extracting("description") + .contains( + "If you could read a leaf or tree\r\nyoud have no need of books.\r\n-- Alistair Cockburn (1987)"); + } + + @Test + @DisplayName("should be able to get {{domain_plural}} when asked for {{domain_plural}} from stub") + public void get{{domain_plural_capitalized}}FromMockedStub(@Mock Obtain{{domain_capitalized}} obtain{{domain_capitalized}}) { + // Stub + var {{domain}} = + {{domain_capitalized}}.builder() + .code(1L) + .description( + "I want to sleep\r\nSwat the flies\r\nSoftly, please.\r\n\r\n-- Masaoka Shiki (1867-1902)") + .build(); + Mockito.lenient().when(obtain{{domain_capitalized}}.getAll{{domain_plural_capitalized}}()).thenReturn(List.of({{domain}})); + // hexagon + var request{{domain_capitalized}} = new {{domain_capitalized}}Domain(obtain{{domain_capitalized}}); + var {{domain_plural}} = request{{domain_capitalized}}.get{{domain_plural_capitalized}}(); + assertThat({{domain_plural}}) + .hasSize(1) + .extracting("description") + .contains( + "I want to sleep\r\nSwat the flies\r\nSoftly, please.\r\n\r\n-- Masaoka Shiki (1867-1902)"); + } + + @Test + @DisplayName("should be able to get {{domain}} when asked for {{domain}} by id from stub") + public void get{{domain_capitalized}}ByIdFromMockedStub(@Mock Obtain{{domain_capitalized}} obtain{{domain_capitalized}}) { + // Given + // Stub + var code = 1L; + var description = + "I want to sleep\\r\\nSwat the flies\\r\\nSoftly, please.\\r\\n\\r\\n-- Masaoka Shiki (1867-1902)"; + var expected{{domain_capitalized}} = {{domain_capitalized}}.builder().code(code).description(description).build(); + Mockito.lenient() + .when(obtain{{domain_capitalized}}.get{{domain_capitalized}}ByCode(code)) + .thenReturn(Optional.of(expected{{domain_capitalized}})); + // When + var request{{domain_capitalized}} = new {{domain_capitalized}}Domain(obtain{{domain_capitalized}}); + var actual{{domain_capitalized}} = request{{domain_capitalized}}.get{{domain_capitalized}}ByCode(code); + assertThat(actual{{domain_capitalized}}).isNotNull().isEqualTo(expected{{domain_capitalized}}); + } + + @Test + @DisplayName("should throw exception when asked for {{domain}} by id that does not exists from stub") + public void getExceptionWhenAsked{{domain_capitalized}}ByIdThatDoesNotExist(@Mock Obtain{{domain_capitalized}} obtain{{domain_capitalized}}) { + // Given + // Stub + var code = -1000L; + Mockito.lenient().when(obtain{{domain_capitalized}}.get{{domain_capitalized}}ByCode(code)).thenReturn(Optional.empty()); + // When + var request{{domain_capitalized}} = new {{domain_capitalized}}Domain(obtain{{domain_capitalized}}); + // Then + assertThatThrownBy(() -> request{{domain_capitalized}}.get{{domain_capitalized}}ByCode(code)) + .isInstanceOf({{domain_capitalized}}NotFoundException.class) + .hasMessageContaining("{{domain_capitalized}} with code " + code + " does not exist"); + } +} diff --git a/{{cookiecutter.app_name}}/jpa-adapter/pom.xml b/{{app_name}}/jpa-adapter/pom.xml.jinja similarity index 95% rename from {{cookiecutter.app_name}}/jpa-adapter/pom.xml rename to {{app_name}}/jpa-adapter/pom.xml.jinja index 72c3e9f..310c326 100644 --- a/{{cookiecutter.app_name}}/jpa-adapter/pom.xml +++ b/{{app_name}}/jpa-adapter/pom.xml.jinja @@ -3,8 +3,8 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - {{cookiecutter.group_id}} - {{cookiecutter.artifact_id}}-parent + {{group_id}} + {{artifact_id}}-parent 1.0-SNAPSHOT 4.0.0 @@ -12,7 +12,7 @@ - {{cookiecutter.group_id}} + {{group_id}} domain-api diff --git a/{{app_name}}/jpa-adapter/src/main/java/{{package_name}}/repository/config/JpaAdapterConfig.java.jinja b/{{app_name}}/jpa-adapter/src/main/java/{{package_name}}/repository/config/JpaAdapterConfig.java.jinja new file mode 100644 index 0000000..7a270e7 --- /dev/null +++ b/{{app_name}}/jpa-adapter/src/main/java/{{package_name}}/repository/config/JpaAdapterConfig.java.jinja @@ -0,0 +1,23 @@ +package {{package_name}}.repository.config; + +import org.springframework.boot.autoconfigure.domain.EntityScan; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.envers.repository.support.EnversRevisionRepositoryFactoryBean; +import org.springframework.data.jpa.repository.config.EnableJpaRepositories; +import {{package_name}}.domain.port.Obtain{{domain_capitalized}}; +import {{package_name}}.repository.{{domain_capitalized}}Repository; +import {{package_name}}.repository.dao.{{domain_capitalized}}Dao; + +@Configuration +@EntityScan("{{package_name}}.repository.entity") +@EnableJpaRepositories( + basePackages = "{{package_name}}.repository.dao", + repositoryFactoryBeanClass = EnversRevisionRepositoryFactoryBean.class) +public class JpaAdapterConfig { + + @Bean + public Obtain{{domain_capitalized}} get{{domain_capitalized}}Repository({{domain_capitalized}}Dao {{domain}}Dao) { + return new {{domain_capitalized}}Repository({{domain}}Dao); + } +} diff --git a/{{app_name}}/jpa-adapter/src/main/java/{{package_name}}/repository/dao/{{domain_capitalized}}Dao.java.jinja b/{{app_name}}/jpa-adapter/src/main/java/{{package_name}}/repository/dao/{{domain_capitalized}}Dao.java.jinja new file mode 100644 index 0000000..6964a43 --- /dev/null +++ b/{{app_name}}/jpa-adapter/src/main/java/{{package_name}}/repository/dao/{{domain_capitalized}}Dao.java.jinja @@ -0,0 +1,14 @@ +package {{package_name}}.repository.dao; + +import java.util.Optional; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.repository.history.RevisionRepository; +import org.springframework.stereotype.Repository; +import {{package_name}}.repository.entity.{{domain_capitalized}}Entity; + +@Repository +public interface {{domain_capitalized}}Dao + extends JpaRepository<{{domain_capitalized}}Entity, Long>, RevisionRepository<{{domain_capitalized}}Entity, Long, Long> { + + Optional<{{domain_capitalized}}Entity> findByCode(Long code); +} diff --git a/{{cookiecutter.app_name}}/jpa-adapter/src/main/java/{{cookiecutter.package_name}}/repository/entity/EnversRevisionEntity.java b/{{app_name}}/jpa-adapter/src/main/java/{{package_name}}/repository/entity/EnversRevisionEntity.java.jinja similarity index 72% rename from {{cookiecutter.app_name}}/jpa-adapter/src/main/java/{{cookiecutter.package_name}}/repository/entity/EnversRevisionEntity.java rename to {{app_name}}/jpa-adapter/src/main/java/{{package_name}}/repository/entity/EnversRevisionEntity.java.jinja index 6af7556..4384b91 100644 --- a/{{cookiecutter.app_name}}/jpa-adapter/src/main/java/{{cookiecutter.package_name}}/repository/entity/EnversRevisionEntity.java +++ b/{{app_name}}/jpa-adapter/src/main/java/{{package_name}}/repository/entity/EnversRevisionEntity.java.jinja @@ -1,4 +1,4 @@ -package {{cookiecutter.package_name}}.repository.entity; +package {{package_name}}.repository.entity; import jakarta.persistence.Column; import jakarta.persistence.Entity; @@ -12,16 +12,16 @@ import lombok.Data; import lombok.NoArgsConstructor; -@Table(name = "REVISION_INFO", schema = "{{cookiecutter.domain_uppercase}}_AUDIT") +@Table(name = "REVISION_INFO", schema = "{{domain_uppercase}}_AUDIT") @Entity @Data @Builder @AllArgsConstructor @NoArgsConstructor @SequenceGenerator( - schema = "{{cookiecutter.domain_uppercase}}_AUDIT", + schema = "{{domain_uppercase}}_AUDIT", name = "SEQ_REVISION_INFO", - sequenceName = "{{cookiecutter.domain_uppercase}}_AUDIT.SEQ_REVISION_INFO", + sequenceName = "{{domain_uppercase}}_AUDIT.SEQ_REVISION_INFO", allocationSize = 1) public class EnversRevisionEntity { @Id diff --git a/{{cookiecutter.app_name}}/jpa-adapter/src/main/java/{{cookiecutter.package_name}}/repository/entity/{{cookiecutter.domain_capitalized}}Entity.java b/{{app_name}}/jpa-adapter/src/main/java/{{package_name}}/repository/entity/{{domain_capitalized}}Entity.java.jinja similarity index 57% rename from {{cookiecutter.app_name}}/jpa-adapter/src/main/java/{{cookiecutter.package_name}}/repository/entity/{{cookiecutter.domain_capitalized}}Entity.java rename to {{app_name}}/jpa-adapter/src/main/java/{{package_name}}/repository/entity/{{domain_capitalized}}Entity.java.jinja index 3c1d673..745f1ae 100644 --- a/{{cookiecutter.app_name}}/jpa-adapter/src/main/java/{{cookiecutter.package_name}}/repository/entity/{{cookiecutter.domain_capitalized}}Entity.java +++ b/{{app_name}}/jpa-adapter/src/main/java/{{package_name}}/repository/entity/{{domain_capitalized}}Entity.java.jinja @@ -1,4 +1,4 @@ -package {{cookiecutter.package_name}}.repository.entity; +package {{package_name}}.repository.entity; import jakarta.persistence.Column; import jakarta.persistence.Entity; @@ -12,22 +12,22 @@ import lombok.Data; import lombok.NoArgsConstructor; import org.hibernate.envers.Audited; -import {{cookiecutter.package_name}}.domain.model.{{cookiecutter.domain_capitalized}}; +import {{package_name}}.domain.model.{{domain_capitalized}}; -@Table(name = "T_{{cookiecutter.domain_uppercase}}") +@Table(name = "T_{{domain_uppercase}}") @Entity @Data @Builder @AllArgsConstructor @NoArgsConstructor @Audited -public class {{cookiecutter.domain_capitalized}}Entity { +public class {{domain_capitalized}}Entity { @Id - @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ_T_{{cookiecutter.domain_uppercase}}") + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ_T_{{domain_uppercase}}") @SequenceGenerator( - name = "SEQ_T_{{cookiecutter.domain_uppercase}}", - sequenceName = "SEQ_T_{{cookiecutter.domain_uppercase}}", + name = "SEQ_T_{{domain_uppercase}}", + sequenceName = "SEQ_T_{{domain_uppercase}}", allocationSize = 1, initialValue = 1) @Column(name = "TECH_ID") @@ -39,7 +39,7 @@ public class {{cookiecutter.domain_capitalized}}Entity { @Column(name = "DESCRIPTION") private String description; - public {{cookiecutter.domain_capitalized}} toModel() { - return {{cookiecutter.domain_capitalized}}.builder().code(code).description(description).build(); + public {{domain_capitalized}} toModel() { + return {{domain_capitalized}}.builder().code(code).description(description).build(); } } diff --git a/{{app_name}}/jpa-adapter/src/main/java/{{package_name}}/repository/{{domain_capitalized}}Repository.java.jinja b/{{app_name}}/jpa-adapter/src/main/java/{{package_name}}/repository/{{domain_capitalized}}Repository.java.jinja new file mode 100644 index 0000000..4cbfa02 --- /dev/null +++ b/{{app_name}}/jpa-adapter/src/main/java/{{package_name}}/repository/{{domain_capitalized}}Repository.java.jinja @@ -0,0 +1,29 @@ +package {{package_name}}.repository; + +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; +import {{package_name}}.domain.model.{{domain_capitalized}}; +import {{package_name}}.domain.port.Obtain{{domain_capitalized}}; +import {{package_name}}.repository.dao.{{domain_capitalized}}Dao; +import {{package_name}}.repository.entity.{{domain_capitalized}}Entity; + +public class {{domain_capitalized}}Repository implements Obtain{{domain_capitalized}} { + + private final {{domain_capitalized}}Dao {{domain}}Dao; + + public {{domain_capitalized}}Repository({{domain_capitalized}}Dao {{domain}}Dao) { + this.{{domain}}Dao = {{domain}}Dao; + } + + @Override + public List<{{domain_capitalized}}> getAll{{domain_plural_capitalized}}() { + return {{domain}}Dao.findAll().stream().map({{domain_capitalized}}Entity::toModel).collect(Collectors.toList()); + } + + @Override + public Optional<{{domain_capitalized}}> get{{domain_capitalized}}ByCode(Long code) { + var {{domain}}Entity = {{domain}}Dao.findByCode(code); + return {{domain}}Entity.map({{domain_capitalized}}Entity::toModel); + } +} diff --git a/{{cookiecutter.app_name}}/jpa-adapter/src/main/resources/application.yaml b/{{app_name}}/jpa-adapter/src/main/resources/application.yaml.jinja similarity index 73% rename from {{cookiecutter.app_name}}/jpa-adapter/src/main/resources/application.yaml rename to {{app_name}}/jpa-adapter/src/main/resources/application.yaml.jinja index ce5094b..6fd2506 100644 --- a/{{cookiecutter.app_name}}/jpa-adapter/src/main/resources/application.yaml +++ b/{{app_name}}/jpa-adapter/src/main/resources/application.yaml.jinja @@ -12,16 +12,16 @@ spring: show-sql: ${database.show_sql:false} properties: hibernate: - default_schema: ${database.default_schema:{{cookiecutter.domain_uppercase}}} + default_schema: ${database.default_schema:{{domain_uppercase}}} show_sql: ${database.show_sql:false} use_sql_comments: ${database.use_sql_comments:false} format_sql: ${database.format_sql:false} org: hibernate: envers: - default_schema: ${database.default_audit_schema:{{cookiecutter.domain_uppercase}}_AUDIT} + default_schema: ${database.default_audit_schema:{{domain_uppercase}}_AUDIT} store_data_at_delete: true liquibase: enabled: true liquibase-schema: ${database.liquibase_schema:LIQUIBASE} - default-schema: ${database.default_schema:{{cookiecutter.domain_uppercase}}} + default-schema: ${database.default_schema:{{domain_uppercase}}} diff --git a/{{cookiecutter.app_name}}/jpa-adapter/src/main/resources/db/changelog/db.changelog-master.yaml b/{{app_name}}/jpa-adapter/src/main/resources/db/changelog/db.changelog-master.yaml.jinja similarity index 57% rename from {{cookiecutter.app_name}}/jpa-adapter/src/main/resources/db/changelog/db.changelog-master.yaml rename to {{app_name}}/jpa-adapter/src/main/resources/db/changelog/db.changelog-master.yaml.jinja index 859d7d1..641bae0 100644 --- a/{{cookiecutter.app_name}}/jpa-adapter/src/main/resources/db/changelog/db.changelog-master.yaml +++ b/{{app_name}}/jpa-adapter/src/main/resources/db/changelog/db.changelog-master.yaml.jinja @@ -2,4 +2,4 @@ databaseChangeLog: - include: file: db/changelog/includes/240720211408009-create-revision.yaml - include: - file: db/changelog/includes/110720212155010-create-{{cookiecutter.domain}}.yaml \ No newline at end of file + file: db/changelog/includes/110720212155010-create-{{domain}}.yaml \ No newline at end of file diff --git a/{{cookiecutter.app_name}}/jpa-adapter/src/main/resources/db/changelog/includes/110720212155010-create-{{cookiecutter.domain}}.yaml b/{{app_name}}/jpa-adapter/src/main/resources/db/changelog/includes/110720212155010-create-{{domain}}.yaml.jinja similarity index 66% rename from {{cookiecutter.app_name}}/jpa-adapter/src/main/resources/db/changelog/includes/110720212155010-create-{{cookiecutter.domain}}.yaml rename to {{app_name}}/jpa-adapter/src/main/resources/db/changelog/includes/110720212155010-create-{{domain}}.yaml.jinja index 34ec4de..96794c5 100644 --- a/{{cookiecutter.app_name}}/jpa-adapter/src/main/resources/db/changelog/includes/110720212155010-create-{{cookiecutter.domain}}.yaml +++ b/{{app_name}}/jpa-adapter/src/main/resources/db/changelog/includes/110720212155010-create-{{domain}}.yaml.jinja @@ -1,10 +1,10 @@ databaseChangeLog: - changeSet: - id: create-table-t_{{cookiecutter.domain}} + id: create-table-t_{{domain}} author: Paul WILLIAMS changes: - createTable: - tableName: T_{{cookiecutter.domain_uppercase}} + tableName: T_{{domain_uppercase}} columns: - column: name: TECH_ID @@ -23,21 +23,21 @@ databaseChangeLog: constraints: nullable: false createSequence: - sequenceName: SEQ_T_{{cookiecutter.domain_uppercase}} + sequenceName: SEQ_T_{{domain_uppercase}} startValue: 1 incrementBy: 1 rollback: - dropSequence: - sequenceName: SEQ_T_{{cookiecutter.domain_uppercase}} + sequenceName: SEQ_T_{{domain_uppercase}} - dropTable: - tableName: T_{{cookiecutter.domain_uppercase}} + tableName: T_{{domain_uppercase}} - changeSet: - id: create-table-t_{{cookiecutter.domain}}_aud + id: create-table-t_{{domain}}_aud author: Paul WILLIAMS changes: - createTable: - schemaName: {{cookiecutter.domain_uppercase}}_AUDIT - tableName: T_{{cookiecutter.domain_uppercase}}_AUD + schemaName: {{domain_uppercase}}_AUDIT + tableName: T_{{domain_uppercase}}_AUD columns: - column: name: TECH_ID @@ -59,19 +59,19 @@ databaseChangeLog: type: BIGINT constraints: nullable: false - foreignKeyName: FK_T_{{cookiecutter.domain_uppercase}}_AUD_REV - references: {{cookiecutter.domain_uppercase}}_AUDIT.REVINFO(REV) + foreignKeyName: FK_T_{{domain_uppercase}}_AUD_REV + references: {{domain_uppercase}}_AUDIT.REVINFO(REV) - column: name: REVTYPE type: INTEGER constraints: nullable: false - addPrimaryKey: - schemaName: {{cookiecutter.domain_uppercase}}_AUDIT - tableName: T_{{cookiecutter.domain_uppercase}}_AUD + schemaName: {{domain_uppercase}}_AUDIT + tableName: T_{{domain_uppercase}}_AUD columnNames: TECH_ID, REV rollback: - dropTable: - schemaName: {{cookiecutter.domain_uppercase}}_AUDIT - tableName: T_{{cookiecutter.domain_uppercase}}_AUD + schemaName: {{domain_uppercase}}_AUDIT + tableName: T_{{domain_uppercase}}_AUD cascadeConstraints: true diff --git a/{{cookiecutter.app_name}}/jpa-adapter/src/main/resources/db/changelog/includes/240720211408009-create-revision.yaml b/{{app_name}}/jpa-adapter/src/main/resources/db/changelog/includes/240720211408009-create-revision.yaml.jinja similarity index 72% rename from {{cookiecutter.app_name}}/jpa-adapter/src/main/resources/db/changelog/includes/240720211408009-create-revision.yaml rename to {{app_name}}/jpa-adapter/src/main/resources/db/changelog/includes/240720211408009-create-revision.yaml.jinja index 3a599a3..2e485f3 100644 --- a/{{cookiecutter.app_name}}/jpa-adapter/src/main/resources/db/changelog/includes/240720211408009-create-revision.yaml +++ b/{{app_name}}/jpa-adapter/src/main/resources/db/changelog/includes/240720211408009-create-revision.yaml.jinja @@ -1,10 +1,10 @@ databaseChangeLog: - changeSet: - id: create-table-t_{{cookiecutter.domain}}_audit + id: create-table-t_{{domain}}_audit author: Anup Baranwal changes: - createTable: - schemaName: {{cookiecutter.domain_uppercase}}_AUDIT + schemaName: {{domain_uppercase}}_AUDIT tableName: REVINFO columns: - column: @@ -20,15 +20,15 @@ databaseChangeLog: constraints: nullable: false createSequence: - schemaName: {{cookiecutter.domain_uppercase}}_AUDIT + schemaName: {{domain_uppercase}}_AUDIT sequenceName: SEQ_REVISION_INFO startValue: 1 incrementBy: 1 rollback: - dropTable: - schemaName: {{cookiecutter.domain_uppercase}}_AUDIT + schemaName: {{domain_uppercase}}_AUDIT tableName: REVINFO cascadeConstraints: true - dropSequence: - schemaName: {{cookiecutter.domain_uppercase}}_AUDIT + schemaName: {{domain_uppercase}}_AUDIT sequenceName: SEQ_REVISION_INFO \ No newline at end of file diff --git a/{{cookiecutter.app_name}}/jpa-adapter/src/main/resources/preliquibase/default.sql b/{{app_name}}/jpa-adapter/src/main/resources/preliquibase/default.sql.jinja similarity index 70% rename from {{cookiecutter.app_name}}/jpa-adapter/src/main/resources/preliquibase/default.sql rename to {{app_name}}/jpa-adapter/src/main/resources/preliquibase/default.sql.jinja index e2af544..690bff3 100644 --- a/{{cookiecutter.app_name}}/jpa-adapter/src/main/resources/preliquibase/default.sql +++ b/{{app_name}}/jpa-adapter/src/main/resources/preliquibase/default.sql.jinja @@ -1,3 +1,3 @@ CREATE SCHEMA IF NOT EXISTS ${spring.liquibase.liquibase-schema:LIQUIBASE}; -CREATE SCHEMA IF NOT EXISTS ${spring.liquibase.default-schema:{{cookiecutter.domain_uppercase}}}; -CREATE SCHEMA IF NOT EXISTS ${spring.jpa.properties.org.hibernate.envers:{{cookiecutter.domain_uppercase}}_AUDIT}; \ No newline at end of file +CREATE SCHEMA IF NOT EXISTS ${spring.liquibase.default-schema:{{domain_uppercase}}}; +CREATE SCHEMA IF NOT EXISTS ${spring.jpa.properties.org.hibernate.envers:{{domain_uppercase}}_AUDIT}; \ No newline at end of file diff --git a/{{cookiecutter.app_name}}/jpa-adapter/src/test/java/{{cookiecutter.package_name}}/repository/{{cookiecutter.domain_capitalized}}JpaAdapterApplication.java b/{{app_name}}/jpa-adapter/src/test/java/{{package_name}}/repository/{{domain_capitalized}}JpaAdapterApplication.java.jinja similarity index 61% rename from {{cookiecutter.app_name}}/jpa-adapter/src/test/java/{{cookiecutter.package_name}}/repository/{{cookiecutter.domain_capitalized}}JpaAdapterApplication.java rename to {{app_name}}/jpa-adapter/src/test/java/{{package_name}}/repository/{{domain_capitalized}}JpaAdapterApplication.java.jinja index 501370c..7aa3f28 100644 --- a/{{cookiecutter.app_name}}/jpa-adapter/src/test/java/{{cookiecutter.package_name}}/repository/{{cookiecutter.domain_capitalized}}JpaAdapterApplication.java +++ b/{{app_name}}/jpa-adapter/src/test/java/{{package_name}}/repository/{{domain_capitalized}}JpaAdapterApplication.java.jinja @@ -1,4 +1,4 @@ -package {{cookiecutter.package_name}}.repository; +package {{package_name}}.repository; import net.lbruun.springboot.preliquibase.PreLiquibaseAutoConfiguration; import org.springframework.boot.SpringApplication; @@ -6,17 +6,17 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.test.context.TestConfiguration; import org.springframework.context.annotation.Import; -import {{cookiecutter.package_name}}.repository.config.JpaAdapterConfig; +import {{package_name}}.repository.config.JpaAdapterConfig; @SpringBootApplication -public class {{cookiecutter.domain_capitalized}}JpaAdapterApplication { +public class {{domain_capitalized}}JpaAdapterApplication { public static void main(String[] args) { - SpringApplication.run({{cookiecutter.domain_capitalized}}JpaAdapterApplication.class, args); + SpringApplication.run({{domain_capitalized}}JpaAdapterApplication.class, args); } @TestConfiguration @Import(JpaAdapterConfig.class) @ImportAutoConfiguration({PreLiquibaseAutoConfiguration.class}) - static class {{cookiecutter.domain_capitalized}}JpaTestConfig {} + static class {{domain_capitalized}}JpaTestConfig {} } diff --git a/{{app_name}}/jpa-adapter/src/test/java/{{package_name}}/repository/{{domain_capitalized}}JpaTest.java.jinja b/{{app_name}}/jpa-adapter/src/test/java/{{package_name}}/repository/{{domain_capitalized}}JpaTest.java.jinja new file mode 100644 index 0000000..ad36dca --- /dev/null +++ b/{{app_name}}/jpa-adapter/src/test/java/{{package_name}}/repository/{{domain_capitalized}}JpaTest.java.jinja @@ -0,0 +1,80 @@ +package {{package_name}}.repository; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.jdbc.Sql; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import {{package_name}}.domain.model.{{domain_capitalized}}; +import {{package_name}}.domain.port.Obtain{{domain_capitalized}}; + +@ExtendWith(SpringExtension.class) +@DataJpaTest +@ActiveProfiles("test") +public class {{domain_capitalized}}JpaTest { + + @Autowired private Obtain{{domain_capitalized}} obtain{{domain_capitalized}}; + + @Test + @DisplayName("should start the application") + public void startup() { + assertThat(Boolean.TRUE).isTrue(); + } + + @Sql(scripts = {"/sql/data.sql"}) + @Test + @DisplayName( + "given {{domain_plural}} exist in database when asked should return all {{domain_plural}} from database") + public void shouldGiveMe{{domain_plural_capitalized}}WhenAskedGiven{{domain_capitalized}}ExistsInDatabase() { + // Given from @Sql + // When + var {{domain_plural}} = obtain{{domain_capitalized}}.getAll{{domain_plural_capitalized}}(); + // Then + assertThat({{domain_plural}}) + .isNotNull() + .extracting("description") + .contains("Twinkle twinkle little star"); + } + + @Test + @DisplayName("given no {{domain_plural}} exists in database when asked should return empty") + public void shouldGiveNo{{domain_capitalized}}WhenAskedGiven{{domain_plural_capitalized}}DoNotExistInDatabase() { + // When + var {{domain_plural}} = obtain{{domain_capitalized}}.getAll{{domain_plural_capitalized}}(); + // Then + assertThat({{domain_plural}}).isNotNull().isEmpty(); + } + + @Sql(scripts = {"/sql/data.sql"}) + @Test + @DisplayName( + "given {{domain_plural}} exists in database when asked for {{domain}} by id should return the {{domain}}") + public void shouldGiveThe{{domain_capitalized}}WhenAskedByIdGivenThat{{domain_capitalized}}ByThatIdExistsInDatabase() { + // Given from @Sql + // When + var {{domain}} = obtain{{domain_capitalized}}.get{{domain_capitalized}}ByCode(1L); + // Then + assertThat({{domain}}) + .isNotNull() + .isNotEmpty() + .get() + .isEqualTo({{domain_capitalized}}.builder().code(1L).description("Twinkle twinkle little star").build()); + } + + @Sql(scripts = {"/sql/data.sql"}) + @Test + @DisplayName( + "given {{domain_plural}} exists in database when asked for {{domain}} by id that does not exist should give empty") + public void shouldGiveNo{{domain_capitalized}}WhenAskedByIdGivenThat{{domain_capitalized}}ByThatIdDoesNotExistInDatabase() { + // Given from @Sql + // When + var {{domain}} = obtain{{domain_capitalized}}.get{{domain_capitalized}}ByCode(-1000L); + // Then + assertThat({{domain}}).isEmpty(); + } +} diff --git a/{{cookiecutter.app_name}}/jpa-adapter/src/test/resources/application-test.yml b/{{app_name}}/jpa-adapter/src/test/resources/application-test.yml.jinja similarity index 100% rename from {{cookiecutter.app_name}}/jpa-adapter/src/test/resources/application-test.yml rename to {{app_name}}/jpa-adapter/src/test/resources/application-test.yml.jinja diff --git a/{{app_name}}/jpa-adapter/src/test/resources/sql/data.sql.jinja b/{{app_name}}/jpa-adapter/src/test/resources/sql/data.sql.jinja new file mode 100644 index 0000000..2930e79 --- /dev/null +++ b/{{app_name}}/jpa-adapter/src/test/resources/sql/data.sql.jinja @@ -0,0 +1,2 @@ +INSERT INTO {{domain_uppercase}}.T_{{domain_uppercase}}(TECH_ID, CODE, DESCRIPTION) VALUES +(1000, 1, 'Twinkle twinkle little star'); \ No newline at end of file diff --git a/{{cookiecutter.app_name}}/pom.xml b/{{app_name}}/pom.xml.jinja similarity index 96% rename from {{cookiecutter.app_name}}/pom.xml rename to {{app_name}}/pom.xml.jinja index c446507..67810e5 100644 --- a/{{cookiecutter.app_name}}/pom.xml +++ b/{{app_name}}/pom.xml.jinja @@ -3,8 +3,8 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - {{cookiecutter.group_id}} - {{cookiecutter.artifact_id}}-parent + {{group_id}} + {{artifact_id}}-parent pom 1.0-SNAPSHOT @@ -46,27 +46,27 @@ - {{cookiecutter.group_id}} + {{group_id}} domain-api ${project.version} - {{cookiecutter.group_id}} + {{group_id}} domain ${project.version} - {{cookiecutter.group_id}} + {{group_id}} jpa-adapter ${project.version} - {{cookiecutter.group_id}} + {{group_id}} rest-adapter ${project.version} - {{cookiecutter.group_id}} + {{group_id}} bootstrap ${project.version} diff --git a/{{cookiecutter.app_name}}/rest-adapter/pom.xml b/{{app_name}}/rest-adapter/pom.xml.jinja similarity index 88% rename from {{cookiecutter.app_name}}/rest-adapter/pom.xml rename to {{app_name}}/rest-adapter/pom.xml.jinja index 704d71a..5a9006c 100644 --- a/{{cookiecutter.app_name}}/rest-adapter/pom.xml +++ b/{{app_name}}/rest-adapter/pom.xml.jinja @@ -3,8 +3,8 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - {{cookiecutter.group_id}} - {{cookiecutter.artifact_id}}-parent + {{group_id}} + {{artifact_id}}-parent 1.0-SNAPSHOT 4.0.0 @@ -12,7 +12,7 @@ - {{cookiecutter.group_id}} + {{group_id}} domain-api @@ -53,13 +53,13 @@ spring spring-boot - {{cookiecutter.domain_capitalized}}={{cookiecutter.package_name}}.domain.model.{{cookiecutter.domain_capitalized}} + {{domain_capitalized}}={{package_name}}.domain.model.{{domain_capitalized}} OffsetDateTime=java.time.LocalDateTime - {{cookiecutter.package_name}}.rest.generated.api - {{cookiecutter.package_name}}.rest.generated.model + {{package_name}}.rest.generated.api + {{package_name}}.rest.generated.model false false diff --git a/{{cookiecutter.app_name}}/rest-adapter/src/main/java/{{cookiecutter.package_name}}/rest/exception/{{cookiecutter.domain_capitalized}}ExceptionHandler.java b/{{app_name}}/rest-adapter/src/main/java/{{package_name}}/rest/exception/{{domain_capitalized}}ExceptionHandler.java.jinja similarity index 58% rename from {{cookiecutter.app_name}}/rest-adapter/src/main/java/{{cookiecutter.package_name}}/rest/exception/{{cookiecutter.domain_capitalized}}ExceptionHandler.java rename to {{app_name}}/rest-adapter/src/main/java/{{package_name}}/rest/exception/{{domain_capitalized}}ExceptionHandler.java.jinja index 4f7cdb2..57fa3c6 100644 --- a/{{cookiecutter.app_name}}/rest-adapter/src/main/java/{{cookiecutter.package_name}}/rest/exception/{{cookiecutter.domain_capitalized}}ExceptionHandler.java +++ b/{{app_name}}/rest-adapter/src/main/java/{{package_name}}/rest/exception/{{domain_capitalized}}ExceptionHandler.java.jinja @@ -1,4 +1,4 @@ -package {{cookiecutter.package_name}}.rest.exception; +package {{package_name}}.rest.exception; import java.time.LocalDateTime; import org.springframework.http.HttpStatus; @@ -7,20 +7,20 @@ import org.springframework.web.bind.annotation.RestControllerAdvice; import org.springframework.web.context.request.ServletWebRequest; import org.springframework.web.context.request.WebRequest; -import {{cookiecutter.package_name}}.domain.exception.{{cookiecutter.domain_capitalized}}NotFoundException; -import {{cookiecutter.package_name}}.rest.generated.model.ProblemDetail; +import {{package_name}}.domain.exception.{{domain_capitalized}}NotFoundException; +import {{package_name}}.rest.generated.model.ProblemDetail; -@RestControllerAdvice(basePackages = {"{{cookiecutter.package_name}}"}) -public class {{cookiecutter.domain_capitalized}}ExceptionHandler { +@RestControllerAdvice(basePackages = {"{{package_name}}"}) +public class {{domain_capitalized}}ExceptionHandler { - @ExceptionHandler(value = {{cookiecutter.domain_capitalized}}NotFoundException.class) - public final ResponseEntity handle{{cookiecutter.domain_capitalized}}NotFoundException( + @ExceptionHandler(value = {{domain_capitalized}}NotFoundException.class) + public final ResponseEntity handle{{domain_capitalized}}NotFoundException( final Exception exception, final WebRequest request) { var problem = ProblemDetail.builder() .type("https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/404") .status(HttpStatus.NOT_FOUND.value()) - .title("{{cookiecutter.domain_capitalized}} not found") + .title("{{domain_capitalized}} not found") .detail(exception.getMessage()) .instance(((ServletWebRequest) request).getRequest().getRequestURI()) .timestamp(LocalDateTime.now()) diff --git a/{{app_name}}/rest-adapter/src/main/java/{{package_name}}/rest/{{domain_capitalized}}Resource.java.jinja b/{{app_name}}/rest-adapter/src/main/java/{{package_name}}/rest/{{domain_capitalized}}Resource.java.jinja new file mode 100644 index 0000000..d3f9865 --- /dev/null +++ b/{{app_name}}/rest-adapter/src/main/java/{{package_name}}/rest/{{domain_capitalized}}Resource.java.jinja @@ -0,0 +1,27 @@ +package {{package_name}}.rest; + +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RestController; +import {{package_name}}.domain.model.{{domain_capitalized}}; +import {{package_name}}.domain.port.Request{{domain_capitalized}}; +import {{package_name}}.rest.generated.api.{{domain_capitalized}}Api; +import {{package_name}}.rest.generated.model.{{domain_capitalized}}Info; + +@RestController +public class {{domain_capitalized}}Resource implements {{domain_capitalized}}Api { + + private final Request{{domain_capitalized}} request{{domain_capitalized}}; + + public {{domain_capitalized}}Resource(Request{{domain_capitalized}} request{{domain_capitalized}}) { + this.request{{domain_capitalized}} = request{{domain_capitalized}}; + } + + public ResponseEntity<{{domain_capitalized}}Info> get{{domain_plural_capitalized}}() { + return ResponseEntity.ok({{domain_capitalized}}Info.builder().{{domain_plural}}(request{{domain_capitalized}}.get{{domain_plural_capitalized}}()).build()); + } + + public ResponseEntity<{{domain_capitalized}}> get{{domain_capitalized}}ByCode(@PathVariable("code") Long code) { + return ResponseEntity.ok(request{{domain_capitalized}}.get{{domain_capitalized}}ByCode(code)); + } +} diff --git a/{{cookiecutter.app_name}}/rest-adapter/src/main/resources/open-api.yaml b/{{app_name}}/rest-adapter/src/main/resources/open-api.yaml.jinja similarity index 52% rename from {{cookiecutter.app_name}}/rest-adapter/src/main/resources/open-api.yaml rename to {{app_name}}/rest-adapter/src/main/resources/open-api.yaml.jinja index 1b8c987..da7d3dd 100644 --- a/{{cookiecutter.app_name}}/rest-adapter/src/main/resources/open-api.yaml +++ b/{{app_name}}/rest-adapter/src/main/resources/open-api.yaml.jinja @@ -1,31 +1,31 @@ --- openapi: 3.0.1 info: - title: {{cookiecutter.domain_capitalized}} API Documentation + title: {{domain_capitalized}} API Documentation version: v1 tags: - - name: {{cookiecutter.domain_capitalized}} - description: Resource to manage {{cookiecutter.domain}} + - name: {{domain_capitalized}} + description: Resource to manage {{domain}} paths: - "/api/v1/{{cookiecutter.domain_plural}}": + "/api/v1/{{domain_plural}}": get: tags: - - {{cookiecutter.domain_capitalized}} - summary: Get all {{cookiecutter.domain_plural}} - operationId: get{{cookiecutter.domain_plural_capitalized}} + - {{domain_capitalized}} + summary: Get all {{domain_plural}} + operationId: get{{domain_plural_capitalized}} responses: '200': description: OK content: "*/*": schema: - "$ref": "#/components/schemas/{{cookiecutter.domain_capitalized}}Info" - "/api/v1/{{cookiecutter.domain_plural}}/{code}": + "$ref": "#/components/schemas/{{domain_capitalized}}Info" + "/api/v1/{{domain_plural}}/{code}": get: tags: - - {{cookiecutter.domain_capitalized}} - summary: Get {{cookiecutter.domain}} by code - operationId: get{{cookiecutter.domain_capitalized}}ByCode + - {{domain_capitalized}} + summary: Get {{domain}} by code + operationId: get{{domain_capitalized}}ByCode parameters: - name: code in: path @@ -39,10 +39,10 @@ paths: content: "*/*": schema: - "$ref": "#/components/schemas/{{cookiecutter.domain_capitalized}}" + "$ref": "#/components/schemas/{{domain_capitalized}}" components: schemas: - {{cookiecutter.domain_capitalized}}: + {{domain_capitalized}}: type: object properties: code: @@ -50,13 +50,13 @@ components: format: int64 description: type: string - {{cookiecutter.domain_capitalized}}Info: + {{domain_capitalized}}Info: type: object properties: - {{cookiecutter.domain_plural}}: + {{domain_plural}}: type: array items: - "$ref": "#/components/schemas/{{cookiecutter.domain_capitalized}}" + "$ref": "#/components/schemas/{{domain_capitalized}}" ProblemDetail: type: object properties: diff --git a/{{cookiecutter.app_name}}/rest-adapter/src/test/java/{{cookiecutter.package_name}}/rest/{{cookiecutter.domain_capitalized}}ResourceTest.java b/{{app_name}}/rest-adapter/src/test/java/{{package_name}}/rest/{{domain_capitalized}}ResourceTest.java.jinja similarity index 50% rename from {{cookiecutter.app_name}}/rest-adapter/src/test/java/{{cookiecutter.package_name}}/rest/{{cookiecutter.domain_capitalized}}ResourceTest.java rename to {{app_name}}/rest-adapter/src/test/java/{{package_name}}/rest/{{domain_capitalized}}ResourceTest.java.jinja index 729a5c9..419a002 100644 --- a/{{cookiecutter.app_name}}/rest-adapter/src/test/java/{{cookiecutter.package_name}}/rest/{{cookiecutter.domain_capitalized}}ResourceTest.java +++ b/{{app_name}}/rest-adapter/src/test/java/{{package_name}}/rest/{{domain_capitalized}}ResourceTest.java.jinja @@ -1,4 +1,4 @@ -package {{cookiecutter.package_name}}.rest; +package {{package_name}}.rest; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.within; @@ -20,22 +20,22 @@ import org.springframework.boot.test.web.server.LocalServerPort; import org.springframework.http.HttpStatus; import org.springframework.test.context.bean.override.mockito.MockitoBean; -import {{cookiecutter.package_name}}.domain.exception.{{cookiecutter.domain_capitalized}}NotFoundException; -import {{cookiecutter.package_name}}.domain.model.{{cookiecutter.domain_capitalized}}; -import {{cookiecutter.package_name}}.domain.port.Request{{cookiecutter.domain_capitalized}}; -import {{cookiecutter.package_name}}.rest.generated.model.{{cookiecutter.domain_capitalized}}Info; -import {{cookiecutter.package_name}}.rest.generated.model.ProblemDetail; +import {{package_name}}.domain.exception.{{domain_capitalized}}NotFoundException; +import {{package_name}}.domain.model.{{domain_capitalized}}; +import {{package_name}}.domain.port.Request{{domain_capitalized}}; +import {{package_name}}.rest.generated.model.{{domain_capitalized}}Info; +import {{package_name}}.rest.generated.model.ProblemDetail; @ExtendWith(MockitoExtension.class) -@SpringBootTest(classes = {{cookiecutter.domain_capitalized}}RestAdapterApplication.class, webEnvironment = RANDOM_PORT) +@SpringBootTest(classes = {{domain_capitalized}}RestAdapterApplication.class, webEnvironment = RANDOM_PORT) @EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class}) -public class {{cookiecutter.domain_capitalized}}ResourceTest { +public class {{domain_capitalized}}ResourceTest { private static final String LOCALHOST = "http://localhost:"; - private static final String API_URI = "/api/v1/{{cookiecutter.domain_plural}}"; + private static final String API_URI = "/api/v1/{{domain_plural}}"; @LocalServerPort private int port; @Autowired private TestRestTemplate restTemplate; - @MockitoBean private Request{{cookiecutter.domain_capitalized}} request{{cookiecutter.domain_capitalized}}; + @MockitoBean private Request{{domain_capitalized}} request{{domain_capitalized}}; @Test @DisplayName("should start the rest adapter application") @@ -44,18 +44,18 @@ public void startup() { } @Test - @DisplayName("should give {{cookiecutter.domain_plural}} when asked for {{cookiecutter.domain_plural}} with the support of domain stub") - public void obtain{{cookiecutter.domain_plural_capitalized}}FromDomainStub() { + @DisplayName("should give {{domain_plural}} when asked for {{domain_plural}} with the support of domain stub") + public void obtain{{domain_plural_capitalized}}FromDomainStub() { // Given - var {{cookiecutter.domain}} = {{cookiecutter.domain_capitalized}}.builder().code(1L).description("Johnny Johnny Yes Papa !!").build(); - Mockito.lenient().when(request{{cookiecutter.domain_capitalized}}.get{{cookiecutter.domain_plural_capitalized}}()).thenReturn(List.of({{cookiecutter.domain}})); + var {{domain}} = {{domain_capitalized}}.builder().code(1L).description("Johnny Johnny Yes Papa !!").build(); + Mockito.lenient().when(request{{domain_capitalized}}.get{{domain_plural_capitalized}}()).thenReturn(List.of({{domain}})); // When var url = LOCALHOST + port + API_URI; - var responseEntity = restTemplate.getForEntity(url, {{cookiecutter.domain_capitalized}}Info.class); + var responseEntity = restTemplate.getForEntity(url, {{domain_capitalized}}Info.class); // Then assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK); assertThat(responseEntity.getBody()).isNotNull(); - assertThat(responseEntity.getBody().get{{cookiecutter.domain_plural_capitalized}}()) + assertThat(responseEntity.getBody().get{{domain_plural_capitalized}}()) .isNotEmpty() .extracting("description") .contains("Johnny Johnny Yes Papa !!"); @@ -63,31 +63,31 @@ public void startup() { @Test @DisplayName( - "should give the {{cookiecutter.domain}} when asked for an {{cookiecutter.domain}} by code with the support of domain stub") - public void obtain{{cookiecutter.domain_capitalized}}ByCodeFromDomainStub() { + "should give the {{domain}} when asked for an {{domain}} by code with the support of domain stub") + public void obtain{{domain_capitalized}}ByCodeFromDomainStub() { // Given var code = 1L; var description = "Johnny Johnny Yes Papa !!"; - var {{cookiecutter.domain}} = {{cookiecutter.domain_capitalized}}.builder().code(code).description(description).build(); - Mockito.lenient().when(request{{cookiecutter.domain_capitalized}}.get{{cookiecutter.domain_capitalized}}ByCode(code)).thenReturn({{cookiecutter.domain}}); + var {{domain}} = {{domain_capitalized}}.builder().code(code).description(description).build(); + Mockito.lenient().when(request{{domain_capitalized}}.get{{domain_capitalized}}ByCode(code)).thenReturn({{domain}}); // When var url = LOCALHOST + port + API_URI + "/" + code; - var responseEntity = restTemplate.getForEntity(url, {{cookiecutter.domain_capitalized}}.class); + var responseEntity = restTemplate.getForEntity(url, {{domain_capitalized}}.class); // Then assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK); assertThat(responseEntity.getBody()).isNotNull(); - assertThat(responseEntity.getBody()).isEqualTo({{cookiecutter.domain}}); + assertThat(responseEntity.getBody()).isEqualTo({{domain}}); } @Test @DisplayName( - "should give exception when asked for an {{cookiecutter.domain}} by code that does not exists with the support of domain stub") - public void shouldGiveExceptionWhenAskedForAn{{cookiecutter.domain_capitalized}}ByCodeFromDomainStub() { + "should give exception when asked for an {{domain}} by code that does not exists with the support of domain stub") + public void shouldGiveExceptionWhenAskedForAn{{domain_capitalized}}ByCodeFromDomainStub() { // Given var code = -1000L; Mockito.lenient() - .when(request{{cookiecutter.domain_capitalized}}.get{{cookiecutter.domain_capitalized}}ByCode(code)) - .thenThrow(new {{cookiecutter.domain_capitalized}}NotFoundException(code)); + .when(request{{domain_capitalized}}.get{{domain_capitalized}}ByCode(code)) + .thenThrow(new {{domain_capitalized}}NotFoundException(code)); // When var url = LOCALHOST + port + API_URI + "/" + code; var responseEntity = restTemplate.getForEntity(url, ProblemDetail.class); @@ -96,9 +96,9 @@ public void startup() { ProblemDetail.builder() .type("https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/404") .status(HttpStatus.NOT_FOUND.value()) - .detail("{{cookiecutter.domain_capitalized}} with code -1000 does not exist") - .instance("/api/v1/{{cookiecutter.domain_plural}}/-1000") - .title("{{cookiecutter.domain_capitalized}} not found") + .detail("{{domain_capitalized}} with code -1000 does not exist") + .instance("/api/v1/{{domain_plural}}/-1000") + .title("{{domain_capitalized}} not found") .build(); assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND); assertThat(responseEntity.getBody()).isNotNull(); diff --git a/{{app_name}}/rest-adapter/src/test/java/{{package_name}}/rest/{{domain_capitalized}}RestAdapterApplication.java.jinja b/{{app_name}}/rest-adapter/src/test/java/{{package_name}}/rest/{{domain_capitalized}}RestAdapterApplication.java.jinja new file mode 100644 index 0000000..3b6742b --- /dev/null +++ b/{{app_name}}/rest-adapter/src/test/java/{{package_name}}/rest/{{domain_capitalized}}RestAdapterApplication.java.jinja @@ -0,0 +1,14 @@ +package {{package_name}}.rest; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.ComponentScan; + +@SpringBootApplication +@ComponentScan(basePackages = "{{package_name}}") +public class {{domain_capitalized}}RestAdapterApplication { + + public static void main(String[] args) { + SpringApplication.run({{domain_capitalized}}RestAdapterApplication.class, args); + } +} diff --git a/{{cookiecutter.app_name}}/.docker/Dockerfile b/{{cookiecutter.app_name}}/.docker/Dockerfile deleted file mode 100644 index 46fc6b4..0000000 --- a/{{cookiecutter.app_name}}/.docker/Dockerfile +++ /dev/null @@ -1,7 +0,0 @@ -FROM gcr.io/distroless/java21-debian12 - -WORKDIR /app - -COPY ../../bootstrap/target/{{cookiecutter.domain}}-exec.jar . - -CMD ["{{cookiecutter.domain}}-exec.jar"] \ No newline at end of file diff --git a/{{cookiecutter.app_name}}/acceptance-test/src/test/resources/features/{{cookiecutter.domain}}.feature b/{{cookiecutter.app_name}}/acceptance-test/src/test/resources/features/{{cookiecutter.domain}}.feature deleted file mode 100644 index a6a7fbf..0000000 --- a/{{cookiecutter.app_name}}/acceptance-test/src/test/resources/features/{{cookiecutter.domain}}.feature +++ /dev/null @@ -1,24 +0,0 @@ -@{{cookiecutter.domain_capitalized}} -Feature: User would like to get {{cookiecutter.domain_plural}} - Background: - Given the following {{cookiecutter.domain_plural}} exists in the library - | code | description | - | 1 | Twinkle twinkle little star | - | 2 | Johnny Johnny Yes Papa | - - Scenario: User should be able to get all {{cookiecutter.domain_plural}} - When user requests for all {{cookiecutter.domain_plural}} - Then the user gets the following {{cookiecutter.domain_plural}} - | code | description | - | 1 | Twinkle twinkle little star | - | 2 | Johnny Johnny Yes Papa | - - Scenario: User should be able to get {{cookiecutter.domain_plural}} by code - When user requests for {{cookiecutter.domain_plural}} by code "1" - Then the user gets the following {{cookiecutter.domain_plural}} - | code | description | - | 1 | Twinkle twinkle little star | - - Scenario: User should get an appropriate NOT FOUND message while trying get {{cookiecutter.domain_plural}} by an invalid code - When user requests for {{cookiecutter.domain_plural}} by id "10000" that does not exists - Then the user gets an exception "{{cookiecutter.domain_capitalized}} with code 10000 does not exist" \ No newline at end of file diff --git a/{{cookiecutter.app_name}}/bootstrap/src/main/java/{{cookiecutter.package_name}}/boot/config/BootstrapConfig.java b/{{cookiecutter.app_name}}/bootstrap/src/main/java/{{cookiecutter.package_name}}/boot/config/BootstrapConfig.java deleted file mode 100644 index 70bf1c7..0000000 --- a/{{cookiecutter.app_name}}/bootstrap/src/main/java/{{cookiecutter.package_name}}/boot/config/BootstrapConfig.java +++ /dev/null @@ -1,19 +0,0 @@ -package {{cookiecutter.package_name}}.boot.config; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Import; -import {{cookiecutter.package_name}}.domain.{{cookiecutter.domain_capitalized}}Domain; -import {{cookiecutter.package_name}}.domain.port.Obtain{{cookiecutter.domain_capitalized}}; -import {{cookiecutter.package_name}}.domain.port.Request{{cookiecutter.domain_capitalized}}; -import {{cookiecutter.package_name}}.repository.config.JpaAdapterConfig; - -@Configuration -@Import(JpaAdapterConfig.class) -public class BootstrapConfig { - - @Bean - public Request{{cookiecutter.domain_capitalized}} getRequest{{cookiecutter.domain_capitalized}}(Obtain{{cookiecutter.domain_capitalized}} obtain{{cookiecutter.domain_capitalized}}) { - return new {{cookiecutter.domain_capitalized}}Domain(obtain{{cookiecutter.domain_capitalized}}); - } -} diff --git a/{{cookiecutter.app_name}}/domain-api/src/main/java/{{cookiecutter.package_name}}/domain/exception/{{cookiecutter.domain_capitalized}}NotFoundException.java b/{{cookiecutter.app_name}}/domain-api/src/main/java/{{cookiecutter.package_name}}/domain/exception/{{cookiecutter.domain_capitalized}}NotFoundException.java deleted file mode 100644 index 2e3a685..0000000 --- a/{{cookiecutter.app_name}}/domain-api/src/main/java/{{cookiecutter.package_name}}/domain/exception/{{cookiecutter.domain_capitalized}}NotFoundException.java +++ /dev/null @@ -1,8 +0,0 @@ -package {{cookiecutter.package_name}}.domain.exception; - -public class {{cookiecutter.domain_capitalized}}NotFoundException extends RuntimeException { - - public {{cookiecutter.domain_capitalized}}NotFoundException(Long id) { - super("{{cookiecutter.domain_capitalized}} with code " + id + " does not exist"); - } -} diff --git a/{{cookiecutter.app_name}}/domain-api/src/main/java/{{cookiecutter.package_name}}/domain/port/Obtain{{cookiecutter.domain_capitalized}}.java b/{{cookiecutter.app_name}}/domain-api/src/main/java/{{cookiecutter.package_name}}/domain/port/Obtain{{cookiecutter.domain_capitalized}}.java deleted file mode 100644 index a7b1e05..0000000 --- a/{{cookiecutter.app_name}}/domain-api/src/main/java/{{cookiecutter.package_name}}/domain/port/Obtain{{cookiecutter.domain_capitalized}}.java +++ /dev/null @@ -1,28 +0,0 @@ -package {{cookiecutter.package_name}}.domain.port; - -import java.util.List; -import java.util.Optional; -import lombok.NonNull; -import {{cookiecutter.package_name}}.domain.model.{{cookiecutter.domain_capitalized}}; - -public interface Obtain{{cookiecutter.domain_capitalized}} { - - default List<{{cookiecutter.domain_capitalized}}> getAll{{cookiecutter.domain_plural_capitalized}}() { - {{cookiecutter.domain_capitalized}} {{cookiecutter.domain}} = - {{cookiecutter.domain_capitalized}}.builder() - .code(1L) - .description( - "If you could read a leaf or tree\r\nyoud have no need of books.\r\n-- Alistair Cockburn (1987)") - .build(); - return List.of({{cookiecutter.domain}}); - } - - default Optional<{{cookiecutter.domain_capitalized}}> get{{cookiecutter.domain_capitalized}}ByCode(@NonNull Long code) { - return Optional.of( - {{cookiecutter.domain_capitalized}}.builder() - .code(1L) - .description( - "If you could read a leaf or tree\r\nyoud have no need of books.\r\n-- Alistair Cockburn (1987)") - .build()); - } -} diff --git a/{{cookiecutter.app_name}}/domain-api/src/main/java/{{cookiecutter.package_name}}/domain/port/Request{{cookiecutter.domain_capitalized}}.java b/{{cookiecutter.app_name}}/domain-api/src/main/java/{{cookiecutter.package_name}}/domain/port/Request{{cookiecutter.domain_capitalized}}.java deleted file mode 100644 index 3c385e0..0000000 --- a/{{cookiecutter.app_name}}/domain-api/src/main/java/{{cookiecutter.package_name}}/domain/port/Request{{cookiecutter.domain_capitalized}}.java +++ /dev/null @@ -1,12 +0,0 @@ -package {{cookiecutter.package_name}}.domain.port; - -import java.util.List; -import lombok.NonNull; -import {{cookiecutter.package_name}}.domain.model.{{cookiecutter.domain_capitalized}}; - -public interface Request{{cookiecutter.domain_capitalized}} { - - List<{{cookiecutter.domain_capitalized}}> get{{cookiecutter.domain_plural_capitalized}}(); - - {{cookiecutter.domain_capitalized}} get{{cookiecutter.domain_capitalized}}ByCode(@NonNull Long code); -} diff --git a/{{cookiecutter.app_name}}/domain/src/main/java/{{cookiecutter.package_name}}/domain/{{cookiecutter.domain_capitalized}}Domain.java b/{{cookiecutter.app_name}}/domain/src/main/java/{{cookiecutter.package_name}}/domain/{{cookiecutter.domain_capitalized}}Domain.java deleted file mode 100644 index 72d382d..0000000 --- a/{{cookiecutter.app_name}}/domain/src/main/java/{{cookiecutter.package_name}}/domain/{{cookiecutter.domain_capitalized}}Domain.java +++ /dev/null @@ -1,32 +0,0 @@ -package {{cookiecutter.package_name}}.domain; - -import java.util.List; -import lombok.NonNull; -import {{cookiecutter.package_name}}.domain.exception.{{cookiecutter.domain_capitalized}}NotFoundException; -import {{cookiecutter.package_name}}.domain.model.{{cookiecutter.domain_capitalized}}; -import {{cookiecutter.package_name}}.domain.port.Obtain{{cookiecutter.domain_capitalized}}; -import {{cookiecutter.package_name}}.domain.port.Request{{cookiecutter.domain_capitalized}}; - -public class {{cookiecutter.domain_capitalized}}Domain implements Request{{cookiecutter.domain_capitalized}} { - - private final Obtain{{cookiecutter.domain_capitalized}} obtain{{cookiecutter.domain_capitalized}}; - - public {{cookiecutter.domain_capitalized}}Domain() { - this(new Obtain{{cookiecutter.domain_capitalized}}() {}); - } - - public {{cookiecutter.domain_capitalized}}Domain(Obtain{{cookiecutter.domain_capitalized}} obtain{{cookiecutter.domain_capitalized}}) { - this.obtain{{cookiecutter.domain_capitalized}} = obtain{{cookiecutter.domain_capitalized}}; - } - - @Override - public List<{{cookiecutter.domain_capitalized}}> get{{cookiecutter.domain_plural_capitalized}}() { - return obtain{{cookiecutter.domain_capitalized}}.getAll{{cookiecutter.domain_plural_capitalized}}(); - } - - @Override - public {{cookiecutter.domain_capitalized}} get{{cookiecutter.domain_capitalized}}ByCode(@NonNull Long code) { - var {{cookiecutter.domain}} = obtain{{cookiecutter.domain_capitalized}}.get{{cookiecutter.domain_capitalized}}ByCode(code); - return {{cookiecutter.domain}}.orElseThrow(() -> new {{cookiecutter.domain_capitalized}}NotFoundException(code)); - } -} diff --git a/{{cookiecutter.app_name}}/domain/src/test/java/{{cookiecutter.package_name}}/AcceptanceTest.java b/{{cookiecutter.app_name}}/domain/src/test/java/{{cookiecutter.package_name}}/AcceptanceTest.java deleted file mode 100644 index fb82876..0000000 --- a/{{cookiecutter.app_name}}/domain/src/test/java/{{cookiecutter.package_name}}/AcceptanceTest.java +++ /dev/null @@ -1,92 +0,0 @@ -package {{cookiecutter.package_name}}; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; - -import java.util.List; -import java.util.Optional; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.junit.jupiter.MockitoExtension; -import {{cookiecutter.package_name}}.domain.{{cookiecutter.domain_capitalized}}Domain; -import {{cookiecutter.package_name}}.domain.exception.{{cookiecutter.domain_capitalized}}NotFoundException; -import {{cookiecutter.package_name}}.domain.model.{{cookiecutter.domain_capitalized}}; -import {{cookiecutter.package_name}}.domain.port.Obtain{{cookiecutter.domain_capitalized}}; - -@ExtendWith(MockitoExtension.class) -public class AcceptanceTest { - - @Test - @DisplayName("should be able to get {{cookiecutter.domain_plural}} when asked for {{cookiecutter.domain_plural}} from hard coded {{cookiecutter.domain_plural}}") - public void get{{cookiecutter.domain_plural_capitalized}}FromHardCoded() { - /* - Request{{cookiecutter.domain_capitalized}} - left side port - {{cookiecutter.domain_capitalized}}Domain - hexagon (domain) - Obtain{{cookiecutter.domain_capitalized}} - right side port - */ - var request{{cookiecutter.domain_capitalized}} = new {{cookiecutter.domain_capitalized}}Domain(); // the {{cookiecutter.domain}} is hard coded - var {{cookiecutter.domain_plural}} = request{{cookiecutter.domain_capitalized}}.get{{cookiecutter.domain_plural_capitalized}}(); - assertThat({{cookiecutter.domain_plural}}) - .hasSize(1) - .extracting("description") - .contains( - "If you could read a leaf or tree\r\nyoud have no need of books.\r\n-- Alistair Cockburn (1987)"); - } - - @Test - @DisplayName("should be able to get {{cookiecutter.domain_plural}} when asked for {{cookiecutter.domain_plural}} from stub") - public void get{{cookiecutter.domain_plural_capitalized}}FromMockedStub(@Mock Obtain{{cookiecutter.domain_capitalized}} obtain{{cookiecutter.domain_capitalized}}) { - // Stub - var {{cookiecutter.domain}} = - {{cookiecutter.domain_capitalized}}.builder() - .code(1L) - .description( - "I want to sleep\r\nSwat the flies\r\nSoftly, please.\r\n\r\n-- Masaoka Shiki (1867-1902)") - .build(); - Mockito.lenient().when(obtain{{cookiecutter.domain_capitalized}}.getAll{{cookiecutter.domain_plural_capitalized}}()).thenReturn(List.of({{cookiecutter.domain}})); - // hexagon - var request{{cookiecutter.domain_capitalized}} = new {{cookiecutter.domain_capitalized}}Domain(obtain{{cookiecutter.domain_capitalized}}); - var {{cookiecutter.domain_plural}} = request{{cookiecutter.domain_capitalized}}.get{{cookiecutter.domain_plural_capitalized}}(); - assertThat({{cookiecutter.domain_plural}}) - .hasSize(1) - .extracting("description") - .contains( - "I want to sleep\r\nSwat the flies\r\nSoftly, please.\r\n\r\n-- Masaoka Shiki (1867-1902)"); - } - - @Test - @DisplayName("should be able to get {{cookiecutter.domain}} when asked for {{cookiecutter.domain}} by id from stub") - public void get{{cookiecutter.domain_capitalized}}ByIdFromMockedStub(@Mock Obtain{{cookiecutter.domain_capitalized}} obtain{{cookiecutter.domain_capitalized}}) { - // Given - // Stub - var code = 1L; - var description = - "I want to sleep\\r\\nSwat the flies\\r\\nSoftly, please.\\r\\n\\r\\n-- Masaoka Shiki (1867-1902)"; - var expected{{cookiecutter.domain_capitalized}} = {{cookiecutter.domain_capitalized}}.builder().code(code).description(description).build(); - Mockito.lenient() - .when(obtain{{cookiecutter.domain_capitalized}}.get{{cookiecutter.domain_capitalized}}ByCode(code)) - .thenReturn(Optional.of(expected{{cookiecutter.domain_capitalized}})); - // When - var request{{cookiecutter.domain_capitalized}} = new {{cookiecutter.domain_capitalized}}Domain(obtain{{cookiecutter.domain_capitalized}}); - var actual{{cookiecutter.domain_capitalized}} = request{{cookiecutter.domain_capitalized}}.get{{cookiecutter.domain_capitalized}}ByCode(code); - assertThat(actual{{cookiecutter.domain_capitalized}}).isNotNull().isEqualTo(expected{{cookiecutter.domain_capitalized}}); - } - - @Test - @DisplayName("should throw exception when asked for {{cookiecutter.domain}} by id that does not exists from stub") - public void getExceptionWhenAsked{{cookiecutter.domain_capitalized}}ByIdThatDoesNotExist(@Mock Obtain{{cookiecutter.domain_capitalized}} obtain{{cookiecutter.domain_capitalized}}) { - // Given - // Stub - var code = -1000L; - Mockito.lenient().when(obtain{{cookiecutter.domain_capitalized}}.get{{cookiecutter.domain_capitalized}}ByCode(code)).thenReturn(Optional.empty()); - // When - var request{{cookiecutter.domain_capitalized}} = new {{cookiecutter.domain_capitalized}}Domain(obtain{{cookiecutter.domain_capitalized}}); - // Then - assertThatThrownBy(() -> request{{cookiecutter.domain_capitalized}}.get{{cookiecutter.domain_capitalized}}ByCode(code)) - .isInstanceOf({{cookiecutter.domain_capitalized}}NotFoundException.class) - .hasMessageContaining("{{cookiecutter.domain_capitalized}} with code " + code + " does not exist"); - } -} diff --git a/{{cookiecutter.app_name}}/jpa-adapter/src/main/java/{{cookiecutter.package_name}}/repository/config/JpaAdapterConfig.java b/{{cookiecutter.app_name}}/jpa-adapter/src/main/java/{{cookiecutter.package_name}}/repository/config/JpaAdapterConfig.java deleted file mode 100644 index 4f172be..0000000 --- a/{{cookiecutter.app_name}}/jpa-adapter/src/main/java/{{cookiecutter.package_name}}/repository/config/JpaAdapterConfig.java +++ /dev/null @@ -1,23 +0,0 @@ -package {{cookiecutter.package_name}}.repository.config; - -import org.springframework.boot.autoconfigure.domain.EntityScan; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.data.envers.repository.support.EnversRevisionRepositoryFactoryBean; -import org.springframework.data.jpa.repository.config.EnableJpaRepositories; -import {{cookiecutter.package_name}}.domain.port.Obtain{{cookiecutter.domain_capitalized}}; -import {{cookiecutter.package_name}}.repository.{{cookiecutter.domain_capitalized}}Repository; -import {{cookiecutter.package_name}}.repository.dao.{{cookiecutter.domain_capitalized}}Dao; - -@Configuration -@EntityScan("{{cookiecutter.package_name}}.repository.entity") -@EnableJpaRepositories( - basePackages = "{{cookiecutter.package_name}}.repository.dao", - repositoryFactoryBeanClass = EnversRevisionRepositoryFactoryBean.class) -public class JpaAdapterConfig { - - @Bean - public Obtain{{cookiecutter.domain_capitalized}} get{{cookiecutter.domain_capitalized}}Repository({{cookiecutter.domain_capitalized}}Dao {{cookiecutter.domain}}Dao) { - return new {{cookiecutter.domain_capitalized}}Repository({{cookiecutter.domain}}Dao); - } -} diff --git a/{{cookiecutter.app_name}}/jpa-adapter/src/main/java/{{cookiecutter.package_name}}/repository/dao/{{cookiecutter.domain_capitalized}}Dao.java b/{{cookiecutter.app_name}}/jpa-adapter/src/main/java/{{cookiecutter.package_name}}/repository/dao/{{cookiecutter.domain_capitalized}}Dao.java deleted file mode 100644 index 5a71255..0000000 --- a/{{cookiecutter.app_name}}/jpa-adapter/src/main/java/{{cookiecutter.package_name}}/repository/dao/{{cookiecutter.domain_capitalized}}Dao.java +++ /dev/null @@ -1,14 +0,0 @@ -package {{cookiecutter.package_name}}.repository.dao; - -import java.util.Optional; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.repository.history.RevisionRepository; -import org.springframework.stereotype.Repository; -import {{cookiecutter.package_name}}.repository.entity.{{cookiecutter.domain_capitalized}}Entity; - -@Repository -public interface {{cookiecutter.domain_capitalized}}Dao - extends JpaRepository<{{cookiecutter.domain_capitalized}}Entity, Long>, RevisionRepository<{{cookiecutter.domain_capitalized}}Entity, Long, Long> { - - Optional<{{cookiecutter.domain_capitalized}}Entity> findByCode(Long code); -} diff --git a/{{cookiecutter.app_name}}/jpa-adapter/src/main/java/{{cookiecutter.package_name}}/repository/{{cookiecutter.domain_capitalized}}Repository.java b/{{cookiecutter.app_name}}/jpa-adapter/src/main/java/{{cookiecutter.package_name}}/repository/{{cookiecutter.domain_capitalized}}Repository.java deleted file mode 100644 index a9084cf..0000000 --- a/{{cookiecutter.app_name}}/jpa-adapter/src/main/java/{{cookiecutter.package_name}}/repository/{{cookiecutter.domain_capitalized}}Repository.java +++ /dev/null @@ -1,29 +0,0 @@ -package {{cookiecutter.package_name}}.repository; - -import java.util.List; -import java.util.Optional; -import java.util.stream.Collectors; -import {{cookiecutter.package_name}}.domain.model.{{cookiecutter.domain_capitalized}}; -import {{cookiecutter.package_name}}.domain.port.Obtain{{cookiecutter.domain_capitalized}}; -import {{cookiecutter.package_name}}.repository.dao.{{cookiecutter.domain_capitalized}}Dao; -import {{cookiecutter.package_name}}.repository.entity.{{cookiecutter.domain_capitalized}}Entity; - -public class {{cookiecutter.domain_capitalized}}Repository implements Obtain{{cookiecutter.domain_capitalized}} { - - private final {{cookiecutter.domain_capitalized}}Dao {{cookiecutter.domain}}Dao; - - public {{cookiecutter.domain_capitalized}}Repository({{cookiecutter.domain_capitalized}}Dao {{cookiecutter.domain}}Dao) { - this.{{cookiecutter.domain}}Dao = {{cookiecutter.domain}}Dao; - } - - @Override - public List<{{cookiecutter.domain_capitalized}}> getAll{{cookiecutter.domain_plural_capitalized}}() { - return {{cookiecutter.domain}}Dao.findAll().stream().map({{cookiecutter.domain_capitalized}}Entity::toModel).collect(Collectors.toList()); - } - - @Override - public Optional<{{cookiecutter.domain_capitalized}}> get{{cookiecutter.domain_capitalized}}ByCode(Long code) { - var {{cookiecutter.domain}}Entity = {{cookiecutter.domain}}Dao.findByCode(code); - return {{cookiecutter.domain}}Entity.map({{cookiecutter.domain_capitalized}}Entity::toModel); - } -} diff --git a/{{cookiecutter.app_name}}/jpa-adapter/src/test/java/{{cookiecutter.package_name}}/repository/{{cookiecutter.domain_capitalized}}JpaTest.java b/{{cookiecutter.app_name}}/jpa-adapter/src/test/java/{{cookiecutter.package_name}}/repository/{{cookiecutter.domain_capitalized}}JpaTest.java deleted file mode 100644 index 1104973..0000000 --- a/{{cookiecutter.app_name}}/jpa-adapter/src/test/java/{{cookiecutter.package_name}}/repository/{{cookiecutter.domain_capitalized}}JpaTest.java +++ /dev/null @@ -1,80 +0,0 @@ -package {{cookiecutter.package_name}}.repository; - -import static org.assertj.core.api.Assertions.assertThat; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; -import org.springframework.test.context.ActiveProfiles; -import org.springframework.test.context.jdbc.Sql; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import {{cookiecutter.package_name}}.domain.model.{{cookiecutter.domain_capitalized}}; -import {{cookiecutter.package_name}}.domain.port.Obtain{{cookiecutter.domain_capitalized}}; - -@ExtendWith(SpringExtension.class) -@DataJpaTest -@ActiveProfiles("test") -public class {{cookiecutter.domain_capitalized}}JpaTest { - - @Autowired private Obtain{{cookiecutter.domain_capitalized}} obtain{{cookiecutter.domain_capitalized}}; - - @Test - @DisplayName("should start the application") - public void startup() { - assertThat(Boolean.TRUE).isTrue(); - } - - @Sql(scripts = {"/sql/data.sql"}) - @Test - @DisplayName( - "given {{cookiecutter.domain_plural}} exist in database when asked should return all {{cookiecutter.domain_plural}} from database") - public void shouldGiveMe{{cookiecutter.domain_plural_capitalized}}WhenAskedGiven{{cookiecutter.domain_capitalized}}ExistsInDatabase() { - // Given from @Sql - // When - var {{cookiecutter.domain_plural}} = obtain{{cookiecutter.domain_capitalized}}.getAll{{cookiecutter.domain_plural_capitalized}}(); - // Then - assertThat({{cookiecutter.domain_plural}}) - .isNotNull() - .extracting("description") - .contains("Twinkle twinkle little star"); - } - - @Test - @DisplayName("given no {{cookiecutter.domain_plural}} exists in database when asked should return empty") - public void shouldGiveNo{{cookiecutter.domain_capitalized}}WhenAskedGiven{{cookiecutter.domain_plural_capitalized}}DoNotExistInDatabase() { - // When - var {{cookiecutter.domain_plural}} = obtain{{cookiecutter.domain_capitalized}}.getAll{{cookiecutter.domain_plural_capitalized}}(); - // Then - assertThat({{cookiecutter.domain_plural}}).isNotNull().isEmpty(); - } - - @Sql(scripts = {"/sql/data.sql"}) - @Test - @DisplayName( - "given {{cookiecutter.domain_plural}} exists in database when asked for {{cookiecutter.domain}} by id should return the {{cookiecutter.domain}}") - public void shouldGiveThe{{cookiecutter.domain_capitalized}}WhenAskedByIdGivenThat{{cookiecutter.domain_capitalized}}ByThatIdExistsInDatabase() { - // Given from @Sql - // When - var {{cookiecutter.domain}} = obtain{{cookiecutter.domain_capitalized}}.get{{cookiecutter.domain_capitalized}}ByCode(1L); - // Then - assertThat({{cookiecutter.domain}}) - .isNotNull() - .isNotEmpty() - .get() - .isEqualTo({{cookiecutter.domain_capitalized}}.builder().code(1L).description("Twinkle twinkle little star").build()); - } - - @Sql(scripts = {"/sql/data.sql"}) - @Test - @DisplayName( - "given {{cookiecutter.domain_plural}} exists in database when asked for {{cookiecutter.domain}} by id that does not exist should give empty") - public void shouldGiveNo{{cookiecutter.domain_capitalized}}WhenAskedByIdGivenThat{{cookiecutter.domain_capitalized}}ByThatIdDoesNotExistInDatabase() { - // Given from @Sql - // When - var {{cookiecutter.domain}} = obtain{{cookiecutter.domain_capitalized}}.get{{cookiecutter.domain_capitalized}}ByCode(-1000L); - // Then - assertThat({{cookiecutter.domain}}).isEmpty(); - } -} diff --git a/{{cookiecutter.app_name}}/jpa-adapter/src/test/resources/sql/data.sql b/{{cookiecutter.app_name}}/jpa-adapter/src/test/resources/sql/data.sql deleted file mode 100644 index 82645a2..0000000 --- a/{{cookiecutter.app_name}}/jpa-adapter/src/test/resources/sql/data.sql +++ /dev/null @@ -1,2 +0,0 @@ -INSERT INTO {{cookiecutter.domain_uppercase}}.T_{{cookiecutter.domain_uppercase}}(TECH_ID, CODE, DESCRIPTION) VALUES -(1000, 1, 'Twinkle twinkle little star'); \ No newline at end of file diff --git a/{{cookiecutter.app_name}}/rest-adapter/src/main/java/{{cookiecutter.package_name}}/rest/{{cookiecutter.domain_capitalized}}Resource.java b/{{cookiecutter.app_name}}/rest-adapter/src/main/java/{{cookiecutter.package_name}}/rest/{{cookiecutter.domain_capitalized}}Resource.java deleted file mode 100644 index 6bdd2f8..0000000 --- a/{{cookiecutter.app_name}}/rest-adapter/src/main/java/{{cookiecutter.package_name}}/rest/{{cookiecutter.domain_capitalized}}Resource.java +++ /dev/null @@ -1,27 +0,0 @@ -package {{cookiecutter.package_name}}.rest; - -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RestController; -import {{cookiecutter.package_name}}.domain.model.{{cookiecutter.domain_capitalized}}; -import {{cookiecutter.package_name}}.domain.port.Request{{cookiecutter.domain_capitalized}}; -import {{cookiecutter.package_name}}.rest.generated.api.{{cookiecutter.domain_capitalized}}Api; -import {{cookiecutter.package_name}}.rest.generated.model.{{cookiecutter.domain_capitalized}}Info; - -@RestController -public class {{cookiecutter.domain_capitalized}}Resource implements {{cookiecutter.domain_capitalized}}Api { - - private final Request{{cookiecutter.domain_capitalized}} request{{cookiecutter.domain_capitalized}}; - - public {{cookiecutter.domain_capitalized}}Resource(Request{{cookiecutter.domain_capitalized}} request{{cookiecutter.domain_capitalized}}) { - this.request{{cookiecutter.domain_capitalized}} = request{{cookiecutter.domain_capitalized}}; - } - - public ResponseEntity<{{cookiecutter.domain_capitalized}}Info> get{{cookiecutter.domain_plural_capitalized}}() { - return ResponseEntity.ok({{cookiecutter.domain_capitalized}}Info.builder().{{cookiecutter.domain_plural}}(request{{cookiecutter.domain_capitalized}}.get{{cookiecutter.domain_plural_capitalized}}()).build()); - } - - public ResponseEntity<{{cookiecutter.domain_capitalized}}> get{{cookiecutter.domain_capitalized}}ByCode(@PathVariable("code") Long code) { - return ResponseEntity.ok(request{{cookiecutter.domain_capitalized}}.get{{cookiecutter.domain_capitalized}}ByCode(code)); - } -} diff --git a/{{cookiecutter.app_name}}/rest-adapter/src/test/java/{{cookiecutter.package_name}}/rest/{{cookiecutter.domain_capitalized}}RestAdapterApplication.java b/{{cookiecutter.app_name}}/rest-adapter/src/test/java/{{cookiecutter.package_name}}/rest/{{cookiecutter.domain_capitalized}}RestAdapterApplication.java deleted file mode 100644 index 5735ff2..0000000 --- a/{{cookiecutter.app_name}}/rest-adapter/src/test/java/{{cookiecutter.package_name}}/rest/{{cookiecutter.domain_capitalized}}RestAdapterApplication.java +++ /dev/null @@ -1,14 +0,0 @@ -package {{cookiecutter.package_name}}.rest; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.context.annotation.ComponentScan; - -@SpringBootApplication -@ComponentScan(basePackages = "{{cookiecutter.package_name}}") -public class {{cookiecutter.domain_capitalized}}RestAdapterApplication { - - public static void main(String[] args) { - SpringApplication.run({{cookiecutter.domain_capitalized}}RestAdapterApplication.class, args); - } -}