options = EnumSet.noneOf(Checker.Option.class);
if (failOnMissingClasses) options.add(FAIL_ON_MISSING_CLASSES);
if (failOnViolation) options.add(FAIL_ON_VIOLATION);
- if (failOnUnresolvableSignatures) options.add(FAIL_ON_UNRESOLVABLE_SIGNATURES);
+ if (failOnUnresolvableSignatures) {
+ options.add(FAIL_ON_UNRESOLVABLE_SIGNATURES);
+ } else {
+ log.warn(DEPRECATED_WARN_FAIL_ON_UNRESOLVABLE_SIGNATURES);
+ }
+ if (ignoreSignaturesOfMissingClasses) options.add(IGNORE_SIGNATURES_OF_MISSING_CLASSES);
if (disableClassloadingCache) options.add(DISABLE_CLASSLOADING_CACHE);
final Checker checker = new Checker(log, loader, options);
@@ -169,7 +175,12 @@ public void info(String msg) {
}
if (checker.hasNoSignatures()) {
- throw new BuildException("No API signatures found; use signaturesFile=, , or inner text to define those!");
+ if (checker.noSignaturesFilesParsed()) {
+ throw new BuildException("No signatures were added to task; use signaturesFile=, , or inner text to define those!");
+ } else {
+ log.info("Skipping execution because no API signatures are available.");
+ return;
+ }
}
log.info("Loading classes to check...");
@@ -325,13 +336,34 @@ public void setFailOnMissingClasses(boolean failOnMissingClasses) {
/**
* Fail the build if a signature is not resolving. If this parameter is set to
- * to false, then such signatures are silently ignored.
- * Defaults to {@code true}.
+ * to false, then such signatures are ignored. Defaults to {@code true}.
+ * When disabling this setting, the task still prints a warning to inform the user about
+ * broken signatures. This cannot be disabled. There is a second setting
+ * {@link #setIgnoreMissingSignaturesClasses()} that can be used to silently ignore
+ * signatures that refer to methods or field in classes that are not on classpath,
+ * e.g. This is useful in multi-module builds where a common set of signatures is used,
+ * that are not part of every sub-modules dependencies.
+ * @see #setIgnoreMissingSignaturesClasses()
+ * @deprecated Use {@link #setIgnoreSignaturesOfMissingClasses(boolean)} instead.
*/
+ @Deprecated
public void setFailOnUnresolvableSignatures(boolean failOnUnresolvableSignatures) {
this.failOnUnresolvableSignatures = failOnUnresolvableSignatures;
}
+ /**
+ * If a class is missing while parsing signatures files, all methods and fields from this
+ * class are silently ignored. This is useful in multi-module
+ * projects where only some modules have the dependency to which the signature file(s) apply.
+ * This settings prints no warning at all, so verify the signatures at least once with
+ * full dependencies.
+ * Defaults to {@code false}.
+ * @since 3.0
+ */
+ public void setIgnoreSignaturesOfMissingClasses(boolean ignoreSignaturesOfMissingClasses) {
+ this.ignoreSignaturesOfMissingClasses = ignoreSignaturesOfMissingClasses;
+ }
+
/** Automatically restrict resource names included to files with a name ending in '.class'.
* This makes filesets easier, as the includes="**/*.class" is not needed.
* Defaults to {@code true}.
diff --git a/src/main/java/de/thetaphi/forbiddenapis/cli/CliMain.java b/src/main/java/de/thetaphi/forbiddenapis/cli/CliMain.java
index b10ca5d3..f4b0f0c3 100644
--- a/src/main/java/de/thetaphi/forbiddenapis/cli/CliMain.java
+++ b/src/main/java/de/thetaphi/forbiddenapis/cli/CliMain.java
@@ -53,7 +53,7 @@
public final class CliMain implements Constants {
private final Option classpathOpt, dirOpt, includesOpt, excludesOpt, signaturesfileOpt, bundledsignaturesOpt, suppressannotationsOpt,
- allowmissingclassesOpt, allowunresolvablesignaturesOpt, versionOpt, helpOpt;
+ allowmissingclassesOpt, ignoresignaturesofmissingclassesOpt, allowunresolvablesignaturesOpt, versionOpt, helpOpt;
private final CommandLine cmd;
private static final Logger LOG = StdIoLogger.INSTANCE;
@@ -129,8 +129,12 @@ public CliMain(String... args) throws ExitException {
.desc("don't fail if a referenced class is missing on classpath")
.longOpt("allowmissingclasses")
.build());
+ options.addOption(ignoresignaturesofmissingclassesOpt = Option.builder()
+ .desc("if a class is missing while parsing signatures files, all methods and fields from this class are silently ignored")
+ .longOpt("ignoresignaturesofmissingclasses")
+ .build());
options.addOption(allowunresolvablesignaturesOpt = Option.builder()
- .desc("don't fail if a signature is not resolving")
+ .desc("DEPRECATED: don't fail if a signature is not resolving")
.longOpt("allowunresolvablesignatures")
.build());
@@ -212,7 +216,12 @@ public void run() throws ExitException {
try (final URLClassLoader loader = URLClassLoader.newInstance(urls, ClassLoader.getSystemClassLoader())) {
final EnumSet options = EnumSet.of(FAIL_ON_VIOLATION);
if (!cmd.hasOption(allowmissingclassesOpt.getLongOpt())) options.add(FAIL_ON_MISSING_CLASSES);
- if (!cmd.hasOption(allowunresolvablesignaturesOpt.getLongOpt())) options.add(FAIL_ON_UNRESOLVABLE_SIGNATURES);
+ if (cmd.hasOption(allowunresolvablesignaturesOpt.getLongOpt())) {
+ LOG.warn(DEPRECATED_WARN_FAIL_ON_UNRESOLVABLE_SIGNATURES);
+ } else {
+ options.add(FAIL_ON_UNRESOLVABLE_SIGNATURES);
+ }
+ if (cmd.hasOption(ignoresignaturesofmissingclassesOpt.getLongOpt())) options.add(IGNORE_SIGNATURES_OF_MISSING_CLASSES);
final Checker checker = new Checker(LOG, loader, options);
if (!checker.isSupportedJDK) {
@@ -267,10 +276,15 @@ public void run() throws ExitException {
}
if (checker.hasNoSignatures()) {
- throw new ExitException(EXIT_ERR_CMDLINE, String.format(Locale.ENGLISH,
- "No API signatures found; use parameters '--%s' and/or '--%s' to specify those!",
- bundledsignaturesOpt.getLongOpt(), signaturesfileOpt.getLongOpt()
- ));
+ if (checker.noSignaturesFilesParsed()) {
+ throw new ExitException(EXIT_ERR_CMDLINE, String.format(Locale.ENGLISH,
+ "No API signatures given as parameters; use '--%s' and/or '--%s' to specify those!",
+ bundledsignaturesOpt.getLongOpt(), signaturesfileOpt.getLongOpt()
+ ));
+ } else {
+ LOG.info("Skipping execution because no API signatures are available.");
+ return;
+ }
}
try {
diff --git a/src/main/java/de/thetaphi/forbiddenapis/gradle/CheckForbiddenApis.java b/src/main/java/de/thetaphi/forbiddenapis/gradle/CheckForbiddenApis.java
index 84ed7fb8..1ff82933 100644
--- a/src/main/java/de/thetaphi/forbiddenapis/gradle/CheckForbiddenApis.java
+++ b/src/main/java/de/thetaphi/forbiddenapis/gradle/CheckForbiddenApis.java
@@ -258,20 +258,47 @@ public void setFailOnMissingClasses(boolean failOnMissingClasses) {
/**
* Fail the build if a signature is not resolving. If this parameter is set to
- * to false, then such signatures are silently ignored. This is useful in multi-module Maven
- * projects where only some modules have the dependency to which the signature file(s) apply.
- * Defaults to {@code true}.
+ * to false, then such signatures are ignored. Defaults to {@code true}.
+ * When disabling this setting, the task still prints a warning to inform the user about
+ * broken signatures. This cannot be disabled. There is a second setting
+ * {@link #getIgnoreSignaturesOfMissingClasses()} that can be used to silently ignore
+ * signatures that refer to methods or field in classes that are not on classpath,
+ * e.g. This is useful in multi-module Gradle builds where a common set of signatures is used,
+ * that are not part of every sub-modules dependencies.
+ * @see #getIgnoreSignaturesOfMissingClasses()
+ * @deprecated Use {@link #getIgnoreSignaturesOfMissingClasses()} instead.
*/
@Input
+ @Deprecated
public boolean getFailOnUnresolvableSignatures() {
return data.failOnUnresolvableSignatures;
}
/** @see #getFailOnUnresolvableSignatures */
+ @Deprecated
public void setFailOnUnresolvableSignatures(boolean failOnUnresolvableSignatures) {
data.failOnUnresolvableSignatures = failOnUnresolvableSignatures;
}
+ /**
+ * If a class is missing while parsing signatures files, all methods and fields from this
+ * class are silently ignored. This is useful in multi-module Gradle
+ * projects where only some modules have the dependency to which the signature file(s) apply.
+ * This settings prints no warning at all, so verify the signatures at least once with
+ * full dependencies.
+ * Defaults to {@code false}.
+ * @since 3.0
+ */
+ @Input
+ public boolean getIgnoreSignaturesOfMissingClasses() {
+ return data.ignoreSignaturesOfMissingClasses;
+ }
+
+ /** @see #getFailOnUnresolvableSignatures */
+ public void setIgnoreSignaturesOfMissingClasses(boolean ignoreSignaturesOfMissingClasses) {
+ data.ignoreSignaturesOfMissingClasses = ignoreSignaturesOfMissingClasses;
+ }
+
/**
* {@inheritDoc}
*
@@ -492,7 +519,12 @@ public void info(String msg) {
final EnumSet options = EnumSet.noneOf(Checker.Option.class);
if (getFailOnMissingClasses()) options.add(FAIL_ON_MISSING_CLASSES);
if (!getIgnoreFailures()) options.add(FAIL_ON_VIOLATION);
- if (getFailOnUnresolvableSignatures()) options.add(FAIL_ON_UNRESOLVABLE_SIGNATURES);
+ if (getFailOnUnresolvableSignatures()) {
+ options.add(FAIL_ON_UNRESOLVABLE_SIGNATURES);
+ } else {
+ log.warn(DEPRECATED_WARN_FAIL_ON_UNRESOLVABLE_SIGNATURES);
+ }
+ if (getIgnoreSignaturesOfMissingClasses()) options.add(IGNORE_SIGNATURES_OF_MISSING_CLASSES);
if (getDisableClassloadingCache()) options.add(DISABLE_CLASSLOADING_CACHE);
final Checker checker = new Checker(log, loader, options);
@@ -552,8 +584,8 @@ public void info(String msg) {
}
if (checker.hasNoSignatures()) {
- if (options.contains(FAIL_ON_UNRESOLVABLE_SIGNATURES)) {
- throw new InvalidUserDataException("No API signatures found; use properties 'signatures', 'bundledSignatures', 'signaturesURLs', and/or 'signaturesFiles' to define those!");
+ if (checker.noSignaturesFilesParsed()) {
+ throw new InvalidUserDataException("No signatures were added to task; use properties 'signatures', 'bundledSignatures', 'signaturesURLs', and/or 'signaturesFiles' to define those!");
} else {
log.info("Skipping execution because no API signatures are available.");
return;
diff --git a/src/main/java/de/thetaphi/forbiddenapis/gradle/CheckForbiddenApisExtension.java b/src/main/java/de/thetaphi/forbiddenapis/gradle/CheckForbiddenApisExtension.java
index 6fe4b9f7..775fbe86 100644
--- a/src/main/java/de/thetaphi/forbiddenapis/gradle/CheckForbiddenApisExtension.java
+++ b/src/main/java/de/thetaphi/forbiddenapis/gradle/CheckForbiddenApisExtension.java
@@ -46,6 +46,7 @@ public CheckForbiddenApisExtension(Project project) {
failOnMissingClasses = true,
failOnUnresolvableSignatures = true,
ignoreFailures = false,
+ ignoreSignaturesOfMissingClasses = false,
disableClassloadingCache = ForbiddenApisPlugin.DEFAULT_DISABLE_CLASSLOADING_CACHE;
}
diff --git a/src/main/java/de/thetaphi/forbiddenapis/maven/AbstractCheckMojo.java b/src/main/java/de/thetaphi/forbiddenapis/maven/AbstractCheckMojo.java
index 611dd742..a6cb8abc 100644
--- a/src/main/java/de/thetaphi/forbiddenapis/maven/AbstractCheckMojo.java
+++ b/src/main/java/de/thetaphi/forbiddenapis/maven/AbstractCheckMojo.java
@@ -130,12 +130,33 @@ public abstract class AbstractCheckMojo extends AbstractMojo implements Constant
/**
* Fail the build if a signature is not resolving. If this parameter is set to
- * to false, then such signatures are silently ignored. This is useful in multi-module Maven
- * projects where only some modules have the dependency to which the signature file(s) apply.
+ * to false, then such signatures are ignored. Defaults to {@code true}.
+ * When disabling this setting, the task still prints a warning to inform the user about
+ * broken signatures. This cannot be disabled. There is a second setting
+ * {@link #ignoreSignaturesOfMissingClasses} that can be used to silently ignore
+ * signatures that refer to methods or field in classes that are not on classpath,
+ * e.g. This is useful in multi-module Maven builds where a common set of signatures is used,
+ * that are not part of every sub-modules dependencies.
+ * @see #ignoreSignaturesOfMissingClasses)
+ * @deprecated The setting 'failOnUnresolvableSignatures' was deprecated and will be removed in next version. Use 'ignoreSignaturesOfMissingClasses' instead.
* @since 1.4
*/
+ @Deprecated
@Parameter(required = false, defaultValue = "true")
private boolean failOnUnresolvableSignatures;
+
+ /**
+ * If a class is missing while parsing signatures files, all methods and fields from this
+ * class are silently ignored. This is useful in multi-module Maven
+ * projects where only some modules have the dependency to which the signature file(s) apply.
+ * This settings prints no warning at all, so verify the signatures at least once with
+ * full dependencies.
+ * Defaults to {@code false}.
+ * @since 3.0
+ */
+ @Parameter(required = false, defaultValue = "false")
+ private boolean ignoreSignaturesOfMissingClasses;
+
/**
* Fail the build if violations have been found. Defaults to {@code true}.
@@ -311,7 +332,12 @@ public void info(String msg) {
final EnumSet options = EnumSet.noneOf(Checker.Option.class);
if (failOnMissingClasses) options.add(FAIL_ON_MISSING_CLASSES);
if (failOnViolation) options.add(FAIL_ON_VIOLATION);
- if (failOnUnresolvableSignatures) options.add(FAIL_ON_UNRESOLVABLE_SIGNATURES);
+ if (failOnUnresolvableSignatures) {
+ options.add(FAIL_ON_UNRESOLVABLE_SIGNATURES);
+ } else {
+ // no warning needed, Maven does this automatically based on @deprecated annotation
+ }
+ if (ignoreSignaturesOfMissingClasses) options.add(IGNORE_SIGNATURES_OF_MISSING_CLASSES);
if (disableClassloadingCache) options.add(DISABLE_CLASSLOADING_CACHE);
final Checker checker = new Checker(log, loader, options);
@@ -411,8 +437,8 @@ public void info(String msg) {
}
if (checker.hasNoSignatures()) {
- if (failOnUnresolvableSignatures) {
- throw new MojoExecutionException("No API signatures found; use parameters 'signatures', 'bundledSignatures', 'signaturesFiles', and/or 'signaturesArtifacts' to define those!");
+ if (checker.noSignaturesFilesParsed()) {
+ throw new MojoExecutionException("No signatures were added to mojo; use parameters 'signatures', 'bundledSignatures', 'signaturesFiles', and/or 'signaturesArtifacts' to define those!");
} else {
log.info("Skipping execution because no API signatures are available.");
return;
diff --git a/src/test/antunit/TestInlineSignatures.xml b/src/test/antunit/TestInlineSignatures.xml
index 84a34b29..cd8bc703 100644
--- a/src/test/antunit/TestInlineSignatures.xml
+++ b/src/test/antunit/TestInlineSignatures.xml
@@ -95,8 +95,8 @@
foo.bar.ForbiddenApis#testMethod() @ should be ignored
java.lang.String#forbiddenFoobarMethod() @ should be ignored
java.lang.String#forbiddenFoobarField @ should be ignored
- java.awt.Color @ Color is disallowed, thats not bad, because ANT has no colors... (this was just added to don't fail because of missing signatures)
+
@@ -109,12 +109,65 @@
foo.bar.ForbiddenApis#testMethod() @ should be ignored
java.lang.String#forbiddenFoobarMethod() @ should be ignored
java.lang.String#forbiddenFoobarField @ should be ignored
- java.awt.Color @ Color is disallowed, thats not bad, because ANT has no colors... (this was just added to don't fail because of missing signatures)
+
+
+
+
+ @ignoreMissingClasses
+ foo.bar.ForbiddenApis#testMethod() @ should be ignored
+ foo.bar.ForbiddenApis#field @ should be ignored
+ foo.bar.ForbiddenApis @ should be ignored
+
+
+
+
+
+
+
+ foo.bar.ForbiddenApis#testMethod() @ should be ignored
+ foo.bar.ForbiddenApis#field @ should be ignored
+ foo.bar.ForbiddenApis @ should be ignored
+
+
+
+
+
+
+
+
+ foo.bar.ForbiddenApis#testMethod() @ should be ignored
+ java.lang.String#forbiddenFoobarMethod() @ should not be ignored
+ java.lang.String#forbiddenFoobarField @ should not be ignored
+
+
+
+
+
+
+
+
+
+
+ @ignoreMissingClasses
+ foo.bar.ForbiddenApis#testMethod() @ should be ignored
+ foo.bar.ForbiddenApis#field @ should be ignored
+ foo.bar.ForbiddenApis @ should be ignored
+
+
+ foo.bar.ForbiddenApis2#testMethod() @ should fail
+ foo.bar.ForbiddenApis2#field @ should fail
+ foo.bar.ForbiddenApis2 @ should fail
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/antunit/TestMavenMojo.xml b/src/test/antunit/TestMavenMojo.xml
index f572bbf4..096e1147 100644
--- a/src/test/antunit/TestMavenMojo.xml
+++ b/src/test/antunit/TestMavenMojo.xml
@@ -96,6 +96,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/test/antunit/pom-generator.xsl b/src/test/antunit/pom-generator.xsl
index f1ee380a..8ced350f 100644
--- a/src/test/antunit/pom-generator.xsl
+++ b/src/test/antunit/pom-generator.xsl
@@ -47,6 +47,7 @@
${version}
${antunit.failOnUnresolvableSignatures}
+ ${antunit.ignoreSignaturesOfMissingClasses}
${antunit.failOnViolation}
jdk-unsafe
diff --git a/src/test/antunit/pom-sigArtifacts.xml b/src/test/antunit/pom-sigArtifacts.xml
index c87ba533..53db1c34 100644
--- a/src/test/antunit/pom-sigArtifacts.xml
+++ b/src/test/antunit/pom-sigArtifacts.xml
@@ -37,6 +37,7 @@
${artifactId}
${version}
jar
+
de/thetaphi/forbiddenapis/signatures/jdk-deprecated-${jdk.version}.txt
diff --git a/src/test/java/de/thetaphi/forbiddenapis/CheckerSetupTest.java b/src/test/java/de/thetaphi/forbiddenapis/CheckerSetupTest.java
index 7b031ca5..1b0dbca2 100644
--- a/src/test/java/de/thetaphi/forbiddenapis/CheckerSetupTest.java
+++ b/src/test/java/de/thetaphi/forbiddenapis/CheckerSetupTest.java
@@ -46,6 +46,7 @@ public void testEmpty() {
assertEquals(Collections.emptyMap(), forbiddenSignatures.signatures);
assertEquals(Collections.emptySet(), forbiddenSignatures.classPatterns);
assertTrue(checker.hasNoSignatures());
+ assertTrue(checker.noSignaturesFilesParsed());
}
@Test
@@ -53,6 +54,8 @@ public void testClassSignature() throws Exception {
checker.parseSignaturesString("java.lang.Object @ Foobar");
assertEquals(Collections.singletonMap(Signatures.getKey("java/lang/Object"), "java.lang.Object [Foobar]"), forbiddenSignatures.signatures);
assertEquals(Collections.emptySet(), forbiddenSignatures.classPatterns);
+ assertFalse(checker.hasNoSignatures());
+ assertFalse(checker.noSignaturesFilesParsed());
}
@Test
@@ -61,6 +64,8 @@ public void testClassPatternSignature() throws Exception {
assertEquals(Collections.emptyMap(), forbiddenSignatures.signatures);
assertEquals(Collections.singleton(new ClassPatternRule("java.lang.**", "Foobar")),
forbiddenSignatures.classPatterns);
+ assertFalse(checker.hasNoSignatures());
+ assertFalse(checker.noSignaturesFilesParsed());
}
@Test
@@ -69,6 +74,8 @@ public void testFieldSignature() throws Exception {
assertEquals(Collections.singletonMap(Signatures.getKey("java/lang/String", "CASE_INSENSITIVE_ORDER"), "java.lang.String#CASE_INSENSITIVE_ORDER [Foobar]"),
forbiddenSignatures.signatures);
assertEquals(Collections.emptySet(), forbiddenSignatures.classPatterns);
+ assertFalse(checker.hasNoSignatures());
+ assertFalse(checker.noSignaturesFilesParsed());
}
@Test
@@ -77,6 +84,8 @@ public void testMethodSignature() throws Exception {
assertEquals(Collections.singletonMap(Signatures.getKey("java/lang/Object", new Method("toString", "()Ljava/lang/String;")), "java.lang.Object#toString() [Foobar]"),
forbiddenSignatures.signatures);
assertEquals(Collections.emptySet(), forbiddenSignatures.classPatterns);
+ assertFalse(checker.hasNoSignatures());
+ assertFalse(checker.noSignaturesFilesParsed());
}
@Test