-
Generates a working application of these types:
-
Spring WebMvc
-
Spring WebFlux
-
For WebFlux and WebMvc, a project with a single controller will have about 600 lines of code and about 80 tests generated
-
-
Spring Boot
-
Spring Batch
-
-
Generates unit and integration tests that currently provide 100% code coverage
-
Assigns resource objects unique identifiers that have 160-bit entropy, the highest amount recommended by OAuth2 (160 bits is approximately 1.46 x 1048 possible values).
-
Supported Integrations:
-
Postges
-
TestContainers
-
Liquibase
-
With Postgres integration, the JPA properties within application.properties
reference Postgres JDBC drivers. With TestContainers integration, the test cases use TestContainers to emulate the database. When both Postgres and TestContainers are used, the tests use the Postgres flavor of the test container. With Liquibase, a simple configuration is generated as a starting point.
Metacode is available on Homebrew. To install it, run these commands:
$ brew tap staycaffeinated/tap
$ brew install metacode
The Metacode CLI requires Java 17 to run. The generated code supports Java 11 and higher.
To get a general idea of the metacode
command usage, type:
metacode --help
You will always start with the create project
subcommand, which lays down the base code and
Gradle artifacts of the project. The create project
subcommand writes files in your current directory,
so always be sure to create your new project’s working directory, navigate into that directory,
then run the create project
subcommand. For example:
$ mkdir customer-importer
$ cd customer-importer
$ metacode create project spring-batch -n customer-importer -p acme.customer.batch --base-path /customer-importer
$ gradle wrapper
$ ./gradlew build
To demonstrate how to generate a project with MetaCode, we’ll walk through generating Spring’s Pet Store example, with three endpoints: pets, owners, and stores.
We’ll start with Spring WebFlux, which uses asynchronous communication, with Mono and Flux streams.
metacode
command.
$ mkdir petstore-webflux
$ cd petstore-webflux
$ metacode create project spring-webflux --name petstore --package acme.petstore --base-path /petstore
$ metacode create endpoint --resource Pet --route /pets
$ gradle wrapper
$ ./gradlew build
$ metacode create endpoint --resource Store --route /stores
$ metacode create endpoint --resource Owner --route /owners
$ ./gradlew build
$ ./gradlew bootRun
Try these URLs in your browser to see what happens
$ http localhost:8080/petstore/pets/findAll
$ http localhost:8080/petstore/stores/findAll
$ http localhost:8080/petstore/owners/findAll
$ http localhost:8080/petstore/pets
$ http localhost:8080/petstore/pets/[resourceId]
$ http localhost:8080/petstore/_internal/health
$ http localhost:8080/petstore/_internal/health/liveness
# Try a resource ID that does not exist
$ http localhost:8080/petstore/pets/55555
# Attempt a JavaScript injection
$ http http "localhost:8080/petstore/pets/'<alert>hello</alert>'"
This example shows using Spring WebMvc, which uses synchronous communication.
$ mkdir petstore-webmvc
$ cd petstore-webmvc
$ metacode create project spring-webmvc --name petstore --package acme.petstore --base-path /petstore
$ metacode create endpoint --resource Pet --route /pets
$ gradle wrapper
$ ./gradlew build
$ metacode create endpoint --resource Store --route /stores
$ metacode create endpoint --resource Owner --route /owners
$ ./gradlew build
$ ./gradlew bootRun
Try these URLs in your browser to see what happens
$ http localhost:8080/petstore/pets/findAll
$ http localhost:8080/petstore/stores/findAll
$ http localhost:8080/petstore/owners/findAll
$ http localhost:8080/petstore/pets
$ http localhost:8080/petstore/pets/[resourceId]
$ http localhost:8080/petstore/_internal/health
$ http localhost:8080/petstore/_internal/health/liveness
# Because the question mark has a special meaning in bash and zsh,
# use quotes around the URL string, as done here.
# (See: https://scriptingosx.com/2017/08/special-characters/ )
$ http "localhost:8080/petstore/search?text=Five"
When you only want the bare minimum of code generated, the spring-boot
template is available.
The spring-boot
template generates an Application.java
, some helper classes, and an
ApplicationTests.java
.
To create such a project, following this recipe:
$ mkdir basic-springboot
$ cd basic-springboot
$ metacode create project spring-boot --name hello-world --package acme.greeting --base-path /greeting
The spring-batch
subcommand creates a simple Spring Batch application. Mainly, the Application.java
class, an example JobCompletionNotificationListener.java and a very basic BatchConfiguration.java class.
From there, the developer has to build out the rest of the application. The BatchConfiguration class
does include comments with suggested next steps for those new to Spring Batch applications.
To create such a Spring Batch project, following this recipe:
$ mkdir basic-springbatch
$ cd basic-springbatch
$ metacode create project spring-batch --name batch-example --package acme.example.batch --base-path /batch-example
If compile errors are encounted after generating endpoint assets, the most likely cause is name collisions. For example, if you do this:
$ metacode create endpoint --resource Controller --route /controller
You will get compile errors because the compile will encounter your Controller class and the org.springframework.stereotype.Controller class. Likewise, if you do
$ metacode create endpoint --resource Test --route /test
You will get compile errors because the compiler will encounter your Test class and the org.junit.jupiter.api.Test class.
The code generator could address this by using fully-qualified class names for all generated classes, but that feels to onerous; the generated code would have this style:
acme.petstore.database.pet.Pet getPet ( String petId );
and
void savePet (acme.petstore.database.pet.Pet pet) { ... }
which works, but becomes tedious to read. The more reasonable solution is to be aware of this behavior and be prepared to open your IDE to resolve these.