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

Prepare forbiddenapis 3.0: Update to Java 7 minimum version #160

Merged
merged 11 commits into from
Apr 6, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 15 additions & 27 deletions build.xml
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@
</condition>
</fail>

<fail message="Minimum supported Java version is 1.6.">
<fail message="Minimum supported Java version is 1.7.">
<condition>
<not><hasmethod classname="java.lang.String" method="isEmpty"/></not>
<not><available classname="java.lang.invoke.MethodHandle"/></not>
</condition>
</fail>

Expand All @@ -54,7 +54,6 @@
-->
<condition property="build.java.runtime" value="${-cleaned.specification.version}" else="unknown">
<or>
<equals arg1="${-cleaned.specification.version}" arg2="1.6"/>
<equals arg1="${-cleaned.specification.version}" arg2="1.7"/>
<equals arg1="${-cleaned.specification.version}" arg2="1.8"/>
<equals arg1="${-cleaned.specification.version}" arg2="9"/>
Expand All @@ -68,9 +67,8 @@

<property name="build.java.info" value="${java.version} / JVM: ${java.vm.name} / Vendor: ${java.vendor} / OS: ${os.name} (${os.version})"/>

<condition property="is.java-6-7">
<condition property="is.java7">
<or>
<equals arg1="${build.java.runtime}" arg2="1.6"/>
<equals arg1="${build.java.runtime}" arg2="1.7"/>
</or>
</condition>
Expand All @@ -79,7 +77,7 @@
<condition property="build.compiler" value="javac1.7">
<and>
<not>
<isset property="is.java-6-7"/>
<isset property="is.java7"/>
</not>
<or>
<antversion exactly="1.8.3" />
Expand All @@ -88,19 +86,19 @@
</and>
</condition>

<!-- With Java 6 and Java 7, the HTTPS access to Maven central is broken, workaround (no TLS 1.2 support): -->
<!-- With Java 7, the HTTPS access to Maven central is broken, workaround (no TLS 1.2 support): -->
<condition property="ivy.maven-central.backup" value="http://insecure.repo1.maven.org/maven2" else="https://repo1.maven.org/maven2">
<isset property="is.java-6-7"/>
<isset property="is.java7"/>
</condition>

<condition property="javadoc.doclint.args" value="" else="-Xdoclint:none">
<isset property="is.java-6-7"/>
<isset property="is.java7"/>
</condition>

<property file="${user.home}/build.properties" />
<property file="build.properties" />

<property name="jdk.version" value="1.6"/>
<property name="jdk.version" value="1.7"/>
<property name="maven.version" value="2.2.1"/>
<property name="maven-plugin-plugin.version" value="3.4"/>

Expand All @@ -126,7 +124,7 @@
<!-- define Maven coordinates -->
<property name="groupId" value="de.thetaphi" />
<property name="artifactId" value="forbiddenapis" />
<property name="version" value="2.8-SNAPSHOT"/>
<property name="version" value="3.0-SNAPSHOT"/>

<property name="description" value="Allows to parse Java byte code to find invocations of method/class/field signatures and fail build (Apache Ant, Apache Maven, Gradle, or CLI)"/>

Expand All @@ -148,14 +146,14 @@

<condition property="tests.supported">
<or>
<equals arg1="${build.java.runtime}" arg2="1.6"/>
<equals arg1="${build.java.runtime}" arg2="1.7"/>
<equals arg1="${build.java.runtime}" arg2="1.8"/>
<equals arg1="${build.java.runtime}" arg2="9"/>
<equals arg1="${build.java.runtime}" arg2="10"/>
<equals arg1="${build.java.runtime}" arg2="11"/>
<equals arg1="${build.java.runtime}" arg2="12"/>
<equals arg1="${build.java.runtime}" arg2="13"/>
<equals arg1="${build.java.runtime}" arg2="14"/>
</or>
</condition>

