Skip to content

Commit

Permalink
Merge pull request #140 from /issues/83
Browse files Browse the repository at this point in the history
Fix for issue #83: Tone down warnings by missing classes in signatures files
  • Loading branch information
uschindler committed Mar 30, 2018
2 parents fbe7a3e + 63bae01 commit b95a724
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 18 deletions.
66 changes: 51 additions & 15 deletions src/main/java/de/thetaphi/forbiddenapis/Checker.java
Expand Up @@ -94,25 +94,30 @@ public static enum Option {
final Set<String> suppressAnnotations = new LinkedHashSet<String>();

private static enum UnresolvableReporting {
FAIL() {
FAIL(true) {
@Override
public void parseFailed(Logger logger, String message, String signature) throws ParseException {
throw new ParseException(String.format(Locale.ENGLISH, "%s while parsing signature: %s", message, signature));
}
},
WARNING() {
WARNING(false) {
@Override
public void parseFailed(Logger logger, String message, String signature) throws ParseException {
logger.warn(String.format(Locale.ENGLISH, "%s while parsing signature: %s [signature ignored]", message, signature));
}
},
SILENT() {
SILENT(true) {
@Override
public void parseFailed(Logger logger, String message, String signature) throws ParseException {
// keep silent
}
};

private UnresolvableReporting(boolean reportClassNotFound) {
this.reportClassNotFound = reportClassNotFound;
}

public final boolean reportClassNotFound;
public abstract void parseFailed(Logger logger, String message, String signature) throws ParseException;
}

Expand Down Expand Up @@ -348,7 +353,7 @@ public ClassSignature lookupRelatedClass(String internalName) {
}

/** Adds the method signature to the list of disallowed methods. The Signature is checked against the given ClassLoader. */
private void addSignature(final String line, final String defaultMessage, final UnresolvableReporting report) throws ParseException,IOException {
private void addSignature(final String line, final String defaultMessage, final UnresolvableReporting report, final Set<String> missingClasses) throws ParseException,IOException {
final String clazz, field, signature;
String message = null;
final Method method;
Expand All @@ -360,6 +365,9 @@ private void addSignature(final String line, final String defaultMessage, final
signature = line;
message = defaultMessage;
}
if (line.isEmpty()) {
throw new ParseException("Empty signature");
}
p = signature.indexOf('#');
if (p >= 0) {
clazz = signature.substring(0, p);
Expand Down Expand Up @@ -401,7 +409,11 @@ private void addSignature(final String line, final String defaultMessage, final
try {
c = getClassFromClassLoader(clazz);
} catch (ClassNotFoundException cnfe) {
report.parseFailed(logger, String.format(Locale.ENGLISH, "Class '%s' not found on classpath", cnfe.getMessage()), signature);
if (report.reportClassNotFound) {
report.parseFailed(logger, String.format(Locale.ENGLISH, "Class '%s' not found on classpath", cnfe.getMessage()), signature);
} else {
missingClasses.add(clazz);
}
return;
}
if (method != null) {
Expand Down Expand Up @@ -433,10 +445,30 @@ private void addSignature(final String line, final String defaultMessage, final
}
}
}

private void reportMissingSignatureClasses(Set<String> missingClasses) {
if (missingClasses.isEmpty()) {
return;
}
logger.warn("Some signatures were ignored because the following classes were not found on classpath:");
final StringBuilder sb = new StringBuilder();
int count = 0;
for (String s : missingClasses) {
sb.append(count == 0 ? " " : ", ").append(s);
count++;
if (sb.length() >= 70) {
sb.append(",... (and ").append(missingClasses.size() - count).append(" more).");
break;
}
}
logger.warn(sb.toString());
}

/** Reads a list of bundled API signatures from classpath. */
public void addBundledSignatures(String name, String jdkTargetVersion) throws IOException,ParseException {
addBundledSignatures(name, jdkTargetVersion, true);
final Set<String> missingClasses = new TreeSet<String>();
addBundledSignatures(name, jdkTargetVersion, true, missingClasses);
reportMissingSignatureClasses(missingClasses);
}

public static String fixTargetVersion(String name) throws ParseException {
Expand Down Expand Up @@ -465,7 +497,7 @@ public static String fixTargetVersion(String name) throws ParseException {
return name;
}

private void addBundledSignatures(String name, String jdkTargetVersion, boolean logging) throws IOException,ParseException {
private void addBundledSignatures(String name, String jdkTargetVersion, boolean logging, Set<String> missingClasses) throws IOException,ParseException {
if (!name.matches("[A-Za-z0-9\\-\\.]+")) {
throw new ParseException("Invalid bundled signature reference: " + name);
}
Expand All @@ -487,13 +519,15 @@ private void addBundledSignatures(String name, String jdkTargetVersion, boolean
throw new FileNotFoundException("Bundled signatures resource not found: " + name);
}
if (logging) logger.info("Reading bundled API signatures: " + name);
parseSignaturesFile(in, true);
parseSignaturesStream(in, true, missingClasses);
}

/** Reads a list of API signatures. Closes the Reader when done (on Exception, too)! */
public void parseSignaturesFile(InputStream in, String name) throws IOException,ParseException {
logger.info("Reading API signatures: " + name);
parseSignaturesFile(in, false);
final Set<String> missingClasses = new TreeSet<String>();
parseSignaturesStream(in, false, missingClasses);
reportMissingSignatureClasses(missingClasses);
}

/** Reads a list of API signatures from the given URL. */
Expand All @@ -509,18 +543,20 @@ public void parseSignaturesFile(File f) throws IOException,ParseException {
/** Reads a list of API signatures from a String. */
public void parseSignaturesString(String signatures) throws IOException,ParseException {
logger.info("Reading inline API signatures...");
parseSignaturesFile(new StringReader(signatures), false);
final Set<String> missingClasses = new TreeSet<String>();
parseSignaturesFile(new StringReader(signatures), false, missingClasses);
reportMissingSignatureClasses(missingClasses);
}

private void parseSignaturesFile(InputStream in, boolean allowBundled) throws IOException,ParseException {
parseSignaturesFile(new InputStreamReader(in, "UTF-8"), allowBundled);
private void parseSignaturesStream(InputStream in, boolean allowBundled, Set<String> missingClasses) throws IOException,ParseException {
parseSignaturesFile(new InputStreamReader(in, "UTF-8"), allowBundled, missingClasses);
}

private static final String BUNDLED_PREFIX = "@includeBundled ";
private static final String DEFAULT_MESSAGE_PREFIX = "@defaultMessage ";
private static final String IGNORE_UNRESOLVABLE_LINE = "@ignoreUnresolvable";

private void parseSignaturesFile(Reader reader, boolean isBundled) throws IOException,ParseException {
private void parseSignaturesFile(Reader reader, boolean isBundled, Set<String> missingClasses) throws IOException,ParseException {
final BufferedReader r = new BufferedReader(reader);
try {
String line, defaultMessage = null;
Expand All @@ -532,7 +568,7 @@ private void parseSignaturesFile(Reader reader, boolean isBundled) throws IOExce
if (line.startsWith("@")) {
if (isBundled && line.startsWith(BUNDLED_PREFIX)) {
final String name = line.substring(BUNDLED_PREFIX.length()).trim();
addBundledSignatures(name, null, false);
addBundledSignatures(name, null, false, missingClasses);
} else if (line.startsWith(DEFAULT_MESSAGE_PREFIX)) {
defaultMessage = line.substring(DEFAULT_MESSAGE_PREFIX.length()).trim();
if (defaultMessage.length() == 0) defaultMessage = null;
Expand All @@ -542,7 +578,7 @@ private void parseSignaturesFile(Reader reader, boolean isBundled) throws IOExce
throw new ParseException("Invalid line in signature file: " + line);
}
} else {
addSignature(line, defaultMessage, reporter);
addSignature(line, defaultMessage, reporter, missingClasses);
}
}
} finally {
Expand Down
6 changes: 4 additions & 2 deletions src/test/antunit/TestInlineSignatures.xml
Expand Up @@ -97,7 +97,8 @@
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)
</forbiddenapis>
<au:assertLogContains level="warning" text="Class 'foo.bar.ForbiddenApis' not found on classpath while parsing signature: foo.bar.ForbiddenApis#testMethod() [signature ignored]"/>
<au:assertLogContains level="warning" text="Some signatures were ignored because the following classes were not found on classpath:"/>
<au:assertLogContains level="warning" text=" foo.bar.ForbiddenApis"/>
<au:assertLogContains level="warning" text="Method not found while parsing signature: java.lang.String#forbiddenFoobarMethod() [signature ignored]"/>
<au:assertLogContains level="warning" text="Field not found while parsing signature: java.lang.String#forbiddenFoobarField [signature ignored]"/>
</target>
Expand All @@ -110,7 +111,8 @@
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)
</forbiddenapis>
<au:assertLogContains level="warning" text="Class 'foo.bar.ForbiddenApis' not found on classpath while parsing signature: foo.bar.ForbiddenApis#testMethod() [signature ignored]"/>
<au:assertLogContains level="warning" text="Some signatures were ignored because the following classes were not found on classpath:"/>
<au:assertLogContains level="warning" text=" foo.bar.ForbiddenApis"/>
<au:assertLogContains level="warning" text="Method not found while parsing signature: java.lang.String#forbiddenFoobarMethod() [signature ignored]"/>
<au:assertLogContains level="warning" text="Field not found while parsing signature: java.lang.String#forbiddenFoobarField [signature ignored]"/>
</target>
Expand Down
3 changes: 2 additions & 1 deletion src/test/antunit/TestMavenMojo.xml
Expand Up @@ -84,7 +84,8 @@
<sysproperty key="antunit.signatures" value="foo.bar.ForbiddenApis#testMethod()&#10;java.lang.String#forbiddenFoobarMethod()&#10;java.lang.String#forbiddenFoobarField"/>
<sysproperty key="antunit.failOnUnresolvableSignatures" value="false"/>
</artifact:mvn>
<au:assertLogContains text="Class 'foo.bar.ForbiddenApis' not found on classpath while parsing signature: foo.bar.ForbiddenApis#testMethod() [signature ignored]"/>
<au:assertLogContains text="Some signatures were ignored because the following classes were not found on classpath:"/>
<au:assertLogContains text=" foo.bar.ForbiddenApis"/>
<au:assertLogContains text="Method not found while parsing signature: java.lang.String#forbiddenFoobarMethod() [signature ignored]"/>
<au:assertLogContains text="Field not found while parsing signature: java.lang.String#forbiddenFoobarField [signature ignored]"/>
</target>
Expand Down

0 comments on commit b95a724

Please sign in to comment.