diff --git a/build.xml b/build.xml index e8f51142..c1e03a79 100644 --- a/build.xml +++ b/build.xml @@ -466,14 +466,14 @@ - + - - + + @@ -482,11 +482,11 @@ - + - - - + + + diff --git a/src/main/docs/ant-task.html b/src/main/docs/ant-task.html index 2b070acc..ed68ab9f 100644 --- a/src/main/docs/ant-task.html +++ b/src/main/docs/ant-task.html @@ -151,6 +151,15 @@

Parameters

pattern may be used (e.g., **.SuppressForbidden). + + targetVersion + String + + The 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 when invoking javac. + +

Parameters specified as nested elements

@@ -165,8 +174,8 @@

Parameters specified as nested elements

To pass in signatures, you have several possibilities:

    -
  • Use bundledSignatures element to pass a built-in signatures file, e.g. <bundledsignatures name="jdk-unsafe-1.7"/>
  • -
  • Use signatures element to wrap any valid Ant resource type (filesets,..). May also be used to wrap <bundled name="jdk-unsafe-1.7"/>
  • +
  • Use bundledSignatures element to pass a built-in signatures file, e.g. <bundledsignatures name="jdk-unsafe" targetVersion="1.7"/>
  • +
  • Use signatures element to wrap any valid Ant resource type (filesets,..). May also be used to wrap <bundled name="jdk-unsafe" targetVersion="1.7"/>
  • Alternatively, use signaturesFileSet, signaturesFileList, signaturesFile elements to pass in collections of signatures files. Those elements behave like the corresponding standard Ant types.
  • Place signatures as plain text (use CDATA sections) inside the forbiddenapis element.
diff --git a/src/main/java/de/thetaphi/forbiddenapis/Checker.java b/src/main/java/de/thetaphi/forbiddenapis/Checker.java index fe622272..d0dee8f1 100644 --- a/src/main/java/de/thetaphi/forbiddenapis/Checker.java +++ b/src/main/java/de/thetaphi/forbiddenapis/Checker.java @@ -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; @@ -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); @@ -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) { diff --git a/src/main/java/de/thetaphi/forbiddenapis/Constants.java b/src/main/java/de/thetaphi/forbiddenapis/Constants.java index 2f3cd661..616fff06 100644 --- a/src/main/java/de/thetaphi/forbiddenapis/Constants.java +++ b/src/main/java/de/thetaphi/forbiddenapis/Constants.java @@ -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); diff --git a/src/main/java/de/thetaphi/forbiddenapis/ant/AntTask.java b/src/main/java/de/thetaphi/forbiddenapis/ant/AntTask.java index d83efb4b..48bf2c65 100644 --- a/src/main/java/de/thetaphi/forbiddenapis/ant/AntTask.java +++ b/src/main/java/de/thetaphi/forbiddenapis/ant/AntTask.java @@ -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 { @@ -132,7 +133,19 @@ public void info(String msg) { if (name == null) { throw new BuildException(" 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); @@ -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; + } } diff --git a/src/main/java/de/thetaphi/forbiddenapis/ant/BundledSignaturesType.java b/src/main/java/de/thetaphi/forbiddenapis/ant/BundledSignaturesType.java index c4f38176..61133cf2 100644 --- a/src/main/java/de/thetaphi/forbiddenapis/ant/BundledSignaturesType.java +++ b/src/main/java/de/thetaphi/forbiddenapis/ant/BundledSignaturesType.java @@ -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; @@ -30,4 +31,12 @@ public String getName() { return name; } + public void setTargetVersion(String targetVersion) { + this.targetVersion = targetVersion; + } + + public String getTargetVersion() { + return targetVersion; + } + } diff --git a/src/test/antunit/TestCommonsIOSignatures.xml b/src/test/antunit/TestCommonsIOSignatures.xml index 0da0b7c9..9fdcda65 100644 --- a/src/test/antunit/TestCommonsIOSignatures.xml +++ b/src/test/antunit/TestCommonsIOSignatures.xml @@ -32,7 +32,7 @@ - +
\ No newline at end of file diff --git a/src/test/antunit/TestDeprecatedTask.xml b/src/test/antunit/TestDeprecatedTask.xml index 40251e7e..c58e8b13 100644 --- a/src/test/antunit/TestDeprecatedTask.xml +++ b/src/test/antunit/TestDeprecatedTask.xml @@ -19,10 +19,10 @@ - + - - + + diff --git a/src/test/antunit/TestFileSignatures.xml b/src/test/antunit/TestFileSignatures.xml index 8c92c95e..3bc68c5a 100644 --- a/src/test/antunit/TestFileSignatures.xml +++ b/src/test/antunit/TestFileSignatures.xml @@ -59,12 +59,12 @@ - + java.util.Locale#ENGLISH @ We are speaking chinese here! - + diff --git a/src/test/antunit/TestFinalJAR.xml b/src/test/antunit/TestFinalJAR.xml index a633fe3f..d841615f 100644 --- a/src/test/antunit/TestFinalJAR.xml +++ b/src/test/antunit/TestFinalJAR.xml @@ -19,10 +19,10 @@ - + - - + + @@ -30,9 +30,9 @@ - - - + + + @@ -40,6 +40,7 @@ + @@ -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! --> - + - - + + diff --git a/src/test/antunit/TestInternalRuntimeCalls.xml b/src/test/antunit/TestInternalRuntimeCalls.xml index 95dafb56..41b7cf6a 100644 --- a/src/test/antunit/TestInternalRuntimeCalls.xml +++ b/src/test/antunit/TestInternalRuntimeCalls.xml @@ -22,7 +22,7 @@ - + @@ -45,9 +45,9 @@ - + - + diff --git a/src/test/antunit/TestJava6Reflection.xml b/src/test/antunit/TestJava6Reflection.xml index 09e932f1..cd4fb87b 100644 --- a/src/test/antunit/TestJava6Reflection.xml +++ b/src/test/antunit/TestJava6Reflection.xml @@ -18,7 +18,7 @@ - + diff --git a/src/test/java/de/thetaphi/forbiddenapis/CheckerStaticTest.java b/src/test/java/de/thetaphi/forbiddenapis/CheckerStaticTest.java new file mode 100644 index 00000000..a9e210dc --- /dev/null +++ b/src/test/java/de/thetaphi/forbiddenapis/CheckerStaticTest.java @@ -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 + } + } + +}