[CookieCutter] Get Java package latest version

There are several ways to create project. It can be done by IDE default wizard or generate via spring initializer. Even these are convenient to us to setup project, but for organization it might has some custom libraries and organization-specific settings (e.g. private repositories, etc)

In this article, we will show how to create a project to support both Maven and Gradle.

This demo will use folder named java-project-template as example.

Prerequisites

  1. Python and cookiecutter should be installed properly.
    // Install Python
    sudo apt install -y python
    
    // Install CookieCutter
    pip install cookiecutter

Steps

  1. Create CookieCutter project structure.
    In command prompt, execute command below:

    mkdir {{cookiecutter.__projectFolder}}
    mkdir hooks
  2. Create cookiecutter.json
    In the same folder, create file named cookiecutter.json and input content as below:

    {
      "javaVersion": ["17", "19", "11", "1.8"],
      "projectType": ["gradle", "maven"],
      "group": "io.github",
      "artifact": "demo-library",
      "version": "1.0.0-SNAPSHOT",
      "__projectName": "{{cookiecutter.group}}.{{cookiecutter.artifact}}",
      "__projectFolder" : "{{cookiecutter.artifact}}",
      "__projectPackageRoot" : "{{cookiecutter.group.lower()}}.{{cookiecutter.artifact.lower().replace('-','.') }}",
    }

    Remind that property __projectFolder should be same as the folder name in step 1, otherwise it cannot be render.

  3. Create project template structure.
    In command prompt, execute command below:

    cd {{cookiecutter.__projectFolder}}
    mkdir gradle
    mkdir src/main
    mkdir src/test
  4. Create maven related file.
    In folder {{cookiecutter.__projectFolder}} , create file named pom.xml and input content below:

    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
      <modelVersion>4.0.0</modelVersion>
    
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.3.1.RELEASE</version>
            <relativePath/> <!-- lookup parent from repository -->
        </parent>
    
        <groupId>{{cookiecutter.group}}</groupId>
        <artifactId>{{cookiecutter.artifact}}</artifactId>
        <version>{{cookiecutter.version}}</version>
        <name>{{cookiecutter.__projectName}}</name>
    
        <properties>
            <maven.compiler.source>{{cookiecutter.javaVersion}}</maven.compiler.source>
            <maven.compiler.target>{{cookiecutter.javaVersion}}</maven.compiler.target>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
            <junit-version>latest</junit-version>
            <mockito.version>latest</mockito.version>
        </properties>
    
        <dependencies>
            <!-- https://mvnrepository.com/artifact/org.junit/junit-bom -->
            <dependency>
                <groupId>org.junit</groupId>
                <artifactId>junit-bom</artifactId>
                <version>${junit-version}</version>
                <type>pom</type>
            </dependency>
            <dependency>
                <groupId>org.mockito</groupId>
                <artifactId>mockito-junit-jupiter</artifactId>
                <version>${mockito.version}</version>
                <scope>test</scope>
            </dependency>
            <dependency>
                <groupId>org.mockito</groupId>
                <artifactId>mockito-inline</artifactId>
                <version>${mockito.version}</version>
                <scope>test</scope>
            </dependency>
        </dependencies>
    
        <build>
            <pluginManagement>
                <plugins>
                    <plugin>
                        <groupId>org.apache.maven.plugins</groupId>
                        <artifactId>maven-compiler-plugin</artifactId>
                        <version>3.8.1</version>
                    </plugin>
                    <plugin>
                        <groupId>org.apache.maven.plugins</groupId>
                        <artifactId>maven-javadoc-plugin</artifactId>
                        <version>3.5.0</version>
                        <configuration>
                            <reportOutputDirectory>docs</reportOutputDirectory>
                            <destDir>docs</destDir>
                        </configuration>
                    </plugin>
                    <plugin>
                        <groupId>org.jacoco</groupId>
                        <artifactId>jacoco-maven-plugin</artifactId>
                        <version>0.8.9</version>
                        <configuration>
                            <excludes>
                                <exclude>docs/**</exclude>
                            </excludes>
                        </configuration>
                    <executions>
                        <execution>
                            <id>prepare-agent</id>
                            <goals>
                                <goal>prepare-agent</goal>
                            </goals>
                        </execution>
                        <execution>
                            <id>report</id>
                            <phase>test</phase>
                            <goals>
                                <goal>report</goal>
                            </goals>
                        </execution>
                    </executions>
                </plugin>
                <plugin>
                        <groupId>org.owasp</groupId>
                        <artifactId>dependency-check-maven</artifactId>
                        <version>8.2.1</version>
                        <executions>
                            <execution>
                                <goals>
                                    <goal>check</goal>
                                </goals>
                            </execution>
                        </executions>
                        <configuration>
                            <name>Dependency Check Report</name>
                            <formats>
                                <format>HTML</format>
                                <format>JSON</format>
                            </formats>
                        </configuration>
                    </plugin>
                <plugin>
                    <groupId>org.sonarsource.scanner.maven</groupId>
                    <artifactId>sonar-maven-plugin</artifactId>
                    <version>3.9.1.2184</version>
                </plugin>
    
                </plugins>
            </pluginManagement>
        </build>
    </project>
  5. Create Gradle related file.
    In folder {{cookiecutter.__projectFolder}} , create file named pom.xml and input content below:

    plugins {
        id("java")
        id("org.owasp.dependencycheck") version "8.2.1"
    }
    
    group = "{{cookiecutter.group}}.{{cookiecutter.artifact}}"
    version = "{{cookiecutter.version}}"
    
    repositories {
        mavenCentral()
    }
    
    dependencies {
        testImplementation(platform("org.junit:junit-bom:5.1.0"))
        testImplementation("org.junit.jupiter:junit-jupiter")
    }
    
    tasks.test {
        useJUnitPlatform()
    }
    
    tasks.withType<Javadoc> {
        val javaSrcDir = project.file("src/main/java")
        source = project.files(javaSrcDir).asFileTree
        classpath += project.files(sourceSets["main"].output)
        destinationDir = project.file("docs/javadoc")
    }
  6. Create post render script.
    In folder hook, create file named post_gen_project.py and input as below:

    import os;
    
    def init_directories():
        print("Initialize main program.")
        mainRootDirectory = "src/main/java/"+"{{cookiecutter.__projectPackageRoot}}".lower().replace(".", "/")
        os.makedirs(mainRootDirectory)
        os.rename("src/main/package-info.java", mainRootDirectory+"/package-info.java")
        os.rename("src/main/Main.java", mainRootDirectory+"/Main.java")
    
        print("Initialize test program.")
        testRootDirectory = "src/test/java/"+"{{cookiecutter.__projectPackageRoot}}".lower().replace(".", "/")
        os.makedirs(testRootDirectory)
        os.rename("src/test/package-info.java", testRootDirectory+"/package-info.java")
        os.rename("src/test/MainTest.java", testRootDirectory+"/MainTest.java")
    
        print("Clean up project.")
        match "{{cookiecutter.projectType}}":
            case "gradle":
                cleanup_maven()
            case "maven":
                cleanup_gradle()
            
    def cleanup_maven():
        os.remove("pom.xml")
        os.remove(".github/workflows/CI-Maven.yaml")
    
    def cleanup_gradle():
        os.rmdir("gradle")
        os.remove("build.gradle.kts")
        os.remove("gradlew")  
        os.remove("gradlew.bat")  
        os.remove("settings.gradle.kts")
        os.remove(".github/workflows/CI-Gradle.yaml")
    
    def main():
        init_directories()
    
    if __name__ == "__main__":
        main()

    Method init_directories() is used to create package structure with package name provided; And it will clean up unused files.

  7. Test.
    In command prompt, execute command below, exepect project will be render.

    cookiecutter java-project-template

Sample project has been store in GitHub repository.

About C.H. Ling 262 Articles
a .net / Java developer from Hong Kong and currently located in United Kingdom. Thanks for Google because it solve many technical problems so I build this blog as return. Besides coding and trying advance technology, hiking and traveling is other favorite to me, so I will write down something what I see and what I feel during it. Happy reading!!!

Be the first to comment

Leave a Reply

Your email address will not be published.


*


This site uses Akismet to reduce spam. Learn how your comment data is processed.