Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add new setting to disable the classloading cache #76

Merged
merged 9 commits into from
Jun 13, 2016
7 changes: 7 additions & 0 deletions src/main/docs/ant-task.html
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,13 @@ <h2>Parameters</h2>
<td>Reference to a <code>path</code> defined anywhere else. Should be identical to classpath used for compiling the class files.</td>
</tr>

<tr>
<td>disableClassloadingCache</td>
<td><code>boolean</code></td>
<td><code>false</code></td>
<td>Disable the internal JVM classloading cache when getting bytecode from the classpath. This setting slows down checks, but <em>may</em> work around issues with other Mojos, that do not close their class loaders. If you get <code>FileNotFoundException</code>s related to non-existent JAR entries you can try to work around using this setting.</td>
</tr>

<tr>
<td>failOnUnsupportedJava</td>
<td><code>boolean</code></td>
Expand Down
6 changes: 5 additions & 1 deletion src/main/java/de/thetaphi/forbiddenapis/Checker.java
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@ public final class Checker implements RelatedClassLookup, Constants {
public static enum Option {
FAIL_ON_MISSING_CLASSES,
FAIL_ON_VIOLATION,
FAIL_ON_UNRESOLVABLE_SIGNATURES
FAIL_ON_UNRESOLVABLE_SIGNATURES,
DISABLE_CLASSLOADING_CACHE
}

public final boolean isSupportedJDK;
Expand Down Expand Up @@ -285,6 +286,9 @@ private ClassSignature getClassFromClassLoader(final String clazz) throws ClassN
if (url != null) {
final URLConnection conn = url.openConnection();
final boolean isRuntimeClass = isRuntimeClass(conn);
if (!isRuntimeClass && options.contains(Option.DISABLE_CLASSLOADING_CACHE)) {
conn.setUseCaches(false);
}
final InputStream in = conn.getInputStream();
try {
classpathClassCache.put(clazz, c = new ClassSignature(AsmUtils.readAndPatchClass(in), isRuntimeClass, false));
Expand Down
14 changes: 14 additions & 0 deletions src/main/java/de/thetaphi/forbiddenapis/ant/AntTask.java
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ public class AntTask extends Task implements Constants {
private boolean failOnViolation = true;
private boolean ignoreEmptyFileset = false;
private String targetVersion = null;
private boolean disableClassloadingCache = false;

@Override
public void execute() throws BuildException {
Expand Down Expand Up @@ -109,6 +110,7 @@ public void info(String msg) {
if (failOnMissingClasses) options.add(FAIL_ON_MISSING_CLASSES);
if (failOnViolation) options.add(FAIL_ON_VIOLATION);
if (failOnUnresolvableSignatures) options.add(FAIL_ON_UNRESOLVABLE_SIGNATURES);
if (disableClassloadingCache) options.add(DISABLE_CLASSLOADING_CACHE);
final Checker checker = new Checker(log, loader, options);

if (!checker.isSupportedJDK) {
Expand Down Expand Up @@ -380,4 +382,16 @@ public void setFailOnViolation(boolean failOnViolation) {
public void setTargetVersion(String targetVersion) {
this.targetVersion = targetVersion;
}

/**
* Disable the internal JVM classloading cache when getting bytecode from
* the classpath. This setting slows down checks, but <em>may</em> work around
* issues with other tasks, that do not close their class loaders.
* If you get {@code FileNotFoundException}s related to non-existent JAR entries
* you can try to work around using this setting.
* The default is {@code false}.
*/
public void setDisableClassloadingCache(boolean disableClassloadingCache) {
this.disableClassloadingCache = disableClassloadingCache;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,27 @@ public void setIgnoreFailures(boolean ignoreFailures) {
data.ignoreFailures = ignoreFailures;
}

/**
* Disable the internal JVM classloading cache when getting bytecode from
* the classpath. This setting slows down checks, but <em>may</em> work around
* issues with other plugin, that do not close their class loaders.
* If you get {@code FileNotFoundException}s related to non-existent JAR entries
* you can try to work around using this setting.
* <p>
* The default is {@code false}, unless the plugin detects that your build is
* running in the <em>Gradle Daemon</em> (which has this problem), setting the
* default to {@code true} as a consequence.
*/
@Input
public boolean getDisableClassloadingCache() {
return data.disableClassloadingCache;
}

/** @see #getDisableClassloadingCache */
public void setDisableClassloadingCache(boolean disableClassloadingCache) {
data.disableClassloadingCache = disableClassloadingCache;
}

/**
* List of a custom Java annotations (full class names) that are used in the checked
* code to suppress errors. Those annotations must have at least
Expand Down Expand Up @@ -483,6 +504,7 @@ public void info(String msg) {
if (getFailOnMissingClasses()) options.add(FAIL_ON_MISSING_CLASSES);
if (!getIgnoreFailures()) options.add(FAIL_ON_VIOLATION);
if (getFailOnUnresolvableSignatures()) options.add(FAIL_ON_UNRESOLVABLE_SIGNATURES);
if (getDisableClassloadingCache()) options.add(DISABLE_CLASSLOADING_CACHE);
final Checker checker = new Checker(log, loader, options);

if (!checker.isSupportedJDK) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ public class CheckForbiddenApisExtension {
"failOnUnsupportedJava",
"failOnMissingClasses",
"failOnUnresolvableSignatures",
"ignoreFailures"
"ignoreFailures",
"disableClassloadingCache"
);

public FileCollection signaturesFiles; // initialized by plugin-init.groovy
Expand All @@ -56,6 +57,7 @@ public class CheckForbiddenApisExtension {
public boolean failOnUnsupportedJava = false,
failOnMissingClasses = true,
failOnUnresolvableSignatures = true,
ignoreFailures = false;
ignoreFailures = false,
disableClassloadingCache = false;

}
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,17 @@ public abstract class AbstractCheckMojo extends AbstractMojo implements Constant
@Parameter(required = false, property="forbiddenapis.failOnViolation", defaultValue = "true")
private boolean failOnViolation;

/**
* Disable the internal JVM classloading cache when getting bytecode from
* the classpath. This setting slows down checks, but <em>may</em> work around
* issues with other Mojos, that do not close their class loaders.
* If you get {@code FileNotFoundException}s related to non-existent JAR entries
* you can try to work around using this setting.
* @since 2.0
*/
@Parameter(required = false, defaultValue = "false")
private boolean disableClassloadingCache;

/**
* The default compiler target version used to expand references to bundled JDK signatures.
* E.g., if you use "jdk-deprecated", it will expand to this version.
Expand Down Expand Up @@ -312,6 +323,7 @@ public void info(String msg) {
if (failOnMissingClasses) options.add(FAIL_ON_MISSING_CLASSES);
if (failOnViolation) options.add(FAIL_ON_VIOLATION);
if (failOnUnresolvableSignatures) options.add(FAIL_ON_UNRESOLVABLE_SIGNATURES);
if (disableClassloadingCache) options.add(DISABLE_CLASSLOADING_CACHE);
final Checker checker = new Checker(log, loader, options);

if (!checker.isSupportedJDK) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,19 @@ if (project.plugins.withType(JavaBasePlugin.class).isEmpty()) {
throw new PluginInstantiationException('Forbidden-apis only works in projects using the java plugin.');
}

// chck if running in Gradle Daemon?
// see: http://stackoverflow.com/questions/23265217/how-to-know-whether-you-are-running-inside-a-gradle-daemon
boolean isGradleDaemon = System.getProperty('sun.java.command', '').startsWith('org.gradle.launcher.daemon.') ||
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have you checked this in any other JVMs like openjdk or ibm?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The second part with stack trace should hit on any JVM. The first check is just a shortcut.

Thread.currentThread().stackTrace.any { it.className.startsWith 'org.gradle.launcher.daemon.' };
if (isGradleDaemon) {
project.logger.info('You are running forbidden-apis in the Gradle Daemon; disabling classloading cache to work around resource leak.');
}

// create Extension for defaults:
def extension = project.extensions.create(FORBIDDEN_APIS_EXTENSION_NAME, CheckForbiddenApisExtension.class);
extension.with {
signaturesFiles = project.files();
disableClassloadingCache |= isGradleDaemon;
}

// Define our tasks (one for each SourceSet):
Expand Down