Introduction
CircleCI Orbs are reusable packages of configuration that help automate repeated processes, speed up project setup, and enforce best practices. For Java projects, orbs can streamline CI/CD pipelines with pre-configured jobs for testing, building, and deploying Java applications.
Core Java Orbs
1. Official CircleCI Java Orb
# .circleci/config.yml version: 2.1 orbs: java: circleci/[email protected] maven: circleci/[email protected] gradle: circleci/[email protected] workflows: java-test-workflow: jobs: - java/test: version: '21' test-task: test
2. Custom Java Orb Structure
# orbs/java-orb.yml version: 2.1 description: "Custom Java CI/CD Orb" commands: setup-java: description: "Setup Java environment with caching" parameters: java-version: type: string default: "21" distribution: type: string default: "temurin" steps: - checkout - java/install-jdk: version: << parameters.java-version >> distribution: << parameters.distribution >> - restore_cache: keys: - v1-dependencies-{{ checksum "pom.xml" }}-{{ checksum "build.gradle" }} - v1-dependencies- run-tests: description: "Run tests with coverage" parameters: test-task: type: string default: "test" coverage-tool: type: string default: "jacoco" steps: - run: name: Run Tests command: | if [ -f "pom.xml" ]; then ./mvnw << parameters.test-task >> elif [ -f "build.gradle" ]; then ./gradlew << parameters.test-task >> fi - run: name: Generate Coverage Report command: | if [ "<< parameters.coverage-tool >>" == "jacoco" ]; then if [ -f "pom.xml" ]; then ./mvnw jacoco:report elif [ -f "build.gradle" ]; then ./gradlew jacocoTestReport fi fi jobs: test: docker: - image: cimg/openjdk:21.0-node resource_class: medium steps: - setup-java - run-tests - store_test_results: path: target/surefire-reports - store_artifacts: path: target/site/jacoco build: docker: - image: cimg/openjdk:21.0-node resource_class: medium steps: - setup-java - run: name: Build Artifact command: | if [ -f "pom.xml" ]; then ./mvnw clean package -DskipTests elif [ -f "build.gradle" ]; then ./gradlew clean build -x test fi - store_artifacts: path: target/*.jar destination: build-artifacts security-scan: docker: - image: cimg/openjdk:21.0-node steps: - setup-java - run: name: Dependency Vulnerability Scan command: | if [ -f "pom.xml" ]; then ./mvnw org.owasp:dependency-check-maven:check elif [ -f "build.gradle" ]; then ./gradlew dependencyCheckAnalyze fi - store_artifacts: path: target/dependency-check-report.html Complete Java CI/CD Pipeline
1. Maven Project Configuration
# .circleci/config.yml version: 2.1 orbs: java: circleci/[email protected] maven: circleci/[email protected] sonarcloud: sonarcloud/[email protected] slack: circleci/[email protected] aws-cli: circleci/[email protected] workflows: java-maven-pipeline: jobs: - java/test: name: test-java-21 version: '21' test-task: 'test' post-steps: - store_test_results: path: target/surefire-reports - store_artifacts: path: target/site/jacoco - sonarcloud/scan: name: code-analysis context: sonarcloud requires: - test-java-21 - security-scan: name: security-scan requires: - test-java-21 - build-artifact: name: build-artifact requires: - test-java-21 - code-analysis - security-scan filters: branches: only: main - deploy-staging: name: deploy-staging requires: - build-artifact filters: branches: only: main - integration-tests: name: integration-tests requires: - deploy-staging filters: branches: only: main - deploy-production: name: deploy-production requires: - integration-tests filters: branches: only: main context: aws-production jobs: security-scan: executor: java/java21 steps: - checkout - java/install-dependencies - run: name: OWASP Dependency Check command: | ./mvnw org.owasp:dependency-check-maven:check -s settings.xml - store_artifacts: path: target/dependency-check-report.html build-artifact: executor: java/java21 steps: - checkout - java/install-dependencies - run: name: Build JAR command: ./mvnw clean package -DskipTests - persist_to_workspace: root: target paths: - *.jar deploy-staging: docker: - image: cimg/aws:2023.12 steps: - attach_workspace: at: target - aws-cli/setup: role-arn: arn:aws:iam::123456789:role/CircleCI-Staging role-session-name: circleci-staging aws-region: us-east-1 - run: name: Deploy to Staging command: | aws s3 cp target/*.jar s3://my-app-staging/artifacts/ aws ecs update-service --cluster my-app-staging --service api-service --force-new-deployment integration-tests: executor: java/java21 steps: - checkout - run: name: Run Integration Tests command: | ./mvnw verify -Pintegration-tests environment: API_BASE_URL: https://staging.myapp.com - store_test_results: path: target/failsafe-reports deploy-production: docker: - image: cimg/aws:2023.12 steps: - attach_workspace: at: target - aws-cli/setup: role-arn: arn:aws:iam::123456789:role/CircleCI-Production role-session-name: circleci-production aws-region: us-east-1 - run: name: Deploy to Production command: | aws s3 cp target/*.jar s3://my-app-production/artifacts/ aws ecs update-service --cluster my-app-production --service api-service --force-new-deployment - slack/notify: event: pass template: basic_success_1 channel: deployments
2. Gradle Project Configuration
# .circleci/config.yml version: 2.1 orbs: java: circleci/[email protected] gradle: circleci/[email protected] codecov: codecov/[email protected] workflows: java-gradle-pipeline: jobs: - test-with-gradle - code-analysis - build-and-scan - deploy jobs: test-with-gradle: executor: gradle/default steps: - checkout - gradle/load-cache - gradle/run-tests: test-command: test test-result-paths: '**/build/test-results/test/*.xml' - gradle/save-cache - store_test_results: path: build/test-results/test - store_artifacts: path: build/reports/tests/test code-analysis: executor: gradle/default steps: - checkout - gradle/load-cache - run: name: Code Quality Checks command: | ./gradlew checkstyleMain checkstyleTest pmdMain pmdTest - store_artifacts: path: build/reports/checkstyle - store_artifacts: path: build/reports/pmd build-and-scan: executor: gradle/default steps: - checkout - gradle/load-cache - run: name: Build and Security Scan command: | ./gradlew build -x test ./gradlew dependencyCheckAnalyze - store_artifacts: path: build/libs - store_artifacts: path: build/reports/dependency-check deploy: executor: gradle/default steps: - checkout - gradle/load-cache - run: name: Build Distribution command: ./gradlew assembleDist - run: name: Upload to Repository command: | ./gradlew publish
Advanced Java Orb Features
1. Multi-Module Maven Project Orb
# orbs/multi-module-java.yml version: 2.1 commands: setup-multi-module: description: "Setup for multi-module Maven projects" parameters: java-version: type: string default: "21" modules: type: string default: "*" steps: - checkout - java/install-jdk: version: << parameters.java-version >> - restore_cache: keys: - maven-multi-module-{{ checksum "pom.xml" }}-{{ checksum "**/pom.xml" }} - maven-multi-module- build-modules: description: "Build specific modules" parameters: modules: type: string default: "" profiles: type: string default: "" steps: - run: name: Build Modules command: | if [ -n "<< parameters.modules >>" ]; then MODULE_FLAG="-pl << parameters.modules >>" fi if [ -n "<< parameters.profiles >>" ]; then PROFILE_FLAG="-P << parameters.profiles >>" fi ./mvnw clean install $MODULE_FLAG $PROFILE_FLAG test-modules-parallel: description: "Run tests in parallel across modules" parameters: parallel-threads: type: integer default: 4 steps: - run: name: Parallel Tests command: | ./mvnw test -T << parameters.parallel-threads >> jobs: multi-module-test: docker: - image: cimg/openjdk:21.0 resource_class: large parallelism: 4 steps: - setup-multi-module - test-modules-parallel - store_test_results: path: */target/surefire-reports build-docker-images: docker: - image: cimg/openjdk:21.0 steps: - setup-multi-module - build-modules - run: name: Build Docker Images command: | ./mvnw spring-boot:build-image -DskipTests - run: name: Scan Docker Images command: | for module in */; do if [ -f "$module/pom.xml" ]; then IMAGE_NAME=$(basename $module) docker scan $IMAGE_NAME:latest fi done 2. Spring Boot Specific Orb
# orbs/spring-boot-orb.yml version: 2.1 commands: setup-spring-boot: description: "Setup Spring Boot specific environment" parameters: spring-boot-version: type: string default: "3.2.0" java-version: type: string default: "21" steps: - setup-java: java-version: << parameters.java-version >> - run: name: Validate Spring Boot Version command: | if [ -f "pom.xml" ]; then SPRING_VERSION=$(mvn help:evaluate -Dexpression=spring-boot.version -q -DforceStdout) echo "Using Spring Boot version: $SPRING_VERSION" fi spring-boot-test: description: "Run Spring Boot specific tests" parameters: test-profile: type: string default: "test" steps: - run: name: Run Spring Tests command: | if [ -f "pom.xml" ]; then ./mvnw test -P<< parameters.test-profile >> -Dspring.profiles.active=test else ./gradlew test -Pspring.profiles.active=test fi - run: name: Test Containers Cleanup command: | docker system prune -f build-spring-native: description: "Build Spring Native image" steps: - run: name: Build Native Image command: | if [ -f "pom.xml" ]; then ./mvnw spring-boot:build-image -Dspring-boot.build-image.imageName=myapp:native else ./gradlew bootBuildImage --imageName=myapp:native fi - store_artifacts: path: build/*.jar jobs: spring-boot-build: docker: - image: cimg/openjdk:21.0 steps: - checkout - setup-spring-boot - spring-boot-test - build-spring-native database-migration: docker: - image: cimg/openjdk:21.0 - image: cimg/postgres:15.0 environment: POSTGRES_USER: test POSTGRES_PASSWORD: test POSTGRES_DB: testdb steps: - checkout - setup-spring-boot - run: name: Run Database Migrations command: | ./mvnw flyway:migrate -Dflyway.url=jdbc:postgresql://localhost:5432/testdb environment: SPRING_PROFILES_ACTIVE: test api-docs: docker: - image: cimg/openjdk:21.0 steps: - checkout - setup-spring-boot - run: name: Generate API Documentation command: | ./mvnw spring-restdocs:asciidoc-generate - store_artifacts: path: target/generated-docs
Security and Compliance Orb
# orbs/security-compliance.yml version: 2.1 commands: license-check: description: "Check license compliance" steps: - run: name: License Compliance Check command: | if [ -f "pom.xml" ]; then ./mvnw org.codehaus.mojo:license-maven-plugin:download-licenses ./mvnw org.codehaus.mojo:license-maven-plugin:check-licenses elif [ -f "build.gradle" ]; then ./gradlew checkLicense fi sbom-generate: description: "Generate Software Bill of Materials" steps: - run: name: Generate SBOM command: | if [ -f "pom.xml" ]; then ./mvnw org.cyclonedx:cyclonedx-maven-plugin:makeAggregateBom elif [ -f "build.gradle" ]; then ./gradlew cyclonedxBom fi - store_artifacts: path: target/bom.xml security-scan: description: "Comprehensive security scanning" steps: - run: name: SAST Scan command: | if [ -f "pom.xml" ]; then ./mvnw org.sonarsource.scanner.maven:sonar-maven-plugin:sonar fi - run: name: Secret Scanning command: | git secrets --scan jobs: security-compliance: docker: - image: cimg/openjdk:21.0 steps: - checkout - setup-java - license-check - sbom-generate - security-scan
Monitoring and Notifications
1. Pipeline Notifications Orb
# orbs/notifications.yml version: 2.1 commands: notify-start: description: "Notify pipeline start" parameters: pipeline-url: type: string steps: - slack/notify: event: start template: basic_success_1 channel: builds custom: | { "attachments": [ { "title": "Build Started", "text": "Pipeline *${CIRCLE_WORKFLOW_ID}* started", "color": "#3498db" } ] } notify-success: description: "Notify pipeline success" steps: - slack/notify: event: success template: basic_success_1 channel: builds notify-failure: description: "Notify pipeline failure" steps: - slack/notify: event: fail template: basic_fail_1 channel: builds-alerts jobs: performance-metrics: docker: - image: cimg/openjdk:21.0 steps: - checkout - run: name: Collect Build Metrics command: | echo "Build time: $CIRCLE_BUILD_TIME seconds" echo "Test count: $(find . -name "TEST-*.xml" | wc -l)" when: always - store_metrics: path: metrics.xml Best Practices Configuration
1. Java Project Template
# .circleci/config.yml version: 2.1 orbs: java-ci: your-namespace/[email protected] security: your-namespace/[email protected] notifications: your-namespace/[email protected] workflows: standard-java-pipeline: jobs: - java-ci/validate-environment - java-ci/run-unit-tests: requires: - validate-environment - security/dependency-scan: requires: - validate-environment - security/code-analysis: requires: - run-unit-tests - java-ci/build-artifact: requires: - run-unit-tests - dependency-scan - java-ci/integration-tests: requires: - build-artifact - java-ci/deploy-staging: requires: - integration-tests filters: branches: only: main - notifications/send-summary: requires: - deploy-staging filters: branches: only: main
Conclusion
CircleCI Orbs for Java projects provide powerful, reusable configuration components that can significantly streamline your CI/CD pipelines. By leveraging these orbs, teams can:
- Standardize builds across multiple Java projects
- Enforce security practices with automated scanning
- Accelerate setup with pre-configured jobs and commands
- Maintain consistency across development teams
- Scale efficiently as projects grow in complexity
The key to successful orb usage is starting with official orbs, creating custom orbs for organization-specific needs, and continuously refining based on team feedback and evolving requirements.