Expand Down Expand Up @@ -195,10 +193,10 @@
<echo level="info" taskname="check-java" message="Java runtime: ${build.java.info}"/>
<local name="java.version-message"/>
<condition property="java.version-message"
value="Java 6 and Java 7 do not support TLS 1.2, so we have to use the insecure Maven Central mirror. If you are building a release, please run the build at least once with Java 8+ to download all Artifacts using HTTPS. If you don't yet have the Gradle Artifacts downloaded, you have to do this anyways."
value="Java 7 does not support TLS 1.2, so we have to use the insecure Maven Central mirror. If you are building a release, please run the build at least once with Java 8+ to download all Artifacts using HTTPS. If you don't yet have the Gradle Artifacts downloaded, you have to do this anyways."
else="You are using Java 8+, so wecan use the HTTPS Maven Repository for downloading artifacts."
>
<isset property="is.java-6-7"/>
<isset property="is.java7"/>
</condition>
<echo level="warn" taskname="check-java" message="${java.version-message}"/>
<ivy:configure file="ivy-settings.xml"/>
Expand Down Expand Up @@ -687,9 +685,6 @@
<condition property="-gen.sunmisc">
<available classname="sun.misc.BASE64Encoder"/>
</condition>
<condition property="-gen.jdk7">
<available classname="java.lang.invoke.MethodHandle"/>
</condition>
<condition property="-gen.jdk8">
<hasmethod classname="java.util.Collections" method="emptySortedSet"/>
</condition>
Expand All @@ -699,20 +694,13 @@
<echo level="info" message="Generating test classes using sun.misc internal APIs (needs Oracle Java):"/>
<delete dir="src/test/antunit" includes="Oracle*.class"/>
<javac includeantruntime="false" srcdir="src/test/antunit" destdir="src/test/antunit" includes="Oracle*.java"
nowarn="true" source="1.6" target="1.6" debug="true" deprecation="false" encoding="${build.encoding}">
nowarn="true" source="1.7" target="1.7" debug="true" deprecation="false" encoding="${build.encoding}">
<!-- This disables the symbol file used to detect internal APIs while compiling: -->
<compilerarg value="-XDignore.symbol.file=true"/>
</javac>
</target>

<target name="-generate-test-classes-jdk6">
<echo level="info" message="Generating test classes for Java 6:"/>
<delete dir="src/test/antunit" includes="Java6*.class"/>
<javac includeantruntime="false" srcdir="src/test/antunit" destdir="src/test/antunit" includes="Java6*.java"
nowarn="true" source="1.6" target="1.6" debug="true" deprecation="false" encoding="${build.encoding}"/>
</target>

<target name="-generate-test-classes-jdk7" if="-gen.jdk7">
<target name="-generate-test-classes-jdk7">
<echo level="info" message="Generating test classes for Java 7:"/>
<delete dir="src/test/antunit" includes="Java7*.class"/>
<javac includeantruntime="false" srcdir="src/test/antunit" destdir="src/test/antunit" includes="Java7*.java"
Expand All @@ -726,7 +714,7 @@
nowarn="true" source="1.8" target="1.8" debug="true" deprecation="false" encoding="${build.encoding}"/>
</target>

<target name="generate-test-classes" depends="-generate-test-classes-init,-generate-test-classes-sunmisc,-generate-test-classes-jdk6,-generate-test-classes-jdk7,-generate-test-classes-jdk8"
<target name="generate-test-classes" depends="-generate-test-classes-init,-generate-test-classes-sunmisc,-generate-test-classes-jdk7,-generate-test-classes-jdk8"
description="Regenerates .class files used by tests if the current JDK version supports it"/>

