Skip to content

Commit

Permalink
Addon for #81: Better parsing and fixing of JDK versions to 1.x style.
Browse files Browse the repository at this point in the history
Add support for targetVersion in Ant task. This closes #101
  • Loading branch information
uschindler committed May 22, 2016
1 parent 49d3a7c commit 6f406dc
Show file tree
Hide file tree
Showing 13 changed files with 148 additions and 33 deletions.
14 changes: 7 additions & 7 deletions build.xml
Original file line number Diff line number Diff line change
Expand Up @@ -466,14 +466,14 @@
</target>

<target name="-check-myself" depends="compile,compile-tools,compile-test,-install-forbiddenapi-task">
<forbiddenapis failOnUnsupportedJava="false">
<forbiddenapis failOnUnsupportedJava="false" targetVersion="${jdk.version}">
<classpath refid="path.all"/>
<fileset dir="build/main"/>
<fileset dir="build/tools"/>
<fileset dir="build/test"/>
<signatures>
<bundled name="jdk-unsafe-${jdk.version}"/>
<bundled name="jdk-deprecated-${jdk.version}"/>
<bundled name="jdk-unsafe"/>
<bundled name="jdk-deprecated"/>
<bundled name="jdk-non-portable"/>
<bundled name="jdk-system-out"/>
<bundled name="jdk-reflection"/>
Expand All @@ -482,11 +482,11 @@
</target>

<target name="-check-bundled-signatures" depends="-install-forbiddenapi-task" if="tests.supported">
<forbiddenapis failOnUnsupportedJava="true" ignoreEmptyFileset="true">
<forbiddenapis failOnUnsupportedJava="true" ignoreEmptyFileset="true" targetVersion="${build.java.runtime}">
<signatures>
<bundled name="jdk-unsafe-${build.java.runtime}"/>
<bundled name="jdk-deprecated-${build.java.runtime}"/>
<bundled name="jdk-internal-${build.java.runtime}"/>
<bundled name="jdk-unsafe"/>
<bundled name="jdk-deprecated"/>
<bundled name="jdk-internal"/>
<bundled name="jdk-system-out"/>
<bundled name="jdk-reflection"/>
</signatures>
Expand Down
13 changes: 11 additions & 2 deletions src/main/docs/ant-task.html
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,15 @@ <h2>Parameters</h2>
pattern may be used (e.g., <code>**.SuppressForbidden</code>).</td>
</tr>

<tr>
<td>targetVersion</td>
<td><code>String</code></td>
<td></td>
<td>The compiler target version used to expand references to bundled JDK signatures.
E.g., if you use &quot;jdk-deprecated&quot;, it will expand to this version.
This setting should be identical to the target version used when invoking <tt>javac</tt>.</td>
</tr>

</table>

<h2>Parameters specified as nested elements</h2>
Expand All @@ -165,8 +174,8 @@ <h2>Parameters specified as nested elements</h2>
<p>To pass in signatures, you have several possibilities:</p>

<ul>
<li>Use <code>bundledSignatures</code> element to pass a <a href="bundled-signatures.html">built-in signatures</a> file, e.g. <code>&lt;bundledsignatures name=&quot;jdk-unsafe-1.7&quot;/&gt;</code></li>
<li>Use <code>signatures</code> element to wrap any valid <a href="https://ant.apache.org/manual/Types/resources.html">Ant resource</a> type (filesets,..). May also be used to wrap <code>&lt;bundled name=&quot;jdk-unsafe-1.7&quot;/&gt;</code></li>
<li>Use <code>bundledSignatures</code> element to pass a <a href="bundled-signatures.html">built-in signatures</a> file, e.g. <code>&lt;bundledsignatures name=&quot;jdk-unsafe&quot; targetVersion=&quot;1.7&quot;/&gt;</code></li>
<li>Use <code>signatures</code> element to wrap any valid <a href="https://ant.apache.org/manual/Types/resources.html">Ant resource</a> type (filesets,..). May also be used to wrap <code>&lt;bundled name=&quot;jdk-unsafe&quot; targetVersion=&quot;1.7&quot;/&gt;</code></li>
<li>Alternatively, use <code>signaturesFileSet</code>, <code>signaturesFileList</code>, <code>signaturesFile</code> elements to pass in collections of signatures files. Those elements behave like the corresponding standard Ant types.</li>
<li>Place signatures as plain text (use CDATA sections) inside the <code>forbiddenapis</code> element.</li>
</ul>
Expand Down
25 changes: 21 additions & 4 deletions src/main/java/de/thetaphi/forbiddenapis/Checker.java
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
import java.util.Set;
import java.util.StringTokenizer;
import java.util.TreeSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.lang.annotation.Annotation;
import java.lang.management.ManagementFactory;
Expand Down Expand Up @@ -426,6 +427,24 @@ public void addBundledSignatures(String name, String jdkTargetVersion) throws IO
addBundledSignatures(name, jdkTargetVersion, true);
}

