The maven plugin can be included in the pom.xml file of your artifact in the following way (requires maven >= 3.0.3):
<plugin>
<groupId>com.github.siom79.japicmp</groupId>
<artifactId>japicmp-maven-plugin</artifactId>
<version>0.23.0</version>
<configuration>
<oldVersion>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>${project.artifactId}</artifactId>
<version>${oldversion}</version>
<type>jar</type>
</dependency>
</oldVersion>
<newVersion>
<file>
<path>${project.build.directory}/${project.artifactId}-${project.version}.${project.packaging}</path>
</file>
</newVersion>
<parameter>
<!-- see documentation -->
</parameter>
</configuration>
<executions>
<execution>
<phase>verify</phase>
<goals>
<goal>cmp</goal>
</goals>
</execution>
</executions>
</plugin>
You can also leave out the <oldVersion> and <newVersion> elements:
<plugin>
<groupId>com.github.siom79.japicmp</groupId>
<artifactId>japicmp-maven-plugin</artifactId>
<version>0.23.0</version>
<configuration>
<parameter>
<!-- see documentation -->
</parameter>
</configuration>
<executions>
<execution>
<phase>verify</phase>
<goals>
<goal>cmp</goal>
</goals>
</execution>
</executions>
</plugin>
This way the plugin tries to determine the artifacts output (new version) and the latest released version (no SNAPSHOT version). If you need to configure the latest version more precisely (e.g. only GA versions), then you can use the parameter <oldVersionPattern>:
<plugin>
<groupId>com.github.siom79.japicmp</groupId>
<artifactId>japicmp-maven-plugin</artifactId>
<version>0.23.0</version>
<configuration>
<parameter>
<oldVersionPattern>\d+\.\d+\.\d+\.GA</oldVersionPattern>
</parameter>
</configuration>
<executions>
<execution>
<phase>verify</phase>
<goals>
<goal>cmp</goal>
</goals>
</execution>
</executions>
</plugin>
The following properties can be set:
Property | Description |
---|---|
japicmp.skip | Skip the execution of this plugin. |
japicmp.skipXmlReport | Skip the generation of the XML report. |
japicmp.skipHtmlReport | Skip the generation of the HTML report. |
japicmp.skipMarkdownReport | Skip the generation of the Markdown report. |
japicmp.breakBuildOnModifications | Break the build in case of any modifications. |
japicmp.breakBuildOnBinaryIncompatibleModifications | Break the build in case of any binary incompatible modifications. |
japicmp.breakBuildOnSourceIncompatibleModifications | Break the build in case of any source incompatible modifications. |
japicmp.breakBuildBasedOnSemanticVersioning | Break the build in case the semantic versioning is violated. |
japicmp.breakBuildBasedOnSemanticVersioningForMajorVersionZero | Break the build in case of semantic versioning used with zero as major version number is violated. |
An advanced configuration can utilize the following parameters:
<build>
<plugins>
<plugin>
<groupId>com.github.siom79.japicmp</groupId>
<artifactId>japicmp-maven-plugin</artifactId>
<version>0.23.0</version>
<configuration>
<oldVersion>
<dependency>
<groupId>japicmp</groupId>
<artifactId>japicmp-test-v1</artifactId>
<version>0.23.0</version>
<type>jar</type>
</dependency>
</oldVersion>
<newVersion>
<file>
<path>${project.build.directory}/${project.artifactId}-${project.version}.${project.packaging}</path>
</file>
</newVersion>
<parameter>
<onlyModified>true</onlyModified>
<includes>
<include>package.to.include</include>
<include>package.ClassToInclude</include>
<include>package.Class#methodToInclude(long,int)</include>
<include>package.Class#fieldToInclude</include>
<include>@my.AnnotationToInclude</include>
</includes>
<excludes>
<exclude>package.to.exclude</exclude>
<exclude>package.ClassToExclude</exclude>
<exclude>package.Class#methodToExclude(long,int)</exclude>
<exclude>package.Class#fieldToExclude</exclude>
<exclude>@my.AnnotationToExclude</exclude>
</excludes>
<includeExclusively>false</includeExclusively>
<excludeExclusively>false</excludeExclusively>
<accessModifier>public</accessModifier>
<breakBuildOnModifications>false</breakBuildOnModifications>
<breakBuildOnBinaryIncompatibleModifications>false</breakBuildOnBinaryIncompatibleModifications>
<breakBuildOnSourceIncompatibleModifications>false</breakBuildOnSourceIncompatibleModifications>
<breakBuildBasedOnSemanticVersioning>false</breakBuildBasedOnSemanticVersioning>
<breakBuildBasedOnSemanticVersioningForMajorVersionZero>false</breakBuildBasedOnSemanticVersioningForMajorVersionZero>
<breakBuildIfCausedByExclusion>true</breakBuildIfCausedByExclusion>
<overrideCompatibilityChangeParameters>
<overrideCompatibilityChangeParameter>
<compatibilityChange>CLASS_REMOVED</compatibilityChange>
<binaryCompatible>true</binaryCompatible>
<sourceCompatible>true</sourceCompatible>
<semanticVersionLevel>PATCH</semanticVersionLevel>
</overrideCompatibilityChangeParameter>
</overrideCompatibilityChangeParameters>
<onlyBinaryIncompatible>false</onlyBinaryIncompatible>
<includeSynthetic>false</includeSynthetic>
<ignoreMissingClasses>false</ignoreMissingClasses>
<ignoreMissingClassesByRegularExpressions>
<ignoreMissingClassesByRegularExpression>org.apache.commons.math3.*</ignoreMissingClassesByRegularExpression>
</ignoreMissingClassesByRegularExpressions>
<skipPomModules>true</skipPomModules>
<htmlStylesheet>path/to/stylesheet.css</htmlStylesheet>
<htmlTitle>Title of report</htmlTitle>
<markdownTitle>Title of report</markdownTitle>
<noAnnotations>false</noAnnotations>
<ignoreNonResolvableArtifacts>false</ignoreNonResolvableArtifacts>
<ignoreMissingOptionalDependency>false</ignoreMissingOptionalDependency>
<packagingSupporteds>
<packagingSupported>jar</packagingSupported>
</packagingSupporteds>
<postAnalysisScript>${project.basedir}/src/main/groovy/postAnalysisScript.groovy</postAnalysisScript>
<reportOnlyFilename>false</reportOnlyFilename>
<skipXmlReport>false</skipXmlReport>
<skipHtmlReport>false</skipHtmlReport>
<skipMarkdownReport>false</skipMarkdownReport>
<skipDiffReport>false</skipDiffReport>
<includeModules>
<includeModule>.*incl.*</includeModule>
</includeModules>
<excludeModules>
<excludeModule>.*incl.*</excludeModule>
</excludeModules>
<reportLinkName>artifact1_vs_artifact2</reportLinkName>
</parameter>
<dependencies>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-math3</artifactId>
<version>3.4</version>
</dependency>
</dependencies>
<skip>false</skip>
</configuration>
<executions>
<execution>
<phase>verify</phase>
<goals>
<goal>cmp</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
The elements <oldVersion> and <newVersion> elements let you specify which version you want to compare. Both elements support either a <dependency> or a <file> element. If necessary you can select the artifact by providing a <classifier> element inside the <dependency> element. Through the <parameter> element you can provide the following options:
Parameter | Optional | Default | Description |
---|---|---|---|
breakBuildOnModifications | true | false | If set to true, the build breaks in case a modification has been detected. |
breakBuildOnBinaryIncompatibleModifications | true | false | If set to true, the build breaks in case a binary incompatible modification has been detected. |
breakBuildOnSourceIncompatibleModifications | true | false | If set to true, the build breaks in case a source incompatible modification has been detected. |
breakBuildBasedOnSemanticVersioning | true | false | If set to true, the plugin analyzes the versions of the old and new archives and decides based on these versions if binary compatible or incompatible changes are allowed or not. This option expects versions in the form Major.Minor.Patch (e.g. 1.2.3 or 1.2.3-SNAPSHOT). |
breakBuildBasedOnSemanticVersioningForMajorVersionZero | true | false | If set to true, the plugin will apply the option breakBuildBasedOnSemanticVersioning also for projects with major version zero (which is not required by the Semantic Versioning Specification). |
breakBuildIfCausedByExclusion | true | true | If set to false, the plugin won't break the build if the incompatible change was caused by an excluded class (e.g. excluded interface removed from not excluded class). |
overrideCompatibilityChangeParameters | true | n.a. | Can be used to override default values for binary and source compatibility checks. |
onlyBinaryIncompatible | true | false | If set to true, only binary incompatible changes are reported. |
onlyModified | true | false | Outputs only modified classes/methods. If not set to true, all classes and methods are printed. |
includeSynthetic | true | false | If set to true, changes for synthetic classes and class members are tracked. |
noAnnotations | true | false | Setting this option to true disables the evaluation of annotations completely. |
reportOnlyFilename | true | false | If set to true, report will include only the artifact filename, not the complete artifact file path. |
reportOnlySummary | true | false | If set to true, report only a breakdown of classes and their status when generating plain text or html reports. |
ignoreMissingClasses | true | false | If set to true, superclasses and interfaces that cannot be resolved are ignored. Pleases note that in this case the results for the affected classes may not be accurate. |
ignoreMissingClassesByRegularExpressions | true | n.a. | List of regular expressions for superclasses and interfaces that cannot be resolved and that should be ignored. In contrast to the option ignoreMissingClasses, which ignores all missing classes, this options allows a fine-grained selection. |
accessModifier | true | protected | Sets the access modifier level (public, protected, package_protected, private). |
includes | true | n.a. | List of package, classes, methods and field that should be included. The syntax is similar to the one used for javadoc references. Annotations can also be used for filtering, just let the fully qualified name start with @. |
excludes | true | n.a. | List of package, classes, methods and field that should be excluded. The syntax is similar to the one used for javadoc references. Annotations can also be used for filtering, just let the fully qualified name start with @. |
includeExclusively | true | false | Include only packages specified in the “includes” parameter, exclude their sub-packages. |
excludeExclusively | true | false | Exclude only packages specified in the “excludes” parameter, include their sub-packages. |
htmlStylesheet | true | n.a. | Path to an individual CSS stylesheet for the HTML report. |
htmlTitle | true | n.a. | A title for the HTML report (optional). |
markdownTitle | true | n.a. | A title for the Markdown report (optional). |
skipPomModules | true | true | Setting this parameter to false (default: true) will not skip execution in modules with packaging type pom. |
skip | true | false | Setting this parameter to true will skip execution of the plugin. |
ignoreNonResolvableArtifacts | true | false | Set this to true in order to ignore artifacts that cannot be resolved, i.e. the build does not break in case a dependency cannot be resolved to a file. |
ignoreMissingOptionalDependency | true | false | Ignore missing optional dependencies. |
ignoreMissingOldVersion | true | false | If set to true, not resolvable artifacts for the old version do not break the build. |
ignoreMissingNewVersion | true | false | If set to true, not resolvable artifacts for the new version do not break the build. |
packagingSupported | true | n.a. | List all packaging type for which the plugin should be executed. Helpful if you define the plugin in a root pom. |
postAnalysisScript | true | n.a. | A Groovy script that gets invoked after analysis is completed and before the output is written. This way it can be used to filter the output or break the build on specific conditions. It can be an absolute path or a relative path of a file within the classpath. |
skipXmlReport | true | false | If set to true, no XML report will be generated. |
skipHtmlReport | true | false | If set to true, no HTML report will be generated. |
skipMarkdownReport | true | false | If set to true, no Markdown report will be generated. |
skipDiffReport | true | false | If set to true, no diff report will be generated. |
oldVersionPattern | true | n.a. | If <oldVersion> is not used, the old version compared against must match this regular expression. |
includeModules | true | n.a. | List of regular expression that specify if an artifact should be excluded based on its artifact id. |
excludeModules | true | n.a. | List of regular expression that specify if an artifact should be included based on its artifact id. |
reportLinkName | true | japicmp | Name of the Site Report. Defaults to ‘japicmp’. You must specify different names when using a ReportSet. |
includeSnapshots | true | false | If <oldVersion> is not used, this determines whether to include SNAPSHOT versions when resolving the version to compare. |
The parameter overrideCompatibilityChangeParameters allows you to override the default values for binary and source compatibility as well as the semantic version level for each check. This allows you to customize the following verifications:
Check | Default binary compatible | Default source compatible | Default semantic version level |
---|---|---|---|
ANNOTATION_ADDED | true | true | PATCH |
ANNOTATION_DEPRECATED_ADDED | true | true | MINOR |
ANNOTATION_MODIFIED | true | true | PATCH |
ANNOTATION_REMOVED | true | true | PATCH |
CLASS_GENERIC_TEMPLATE_CHANGED | true | false | MINOR |
CLASS_GENERIC_TEMPLATE_GENERICS_CHANGED | true | false | MINOR |
CLASS_LESS_ACCESSIBLE | false | false | MAJOR |
CLASS_NOW_ABSTRACT | false | false | MAJOR |
CLASS_NOW_CHECKED_EXCEPTION | true | false | MINOR |
CLASS_NOW_FINAL | false | false | MAJOR |
CLASS_NO_LONGER_PUBLIC | false | false | MAJOR |
CLASS_REMOVED | false | false | MAJOR |
CLASS_TYPE_CHANGED | false | false | MAJOR |
CONSTRUCTOR_LESS_ACCESSIBLE | false | false | MAJOR |
CONSTRUCTOR_REMOVED | false | false | MAJOR |
FIELD_GENERICS_CHANGED | true | false | MINOR |
FIELD_LESS_ACCESSIBLE | false | false | MAJOR |
FIELD_LESS_ACCESSIBLE_THAN_IN_SUPERCLASS | false | false | MAJOR |
FIELD_NOW_FINAL | false | false | MAJOR |
FIELD_NOW_STATIC | false | false | MAJOR |
FIELD_NOW_TRANSIENT | true | true | PATCH |
FIELD_NOW_VOLATILE | true | true | PATCH |
FIELD_NO_LONGER_STATIC | false | false | MAJOR |
FIELD_NO_LONGER_TRANSIENT | true | true | PATCH |
FIELD_NO_LONGER_VOLATILE | true | true | PATCH |
FIELD_REMOVED | false | false | MAJOR |
FIELD_REMOVED_IN_SUPERCLASS | false | false | MAJOR |
FIELD_STATIC_AND_OVERRIDES_STATIC | false | false | MAJOR |
FIELD_TYPE_CHANGED | false | false | MAJOR |
INTERFACE_ADDED | true | true | MINOR |
INTERFACE_REMOVED | false | false | MAJOR |
METHOD_ABSTRACT_ADDED_IN_IMPLEMENTED_INTERFACE | true | false | MINOR |
METHOD_ABSTRACT_ADDED_IN_SUPERCLASS | true | false | MINOR |
METHOD_ABSTRACT_ADDED_TO_CLASS | true | false | MINOR |
METHOD_ABSTRACT_NOW_DEFAULT | false | false | MAJOR |
METHOD_ADDED_TO_INTERFACE | true | false | MINOR |
METHOD_ADDED_TO_PUBLIC_CLASS | true | true | PATCH |
METHOD_DEFAULT_ADDED_IN_IMPLEMENTED_INTERFACE | true | true | MINOR |
METHOD_IS_STATIC_AND_OVERRIDES_NOT_STATIC | false | false | MAJOR |
METHOD_LESS_ACCESSIBLE | false | false | MAJOR |
METHOD_LESS_ACCESSIBLE_THAN_IN_SUPERCLASS | false | false | MAJOR |
METHOD_MOVED_TO_SUPERCLASS | true | true | PATCH |
METHOD_NEW_DEFAULT | true | true | MINOR |
METHOD_NEW_STATIC_ADDED_TO_INTERFACE | true | true | MINOR |
METHOD_NON_STATIC_IN_INTERFACE_NOW_STATIC | false | false | MAJOR |
METHOD_NOW_ABSTRACT | false | false | MAJOR |
METHOD_NOW_FINAL | false | false | MAJOR |
METHOD_NOW_STATIC | false | false | MAJOR |
METHOD_NOW_THROWS_CHECKED_EXCEPTION | true | false | MINOR |
METHOD_NOW_VARARGS | true | true | MINOR |
METHOD_NO_LONGER_STATIC | false | false | MAJOR |
METHOD_NO_LONGER_THROWS_CHECKED_EXCEPTION | true | false | MINOR |
METHOD_NO_LONGER_VARARGS | true | false | MINOR |
METHOD_PARAMETER_GENERICS_CHANGED | true | false | MINOR |
METHOD_REMOVED | false | false | MAJOR |
METHOD_REMOVED_IN_SUPERCLASS | false | false | MAJOR |
METHOD_RETURN_TYPE_CHANGED | false | false | MAJOR |
METHOD_RETURN_TYPE_GENERICS_CHANGED | true | false | MINOR |
METHOD_STATIC_IN_INTERFACE_NO_LONGER_STATIC | false | false | MAJOR |
SUPERCLASS_ADDED | true | true | MINOR |
SUPERCLASS_MODIFIED_INCOMPATIBLE | false | false | MAJOR |
SUPERCLASS_REMOVED | false | false | MAJOR |
If your library implements interfaces or extends classes from other libraries than the JDK, you can add these dependencies by using the <dependencies> element:
<dependencies>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-math3</artifactId>
<version>3.4</version>
</dependency>
</dependencies>
Dependencies declared in the enclosing pom.xml and its parents are added automatically. The dependencies declared explicitly for this plugin are appended to the classpath before the ones from the enclosing pom.xml, hence you can override them.
In case the classpath between both versions differs, you can add the dependencies for the new and old version separately:
<oldClassPathDependencies>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-math3</artifactId>
<version>3.4</version>
</dependency>
</oldClassPathDependencies>
<newClassPathDependencies>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-math3</artifactId>
<version>3.5</version>
</dependency>
</newClassPathDependencies>
The maven plugin produces the two files japicmp.diff
and japicmp.xml
within the directory ${project.build.directory}/japicmp
of your artifact. If you run the plugin multiple times within the same module using the <executions> element, the reports
are named after the execution id.
Alternatively it can be used inside the <reporting/>
tag in order to be invoked by the
maven-site-plugin and therewith to be integrated into the site report:
<reporting>
<plugins>
<plugin>
<groupId>com.github.siom79.japicmp</groupId>
<artifactId>japicmp-maven-plugin</artifactId>
<version>0.23.0</version>
<reportSets>
<reportSet>
<reports>
<report>cmp-report</report>
</reports>
</reportSet>
</reportSets>
<configuration>
<!-- see above -->
</configuration>
</plugin>
</plugins>
</reporting>
To create a summary report, you can also provide multiple old and new versions:
<configuration>
<oldVersions>
<dependency>
<groupId>com.github.siom79.japicmp</groupId>
<artifactId>japicmp-test-v1</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.github.siom79.japicmp</groupId>
<artifactId>japicmp-test2-v1</artifactId>
<version>${project.version}</version>
</dependency>
</oldVersions>
<newVersions>
<dependency>
<groupId>com.github.siom79.japicmp</groupId>
<artifactId>japicmp-test-v2</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.github.siom79.japicmp</groupId>
<artifactId>japicmp-test2-v2</artifactId>
<version>${project.version}</version>
</dependency>
</newVersions>
...
</configuration>
The configuration above will create one report for all the declared dependencies.
The parameter <postAnalysisScript/> can be used to invoke a Groovy script after the analysis but before the output is written.
This is helpful if you want to apply some custom filtering that is not possible with the standard means of japicmp. The following script for example filters out
all classes that reside within the package japicmp.test.annotation
and all methods that start with get...()
and set...()
.
def it = jApiClasses.iterator()
while (it.hasNext()) {
def jApiClass = it.next()
def fqn = jApiClass.getFullyQualifiedName()
if (fqn.startsWith("japicmp.test.annotation")) {
it.remove()
}
def methodIt = jApiClass.getMethods().iterator()
while (methodIt.hasNext()) {
def method = methodIt.next()
if (method.getName().startsWith("get") || method.getName().startsWith("set")) {
methodIt.remove()
}
}
}
return jApiClasses
Please note that the script has to return a list of JApiClass
objects, otherwise the maven plugin will report an error.
Beyond that the script can also be used to break the build on some project specific requirement. Let's assume that for the next release no classes within the package
japicmp.test.annotation
should be modified in any way. The following Groovy script iterates over all classes and throws an exception if a class is not UNCHANGED
.
import static japicmp.model.JApiChangeStatus.*
def it = jApiClasses.iterator()
while (it.hasNext()) {
def jApiClass = it.next()
def fqn = jApiClass.getFullyQualifiedName()
if (fqn.startsWith("japicmp.test.annotation")) {
if (jApiClass.getChangeStatus() != UNCHANGED) {
throw new Exception("Class in package japicmp.test.annotation has been modified.")
}
}
}
return jApiClasses
The script can also be placed inside another artifact and loaded from the classpath. Therefore, add the artifact containing the script as dependency to the japicmp-plugin:
<plugin>
<groupId>com.github.siom79.japicmp</groupId>
<artifactId>japicmp-maven-plugin</artifactId>
<version>${project.version}</version>
<configuration>
[...]
<parameter>
<!-- The post-analysis script is contained in "post-analysis-script-artifact" -->
<postAnalysisScript>post-analysis-script.groovy</postAnalysisScript>
</parameter>
</configuration>
<dependencies>
<dependency>
<groupId>com.github.siom79.japicmp</groupId>
<artifactId>post-analysis-script-artifact</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</plugin>