<target name="show-help-mojo" depends="install-maven-artifacts" description="Shows help about mojo usage">
Expand Down
2 changes: 1 addition & 1 deletion ivy-settings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
<ibiblio name="gradle" root="https://repo.gradle.org/gradle/libs-releases-local" m2compatible="true" />
<ibiblio name="maven-http-backup" root="${ivy.maven-central.backup}" m2compatible="true" />
<chain name="default" returnFirst="true" checkmodified="true" changingPattern=".*SNAPSHOT">
<resolver ref="maven-http-backup" /><!-- use HTTP with Java 6/7 -->
<resolver ref="maven-http-backup" /><!-- use HTTP with Java 7 -->
<resolver ref="gradle" />
</chain>
</resolvers>
Expand Down
6 changes: 3 additions & 3 deletions src/main/docs/bundled-signatures.html
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,14 @@ <h1>Bundled Signatures Documentation</h1>
<li><strong><tt>jdk-unsafe-*</tt>:</strong> Signatures
of &quot;unsafe&quot; methods that use default charset, default locale, or default timezone. For server applications it is very
stupid to call those methods, as the results will definitely not what the user wants
(for Java <tt>*</tt> = 1.6, 1.7, 1.8, 9, 10, 11, 12, 13, 14; Ant / Maven / Gradle automatically add the compile Java version).</li>
(for Java <tt>*</tt> = 1.7, 1.8, 9, 10, 11, 12, 13, 14; Ant / Maven / Gradle automatically add the compile Java version).</li>

<li><strong><tt>jdk-deprecated-*</tt>:</strong> This disallows all deprecated
methods from the JDK (for Java <tt>*</tt> = 1.6, 1.7, 1.8, 9, 10, 11, 12, 13, 14; Ant / Maven / Gradle automatically add the compile Java version).</li>
methods from the JDK (for Java <tt>*</tt> = 1.7, 1.8, 9, 10, 11, 12, 13, 14; Ant / Maven / Gradle automatically add the compile Java version).</li>

<li><strong><tt>jdk-internal-*</tt>:</strong> Lists all internal packages of the JDK as of <code>Security.getProperty(&quot;package.access&quot;)</code>.
Calling those methods will always trigger security manager and is completely forbidden from Java 9 on
(for Java <tt>*</tt> = 1.6, 1.7, 1.8, 9, 10, 11, 12, 13, 14; Ant / Maven / Gradle automatically add the compile Java version, <em>since forbiddenapis v2.1</em>).</li>
(for Java <tt>*</tt> = 1.7, 1.8, 9, 10, 11, 12, 13, 14; Ant / Maven / Gradle automatically add the compile Java version, <em>since forbiddenapis v2.1</em>).</li>

<li><strong><tt>jdk-non-portable</tt>:</strong> Signatures of all non-portable (like <code>com.sun.management.HotSpotDiagnosticMXBean</code>)
or internal runtime APIs (like <code>sun.misc.Unsafe</code>). This is a superset of <tt>jdk-internal</tt>.<br>
Expand Down
3 changes: 1 addition & 2 deletions src/main/java/de/thetaphi/forbiddenapis/AsmUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -162,8 +162,7 @@ private static void patchClassMajorVersion(byte[] bytecode, int versionFrom, int
}
}

