Static Analysis
Why Use Static Analysis?
Static analysis tools are an integral part of the Self-Managed Commerce development process, providing automated code quality checks that help maintain high standards across our codebase. While we use these tools to ensure consistency and quality in our core product, we understand that your needs might differ.
Benefits for Your Development
- Early Bug Detection: Catch potential issues during development, reducing debugging time.
- Code Quality: Maintain consistent style and reduce technical debt across your team.
- Best Practices: Benefit from established Java development patterns and standards.
Your Choice
These tools are configured to run during the build process, but they are not mandatory for your customizations. You can:
- Use them as-is to maintain consistency with our development standards.
- Customize the rules to better fit your team's workflow.
- Disable specific checks that don't align with your requirements.
Static Analysis in Self-Managed Commerce Builds
When running a build using Maven, the Self-Managed Commerce builds perform multiple static analysis checks. The static analysis checks are run for each module after the Surefire and Failsafe tests are executed, and if any failures are found, the build will fail.
For details on how to configure the builds to skip or run static analysis checks, see Building Source Code.
The Maven plugins used to run static analysis checks in Self-Managed Commerce builds are shown below:
Checkstyle
Plugin: org.apache.maven.plugins:maven-checkstyle-plugin
This plugin identifies common formatting and style issues that violate standard Java coding best practices.
- Improve Readability: Consistent formatting makes code easier to read and understand.
- Reduce Review Time: Automated style checking lets reviewers focus on logic rather than formatting.
- Prevent Common Mistakes: Catches problematic patterns like unused imports or missing Javadoc.
- Ease Onboarding: New team members can understand the codebase faster with consistent style.
Sample failure:
[INFO] --- checkstyle:2.17:check (compliance-checkstyle) @ ep-core ---
[WARNING] src/main/java/com/elasticpath/service/store/StoreService.java:[10,8] (imports) UnusedImports: Unused import - java.util.UUID.
Errors can be suppressed using the @SuppressWarnings
annotation as in the following example:
@SuppressWarnings("UnusedImports")
PMD
Plugin: org.apache.maven.plugins:maven-pmd-plugin
This plugin identifies more complex issues that violate standard Java and Self-Managed Commerce coding best practices.
- Bug Prevention: Catches common programming mistakes and security vulnerabilities.
- Code Quality: Identifies performance issues and problematic patterns.
- Architecture: Enforces project-specific design decisions and best practices.
Sample failure:
[INFO] --- pmd:3.5:check (compliance-pmd) @ ep-core ---
[INFO] PMD Failure: com.elasticpath.domain.rules.Rule:97 Rule:BooleanGetMethodName Priority:4 A getX() method which returns a boolean should be named isX().
Errors can be suppressed using the @SuppressWarnings
annotation as in the following example:
@SuppressWarnings("PMD.BooleanGetMethodName")
Jacoco
Plugin: org.jacoco:jacoco-maven-plugin
This plugin identifies when unit test coverage is less than the thresholds specified in the plugin configuration. This may indicate that new code does not have sufficient test coverage.
- Quality Assurance: Ensures new code meets minimum test coverage standards.
- Risk Management: Identifies untested code that might be more prone to bugs.
- Safe Refactoring: Provides confidence when making changes to existing code.
Sample failure:
[INFO] --- jacoco:0.8.10:check (default-check) @ ep-core ---
[ERROR] Failed to execute goal org.jacoco:jacoco-maven-plugin:0.8.10:check
(jacoco-check) on project ep-core: Coverage checks have not been met.
Enforcer
Plugin: org.apache.maven.plugins:maven-enforcer-plugin
This plugin identifies many issues with Maven and environment configuration.
- Consistent Environments: Ensures all developers use compatible tool versions.
- Dependency Management: Prevents conflicts and version mismatches.
- Build Reliability: Makes builds more reproducible across different environments.
The specific checks are shown in the sections below:
Enforce Java and Maven Versions
Checks to ensure that the correct minimum Java and Maven versions are being used for the build.
- Consistency: Prevents "works on my machine" issues with standardized environments.
- Security & Support: Ensures use of secure, supported versions with important patches.
- Performance: Takes advantage of improvements in newer versions.
Sample failure:
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-enforcer-plugin:3.5.0:enforce (enforce-maven-version) on project ep-core:
[ERROR] Rule 0: org.apache.maven.enforcer.rules.version.RequireJavaVersion failed with message:
[ERROR] Detected JDK version 1.8.0-382 (JAVA_HOME=/Library/Java/JavaVirtualMachines/zulu-8.jdk/Contents/Home/jre) is not in the allowed range [17,).
Enforce Banned Dependencies
Checks to ensure that no banned dependencies or plugins are present in the project. Usually dependencies are banned because they conflict with other existing dependencies. For example, jakarta.el:jakarta.el-api
is banned because it contains classes that conflict with org.glassfish:jakarta.el
.
- Stability: Blocks dependencies that cause classpath conflicts or have known issues.
- Security & Compliance: Prohibits vulnerable or non-compliant dependencies.
- Architecture: Enforces technology choices and prevents technical debt.
Sample failure:
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-enforcer-plugin:3.5.0:enforce (enforce-banned-dependencies) on project payment-provider-api:
[ERROR] Rule 0: org.apache.maven.enforcer.rules.dependency.BannedDependencies failed with message:
[ERROR] com.elasticpath:payment-provider-api:jar:0.0.0-SNAPSHOT
[ERROR] org.osgi:osgi.core:jar:6.0.0 <--- banned via the exclude/include list
Enforce Plugin Versions
Checks to ensure that all plugins are declared with a specific version.
- Consistent Builds: Makes builds reproducible across environments.
- Reliability: Prevents issues from unexpected plugin updates.
- Security: Mitigates supply chain risks through version pinning.
Sample failure:
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-enforcer-plugin:3.5.0:enforce (enforce-plugin-versions) on project parent:
[ERROR] Rule 0: org.apache.maven.enforcer.rules.RequirePluginVersions failed with message:
[ERROR] Some plugins are missing valid versions or depend on Maven 3.9.1 defaults (LATEST, RELEASE, SNAPSHOT, TIMESTAMP SNAPSHOT as plugin version are not allowed)
[ERROR] org.jacoco:jacoco-maven-plugin. The version currently in use is 0.8.13 via super POM or default lifecycle bindings
[ERROR] All plugins must be pinned to an explicit version
Enforce POM/BOM Sync
Checks to ensure that any properties defined in the root pom.xml
have the same value in the bill of materials bill-of-materials/pom.xml
.
- Version Consistency: Ensures all modules use compatible dependency versions.
- Simplified Maintenance: Makes dependency updates more straightforward.
- Build Efficiency: Reduces redundant dependency downloads and potential conflicts.
Sample failure:
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-enforcer-plugin:3.5.0:enforce (pombom-sync-enforcer) on project commerce-parent:
[ERROR] Rule 0: com.elasticpath.tools.maven.PomBomPropertySyncEnforcer(pombom-property-sync-enforcer) failed with message:
[ERROR] Total 1 Mismatched version number property values detected:
[ERROR] Property: api-platform.version
[ERROR] com.elasticpath:commerce-parent '1.52.0.fadb60876f'
[ERROR] com.elasticpath:bill-of-materials '1.53.0.fadb60876f'
Enforce Upper-Bound Dependencies
Checks that the version for each dependency resolved during a build is equal to or higher than all transitive dependency declarations. This means that if a dependency is declared with a version that is lower than the version required by a transitive dependency, the build will fail.
- Reliability: Ensures compatible dependency versions are used.
- Security: Helps avoid vulnerabilities in outdated dependencies.
- Maintainability: Reduces classpath issues and makes conflicts easier to resolve.
Sample failure:
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-enforcer-plugin:3.5.0:enforce (enforce-upper-bound-deps) on project ep-test-support:
[ERROR] Rule 0: org.apache.maven.enforcer.rules.dependency.RequireUpperBoundDeps failed with message:
[ERROR] Failed while enforcing RequireUpperBoundDeps. The error(s) are [
[ERROR] Require upper bound dependencies error for jakarta.jms:jakarta.jms-api:2.0.2 paths to dependency are:
[ERROR] +-com.elasticpath:ep-test-support:0.0.0-SNAPSHOT
[ERROR] +-org.apache.activemq:activemq-jms-pool:5.18.5
[ERROR] +-jakarta.jms:jakarta.jms-api:2.0.2 (managed) <-- jakarta.jms:jakarta.jms-api:2.0.3
[ERROR] and
[ERROR] +-com.elasticpath:ep-test-support:0.0.0-SNAPSHOT
[ERROR] +-org.apache.activemq:activemq-client:5.18.5
[ERROR] +-jakarta.jms:jakarta.jms-api:2.0.2 (managed) <-- jakarta.jms:jakarta.jms-api:2.0.3
[ERROR] ]
Duplicate Jar Finder
Plugin: basepom:duplicate-finder-maven-plugin
This plugin checks for multiple JARs that provide the same fully qualified class name. The plugin will fail the build if it finds more than one JAR that provides the same class.
- Runtime Stability: Prevents exceptions such as
NoSuchMethodError
andClassCastException
. - Predictable Behavior: Ensures the correct version of each class is loaded.
- Build Efficiency: Reduces overhead by eliminating duplicate dependencies.
Sample failure:
[WARNING] Found duplicate (but equal) classes in [com.sun.activation:jakarta.activation:1.2.2, jakarta.activation:jakarta.activation-api:1.2.2]:
[WARNING] javax.activation.ActivationDataFlavor
[WARNING] javax.activation.CommandInfo
[WARNING] javax.activation.CommandMap
[WARNING] javax.activation.CommandObject
[WARNING] javax.activation.DataContentHandler
[WARNING] javax.activation.DataContentHandlerFactory
[WARNING] javax.activation.DataHandler
[WARNING] javax.activation.DataHandlerDataSource
[WARNING] javax.activation.DataSource
[WARNING] javax.activation.DataSourceDataContentHandler
[WARNING] javax.activation.FileDataSource
[WARNING] javax.activation.FileTypeMap
[WARNING] javax.activation.MailcapCommandMap
[WARNING] javax.activation.MimeType
[WARNING] javax.activation.MimeTypeParameterList
[WARNING] javax.activation.MimeTypeParseException
[WARNING] javax.activation.MimetypesFileTypeMap
[WARNING] javax.activation.ObjectDataContentHandler
[WARNING] javax.activation.SecuritySupport
[WARNING] javax.activation.URLDataSource
[WARNING] javax.activation.UnsupportedDataTypeException
To fix these failures, all but one of the conflicting JARs needs to be excluded from the dependencies. Determining which ones to exclude and which to keep requires some investigation. Here are some guidelines to help you:
- Lookup the JARs in question in
mvnrepository.com
. Sometimes it will indicate that one of the JARs should be replaced by the other. - If one of the JARs is a superset of the other (includes the other), you should usually keep the superset and exclude the other.
- If one of the JARs provides an OSGi bundle implementation, you should usually keep that one and exclude the other.
- Ask ChatGPT for help if you're stuck. An example of a good prompt is the following:
There seem to be duplicate classes in com.sun.activation:jakarta.activation:1.2.2 and jakarta.activation:jakarta.activation-api:1.2.2; should they both be in my classpath?
- In this case it indicated the following: "If you need a working implementation, you need com.sun.activation:jakarta.activation — and it already contains the API too, so you don’t need to bring in the api separately."
Once you've determined which JARs to exclude, use mvn dependency:tree
in the affected module to determine where the dependency is coming from. If it's a direct dependency, you can simply remove it from the pom.xml
. If it's a transitive dependency, find where the top-level dependency was defined, and add an exclusion as in the following example:
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-jaxb-annotations</artifactId>
<version>${jackson.version}</version>
<exclusions>
<exclusion>
<groupId>jakarta.activation</groupId>
<artifactId>jakarta.activation-api</artifactId>
</exclusion>
</exclusions>
</dependency>