public static String fixTargetVersion(String name) throws ParseException {
final Matcher m = JDK_SIG_PATTERN.matcher(name);
if (m.matches()) {
if (m.group(4) == null) {
// rewrite version number if it does not start with "1"
if ("1".equals(m.group(2)) && m.group(3) != null) {
return name;
} else {
if (".0".equals(m.group(3)) || m.group(3) == null) {
return m.group(1) + "1." + m.group(2);
}
}
}
throw new ParseException("Invalid bundled signature reference (JDK version is invalid): " + name);
}
return name;
}

private void addBundledSignatures(String name, String jdkTargetVersion, boolean logging) throws IOException,ParseException {
if (!name.matches("[A-Za-z0-9\\-\\.]+")) {
throw new ParseException("Invalid bundled signature reference: " + name);
Expand All @@ -435,15 +454,13 @@ private void addBundledSignatures(String name, String jdkTargetVersion, boolean
forbidNonPortableRuntime = true;
return;
}
name = fixTargetVersion(name);
// use Checker.class hardcoded (not getClass) so we have a fixed package name:
InputStream in = Checker.class.getResourceAsStream("signatures/" + name + ".txt");
// automatically expand the compiler version in here (for jdk-* signatures without version):
if (in == null && jdkTargetVersion != null && name.startsWith("jdk-") && !name.matches(".*?\\-\\d\\.\\d")) {
// convert the "new" version number "major.0" to old-style "1.major" (as this matches our resources):
if (!jdkTargetVersion.startsWith("1.") && jdkTargetVersion.matches("\\d(\\.0|)")) {
jdkTargetVersion = "1." + jdkTargetVersion.substring(0, 1);
}
name = name + "-" + jdkTargetVersion;
name = fixTargetVersion(name);
in = Checker.class.getResourceAsStream("signatures/" + name + ".txt");
}
if (in == null) {
Expand Down
3 changes: 3 additions & 0 deletions src/main/java/de/thetaphi/forbiddenapis/Constants.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,14 @@
package de.thetaphi.forbiddenapis;

import java.util.Locale;
import java.util.regex.Pattern;

public interface Constants {

final String BS_JDK_NONPORTABLE = "jdk-non-portable";

final Pattern JDK_SIG_PATTERN = Pattern.compile("(jdk\\-.*?\\-)(\\d)(\\.\\d)?(\\.\\d)*");

final String DEPRECATED_WARN_INTERNALRUNTIME = String.format(Locale.ENGLISH,
"The setting 'internalRuntimeForbidden' was deprecated and will be removed in next version. For backwards compatibility task/mojo is using '%s' bundled signatures instead.", BS_JDK_NONPORTABLE);

Expand Down
25 changes: 24 additions & 1 deletion src/main/java/de/thetaphi/forbiddenapis/ant/AntTask.java
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ public class AntTask extends Task implements Constants {
private boolean failOnUnresolvableSignatures = true;
private boolean failOnViolation = true;
private boolean ignoreEmptyFileset = false;
private String targetVersion = null;

@Override
public void execute() throws BuildException {
Expand Down Expand Up @@ -132,7 +133,19 @@ public void info(String msg) {
if (name == null) {
throw new BuildException("<bundledSignatures/> must have the mandatory attribute 'name' referring to a bundled signatures file.");
}
checker.addBundledSignatures(name, null);
String targetVersion = this.targetVersion;
if (bs.getTargetVersion() != null) {
if (!name.startsWith("jdk-")) {
throw new ParseException("Cannot supply a targetVersion for non-JDK signatures.");
}
targetVersion = bs.getTargetVersion();
}
if (targetVersion == null && name.startsWith("jdk-")) {
log.warn("The 'targetVersion' parameter is missing. " +
"Trying to read bundled JDK signatures without compiler target. " +
"You have to explicitely specify the version in the resource name.");
}
checker.addBundledSignatures(name, targetVersion);
}
if (internalRuntimeForbidden) {
log.warn(DEPRECATED_WARN_INTERNALRUNTIME);
Expand Down Expand Up @@ -357,4 +370,14 @@ public void setIgnoreEmptyFileSet(boolean ignoreEmptyFileset) {
public void setFailOnViolation(boolean failOnViolation) {
this.failOnViolation = failOnViolation;
}

/**
* 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.
* This setting should be identical to the target version used in the compiler task.
* Defaults to {@code null}.
*/
public void setTargetVersion(String targetVersion) {
this.targetVersion = targetVersion;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
public final class BundledSignaturesType extends ProjectComponent {

private String name = null;
private String targetVersion = null;

public void setName(String name) {
this.name = name;
Expand All @@ -30,4 +31,12 @@ public String getName() {
return name;
}

public void setTargetVersion(String targetVersion) {
this.targetVersion = targetVersion;
}

public String getTargetVersion() {
return targetVersion;
}

}
2 changes: 1 addition & 1 deletion src/test/antunit/TestCommonsIOSignatures.xml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
<echo message="Testing signatures of version ${commons-io-version}..."/>
<ivy:cachepath organisation="commons-io" module="commons-io" revision="${commons-io-version}"
inline="true" conf="master" type="jar" pathid="commons-io.classpath" log="${ivy.logging}"/>
<forbiddenapis bundledSignatures="${commons-io-signature}" ignoreEmptyFileset="true" classpathref="commons-io.classpath"/>
<forbiddenapis bundledSignatures="${commons-io-signature}" ignoreEmptyFileset="true" classpathref="commons-io.classpath" targetVersion="${jdk.version}"/>
</target>

</project>
6 changes: 3 additions & 3 deletions src/test/antunit/TestDeprecatedTask.xml
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@
<taskdef name="forbiddenapis-deprecated" classname="de.thetaphi.forbiddenapis.AntTask" classpath="${jar-file}"/>

<target name="testMySelf">
<forbiddenapis-deprecated classpathref="path.all">
<forbiddenapis-deprecated classpathref="path.all" targetVersion="${jdk.version}">
<fileset dir="${antunit.main.classes}"/>
<bundledsignatures name="jdk-unsafe-${jdk.version}"/>
<bundledsignatures name="jdk-deprecated-${jdk.version}"/>
<bundledsignatures name="jdk-unsafe"/>
<bundledsignatures name="jdk-deprecated"/>
<bundledsignatures name="jdk-non-portable"/>
</forbiddenapis-deprecated>
<au:assertLogContains level="info" text=" 0 error(s)."/>
Expand Down
4 changes: 2 additions & 2 deletions src/test/antunit/TestFileSignatures.xml
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,12 @@

<target name="testGeneralResources">
<au:expectfailure expectedMessage="Check for forbidden API calls failed, see log">
<forbiddenapis classpathref="path.all">
<forbiddenapis classpathref="path.all" targetVersion="${jdk.version}">
<fileset refid="main.classes"/>
<signatures>
<file file="signatures1.txt"/>
<string>java.util.Locale#ENGLISH @ We are speaking chinese here!</string>
<bundled name="jdk-unsafe-${jdk.version}"/>
<bundled name="jdk-unsafe"/>
</signatures>
</forbiddenapis>
</au:expectfailure>
Expand Down
19 changes: 10 additions & 9 deletions src/test/antunit/TestFinalJAR.xml
Original file line number Diff line number Diff line change
Expand Up @@ -19,27 +19,28 @@
<taskdef name="forbiddenapis-jar" classname="de.thetaphi.forbiddenapis.ant.AntTask" classpath="${jar-file}"/>

<target name="testMySelfWithFinalJAR1">
<forbiddenapis-jar classpathref="path.all">
<forbiddenapis-jar classpathref="path.all" targetVersion="${jdk.version}">
<fileset dir="${antunit.main.classes}"/>
<bundledsignatures name="jdk-unsafe-${jdk.version}"/>
<bundledsignatures name="jdk-deprecated-${jdk.version}"/>
<bundledsignatures name="jdk-unsafe"/>
<bundledsignatures name="jdk-deprecated"/>
<bundledsignatures name="jdk-non-portable"/>
</forbiddenapis-jar>
<au:assertLogContains level="info" text=" 0 error(s)."/>
</target>

<target name="testMySelfWithFinalJAR2">
<forbiddenapis-jar dir="${antunit.main.classes}" classpathref="path.all">
<bundledsignatures name="jdk-unsafe-${jdk.version}"/>
<bundledsignatures name="jdk-deprecated-${jdk.version}"/>
<bundledsignatures name="jdk-non-portable"/>
<bundledsignatures name="jdk-unsafe" targetVersion="${jdk.version}"/>
<bundledsignatures name="jdk-deprecated" targetVersion="${jdk.version}"/>
<bundledsignatures name="jdk-non-portable" targetVersion="${jdk.version}"/>
</forbiddenapis-jar>
<au:assertLogContains level="info" text=" 0 error(s)."/>
</target>

<target name="testMySelfWithAntLib">
<taskdef uri="antlib:de.thetaphi.forbiddenapis" classpath="${jar-file}"/>
<fa:forbiddenapis xmlns:fa="antlib:de.thetaphi.forbiddenapis" dir="${antunit.main.classes}" classpathref="path.all">
<!-- here with hardcoded versions -->
<bundledsignatures name="jdk-unsafe-${jdk.version}"/>
<bundledsignatures name="jdk-deprecated-${jdk.version}"/>
<bundledsignatures name="jdk-non-portable"/>
Expand All @@ -55,10 +56,10 @@
only plexus-utils v1.1, which is much slimmer and does not reference
broken StringUtils. ASM is completely forbidden-api bug-free!
-->
<forbiddenapis-jar>
<forbiddenapis-jar targetVersion="${jdk.version}">
<zipfileset src="${jar-file}" excludes="de/thetaphi/forbiddenapis/commons/cli/**"/>
<bundledsignatures name="jdk-unsafe-${jdk.version}"/>
<bundledsignatures name="jdk-deprecated-${jdk.version}"/>
<bundledsignatures name="jdk-unsafe"/>
<bundledsignatures name="jdk-deprecated"/>
<bundledsignatures name="jdk-non-portable"/>
<classpath>
<pathelement path="${jar-file}"/>
Expand Down
6 changes: 3 additions & 3 deletions src/test/antunit/TestInternalRuntimeCalls.xml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@

<target name="testNonPortableSignatures" if="has.sunmisc">
<au:expectfailure expectedMessage="Check for forbidden API calls failed, see log">
<forbiddenapis failOnMissingClasses="false">
<forbiddenapis failOnMissingClasses="false" targetVersion="${jdk.version}">
<file file="OracleInternalRuntime.class"/>
<bundledsignatures name="jdk-non-portable"/>
</forbiddenapis>
Expand All @@ -45,9 +45,9 @@
<!-- this should work also with non-Oracle runtimes, as no heuristics: -->
<target name="testInternalSignatures">
<au:expectfailure expectedMessage="Check for forbidden API calls failed, see log">
<forbiddenapis failOnMissingClasses="false">
<forbiddenapis failOnMissingClasses="false" targetVersion="${jdk.version}">
<file file="OracleInternalRuntime.class"/>
<bundledsignatures name="jdk-internal-${jdk.version}"/>
<bundledsignatures name="jdk-internal"/>
</forbiddenapis>
</au:expectfailure>
<au:assertLogContains level="error" text="sun.misc.BASE64Encoder [non-public internal runtime class in Java ${jdk.version}]"/>
Expand Down
2 changes: 1 addition & 1 deletion src/test/antunit/TestJava6Reflection.xml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

<target name="testReflection">
<au:expectfailure expectedMessage="Check for forbidden API calls failed, see log">
<forbiddenapis>
<forbiddenapis targetVersion="${jdk.version}">
<bundledsignatures name="jdk-reflection"/>
<file file="Java6Reflection.class"/>
</forbiddenapis>
Expand Down
53 changes: 53 additions & 0 deletions src/test/java/de/thetaphi/forbiddenapis/CheckerStaticTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* (C) Copyright Uwe Schindler (Generics Policeman) and others.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package de.thetaphi.forbiddenapis;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;

import org.junit.Test;

public final class CheckerStaticTest {

@Test
public void testTragetVersionFix() throws Exception {
assertEquals("jdk-dummy-1.7", Checker.fixTargetVersion("jdk-dummy-1.7"));
assertEquals("jdk-dummy-1.7", Checker.fixTargetVersion("jdk-dummy-7"));
assertEquals("jdk-dummy-1.7", Checker.fixTargetVersion("jdk-dummy-7.0"));

assertEquals("jdk-dummy-1.1", Checker.fixTargetVersion("jdk-dummy-1"));
assertEquals("jdk-dummy-1.1", Checker.fixTargetVersion("jdk-dummy-1.1"));

assertFails("jdk-dummy-1.7.1");
assertFails("jdk-dummy-1.7.1.1");
assertFails("jdk-dummy-1.7.0.1");

assertFails("jdk-dummy-7.1");
assertFails("jdk-dummy-7.1.1");
assertFails("jdk-dummy-7.0.1");
}

private void assertFails(String name) {
try {
Checker.fixTargetVersion(name);
fail("Should fail for: " + name);
} catch (ParseException pe) {
// pass
}
}

}

0 comments on commit 6f406dc

Please sign in to comment.