/** This method is used to read the whole stream into byte array. This allows patching.
* It also works around a bug in ASM 6.1 (https://gitlab.ow2.org/asm/asm/issues/317816). */
/** This method is used to read the whole stream into byte array. This allows patching. */
private static byte[] readStream(final InputStream in) throws IOException {
final ByteArrayOutputStream bos = new ByteArrayOutputStream();
final byte[] data = new byte[4096];
Expand Down
25 changes: 9 additions & 16 deletions src/main/java/de/thetaphi/forbiddenapis/Checker.java
Original file line number Diff line number Diff line change
Expand Up @@ -69,14 +69,14 @@ public static enum Option {
final EnumSet<Option> options;

/** Classes to check: key is the binary name (dotted) */
final Map<String,ClassSignature> classesToCheck = new HashMap<String,ClassSignature>();
final Map<String,ClassSignature> classesToCheck = new HashMap<>();
/** Cache of loaded classes: key is the binary name (dotted) */
final Map<String,ClassSignature> classpathClassCache = new HashMap<String,ClassSignature>();
final Map<String,ClassSignature> classpathClassCache = new HashMap<>();

final Signatures forbiddenSignatures;

/** descriptors (not internal names) of all annotations that suppress */
final Set<String> suppressAnnotations = new LinkedHashSet<String>();
final Set<String> suppressAnnotations = new LinkedHashSet<>();

public Checker(Logger logger, ClassLoader loader, Option... options) {
this(logger, loader, (options.length == 0) ? EnumSet.noneOf(Option.class) : EnumSet.copyOf(Arrays.asList(options)));
Expand Down Expand Up @@ -106,7 +106,7 @@ public Checker(Logger logger, ClassLoader loader, EnumSet<Option> options) {
this.method_Class_getModule = method_Class_getModule;
this.method_Module_getName = method_Module_getName;

final NavigableSet<String> runtimePaths = new TreeSet<String>();
final NavigableSet<String> runtimePaths = new TreeSet<>();

// fall back to legacy behavior:
if (!isSupportedJDK) {
Expand All @@ -124,8 +124,8 @@ public Checker(Logger logger, ClassLoader loader, EnumSet<Option> options) {
}
runtimePaths.add(javaHome);
}
// Scan the runtime's bootclasspath, too! This is needed because
// Apple's JDK 1.6 has the main rt.jar outside ${java.home}!
// Scan the runtime's bootclasspath, too! This is needed for
// some JDKs that may have the rt.jar outside ${java.home}!
final RuntimeMXBean rb = ManagementFactory.getRuntimeMXBean();
if (rb.isBootClassPathSupported()) {
final String cp = rb.getBootClassPath();
Expand Down Expand Up @@ -247,9 +247,8 @@ public ClassSignature getClassFromClassLoader(final String clazz) throws ClassNo
if (!isRuntimeClass && options.contains(Option.DISABLE_CLASSLOADING_CACHE)) {
conn.setUseCaches(false);
}
final InputStream in = conn.getInputStream();
final ClassReader cr;
try {
try (final InputStream in = conn.getInputStream()) {
cr = AsmUtils.readAndPatchClass(in);
} catch (IllegalArgumentException iae) {
// if class is too new for this JVM, we try to load it as Class<?> via Jigsaw
Expand All @@ -261,12 +260,9 @@ public ClassSignature getClassFromClassLoader(final String clazz) throws ClassNo
return c;
}
}
// unfortunately the ASM IAE has no message, so add good info!
throw new IllegalArgumentException(String.format(Locale.ENGLISH,
"The class file format of '%s' (loaded from location '%s') is too recent to be parsed by ASM.",
clazz, url.toExternalForm()));
} finally {
in.close();
}
final ClassSignature c = new ClassSignature(cr, isRuntimeClass, false);
classpathClassCache.put(clazz, c);
Expand Down Expand Up @@ -348,14 +344,11 @@ public boolean hasNoSignatures() {
/** Parses and adds a class from the given stream to the list of classes to check. Closes the stream when parsed (on Exception, too)! Does not log anything. */
public void addClassToCheck(final InputStream in, String name) throws IOException {
final ClassReader reader;
try {
reader = AsmUtils.readAndPatchClass(in);
try (final InputStream in_ = in) {
reader = AsmUtils.readAndPatchClass(in_);
} catch (IllegalArgumentException iae) {
// unfortunately the ASM IAE has no message, so add good info!
throw new IllegalArgumentException(String.format(Locale.ENGLISH,
"The class file format of '%s' is too recent to be parsed by ASM.", name));
} finally {
in.close();
}
final String binaryName = Type.getObjectType(reader.getClassName()).getClassName();
classesToCheck.put(binaryName, new ClassSignature(reader, false, true));
Expand Down
6 changes: 3 additions & 3 deletions src/main/java/de/thetaphi/forbiddenapis/ClassScanner.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
public final class ClassScanner extends ClassVisitor implements Constants {
private final boolean forbidNonPortableRuntime;
final RelatedClassLookup lookup;
final List<ForbiddenViolation> violations = new ArrayList<ForbiddenViolation>();
final List<ForbiddenViolation> violations = new ArrayList<>();

final Signatures forbiddenSignatures;

Expand All @@ -57,7 +57,7 @@ public final class ClassScanner extends ClassVisitor implements Constants {
int currentGroupId = 0;

// Mapping from a (possible) lambda Method to groupId of declaring method
final Map<Method,Integer> lambdas = new HashMap<Method,Integer>();
final Map<Method,Integer> lambdas = new HashMap<>();

// all groups that were disabled due to suppressing annotation
final BitSet suppressedGroups = new BitSet();
Expand Down Expand Up @@ -156,7 +156,7 @@ String checkType(Type type) {
type = type.getElementType();
break;
case Type.METHOD:
final ArrayList<String> violations = new ArrayList<String>();
final ArrayList<String> violations = new ArrayList<>();
violation = checkType(type.getReturnType());
if (violation != null) {
violations.add(violation);
Expand Down
12 changes: 6 additions & 6 deletions src/main/java/de/thetaphi/forbiddenapis/ClassSignature.java
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,9 @@ public ClassSignature(final ClassReader classReader, boolean isRuntimeClass, boo
this.className = classReader.getClassName();
this.superName = classReader.getSuperName();
this.interfaces = classReader.getInterfaces();
final Set<Method> methods = new HashSet<Method>();
final Set<String> fields = new HashSet<String>();
final Set<String> signaturePolymorphicMethods = new HashSet<String>();
final Set<Method> methods = new HashSet<>();
final Set<String> fields = new HashSet<>();
final Set<String> signaturePolymorphicMethods = new HashSet<>();
classReader.accept(new ClassVisitor(Opcodes.ASM8) {
@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
Expand Down Expand Up @@ -90,9 +90,9 @@ public ClassSignature(final Class<?> clazz, boolean isRuntimeClass) {
for (int i = 0; i < interfClasses.length; i++) {
this.interfaces[i] = Type.getType(interfClasses[i]).getInternalName();
}
final Set<Method> methods = new HashSet<Method>();
final Set<String> fields = new HashSet<String>();
final Set<String> signaturePolymorphicMethods = new HashSet<String>();
final Set<Method> methods = new HashSet<>();
final Set<String> fields = new HashSet<>();
final Set<String> signaturePolymorphicMethods = new HashSet<>();
for (final java.lang.reflect.Method m : clazz.getDeclaredMethods()) {
methods.add(Method.getMethod(m));
if (className.startsWith(SIGNATURE_POLYMORPHIC_PKG_INTERNALNAME) &&
Expand Down
15 changes: 6 additions & 9 deletions src/main/java/de/thetaphi/forbiddenapis/Signatures.java
Original file line number Diff line number Diff line change
Expand Up @@ -86,10 +86,10 @@ private UnresolvableReporting(boolean reportClassNotFound) {
* <li>classes: key is the internal name (slashed)
* </ul>
*/
final Map<String,String> signatures = new HashMap<String,String>();
final Map<String,String> signatures = new HashMap<>();

/** set of patterns of forbidden classes */
final Set<ClassPatternRule> classPatterns = new LinkedHashSet<ClassPatternRule>();
final Set<ClassPatternRule> classPatterns = new LinkedHashSet<>();

/** if enabled, the bundled signature to enable heuristics for detection of non-portable runtime calls is used */
private boolean forbidNonPortableRuntime = false;
Expand Down Expand Up @@ -261,8 +261,7 @@ private void parseSignaturesStream(InputStream in, boolean allowBundled, Set<Str
}

private void parseSignaturesFile(Reader reader, boolean isBundled, Set<String> missingClasses) throws IOException,ParseException {
final BufferedReader r = new BufferedReader(reader);
try {
try (final BufferedReader r = new BufferedReader(reader)) {
String line, defaultMessage = null;
UnresolvableReporting reporter = failOnUnresolvableSignatures ? UnresolvableReporting.FAIL : UnresolvableReporting.WARNING;
while ((line = r.readLine()) != null) {
Expand All @@ -285,30 +284,28 @@ private void parseSignaturesFile(Reader reader, boolean isBundled, Set<String> m
addSignature(line, defaultMessage, reporter, missingClasses);
}
}
} finally {
r.close();
}
}

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

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

/** Reads a list of API signatures from a String. */
public void parseSignaturesString(String signatures) throws IOException,ParseException {
logger.info("Reading inline API signatures...");
final Set<String> missingClasses = new TreeSet<String>();
final Set<String> missingClasses = new TreeSet<>();
parseSignaturesFile(new StringReader(signatures), false, missingClasses);
reportMissingSignatureClasses(missingClasses);
}
Expand Down
Loading