LUCENE-10283: Bump minimum required Java version to 17. (#579)

Co-authored-by: Dawid Weiss <dawid.weiss@carrotsearch.com>
This commit is contained in:
Adrien Grand 2022-01-10 15:42:15 +01:00 committed by GitHub
parent 74698994a9
commit 2ebc57a465
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 128 additions and 100 deletions

View File

@ -21,7 +21,7 @@ jobs:
# Operating systems to run on. # Operating systems to run on.
os: [ubuntu-latest] os: [ubuntu-latest]
# Test JVMs. # Test JVMs.
java: [ '11' ] java: [ '17' ]
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
@ -65,7 +65,7 @@ jobs:
# macos-latest: a tad slower than ubuntu and pretty much the same (?) so leaving out. # macos-latest: a tad slower than ubuntu and pretty much the same (?) so leaving out.
os: [ubuntu-latest] os: [ubuntu-latest]
# Test JVMs. # Test JVMs.
java: [ '11' ] java: [ '17' ]
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2

View File

@ -39,16 +39,16 @@ comprehensive documentation, visit:
### Basic steps: ### Basic steps:
0. Install OpenJDK 11 (or greater). 0. Install OpenJDK 17 (or greater).
1. Clone Lucene's git repository (or download the source distribution). 1. Clone Lucene's git repository (or download the source distribution).
2. Run gradle launcher script (`gradlew`). 2. Run gradle launcher script (`gradlew`).
### Step 0) Set up your development environment (OpenJDK 11 or greater) ### Step 0) Set up your development environment (OpenJDK 17 or greater)
We'll assume that you know how to get and set up the JDK - if you We'll assume that you know how to get and set up the JDK - if you
don't, then we suggest starting at https://jdk.java.net/ and learning don't, then we suggest starting at https://jdk.java.net/ and learning
more about Java, before returning to this README. Lucene runs with more about Java, before returning to this README. Lucene runs with
Java 11 or later. Java 17 or later.
Lucene uses [Gradle](https://gradle.org/) for build control. Gradle is itself Java-based Lucene uses [Gradle](https://gradle.org/) for build control. Gradle is itself Java-based
and may be incompatible with newer Java versions; you can still build and test and may be incompatible with newer Java versions; you can still build and test

View File

@ -72,7 +72,7 @@ ext {
} }
// Minimum Java version required to compile and run Lucene. // Minimum Java version required to compile and run Lucene.
minJavaVersion = JavaVersion.VERSION_11 minJavaVersion = JavaVersion.VERSION_17
// snapshot build marker used in scripts. // snapshot build marker used in scripts.
snapshotBuild = version.contains("SNAPSHOT") snapshotBuild = version.contains("SNAPSHOT")

View File

@ -23,7 +23,7 @@ ext {
scriptDepVersions = [ scriptDepVersions = [
"apache-rat": "0.11", "apache-rat": "0.11",
"commons-codec": "1.13", "commons-codec": "1.13",
"ecj": "3.27.0", "ecj": "3.28.0",
"flexmark": "0.61.24", "flexmark": "0.61.24",
"javacc": "7.0.4", "javacc": "7.0.4",
"jflex": "1.8.2", "jflex": "1.8.2",

View File

@ -37,7 +37,7 @@ configure(project(":lucene").subprojects) { prj ->
lineEndings 'UNIX' lineEndings 'UNIX'
endWithNewline() endWithNewline()
googleJavaFormat('1.11.0') googleJavaFormat('1.13.0')
// Apply to all Java sources // Apply to all Java sources
target "src/**/*.java" target "src/**/*.java"

View File

@ -32,6 +32,9 @@ Bug Fixes
Other Other
--------------------- ---------------------
* LUCENE-10283: The minimum required Java version was bumped from 11 to 17.
(Adrien Grand, Uwe Schindler, Dawid Weiss, Robert Muir)
* LUCENE-10253: The @BadApple annotation has been removed from the test * LUCENE-10253: The @BadApple annotation has been removed from the test
framework. (Adrien Grand) framework. (Adrien Grand)

View File

@ -17,11 +17,11 @@
# System Requirements # System Requirements
Apache Lucene runs on Java 11 or greater. Apache Lucene runs on Java 17 or greater.
It is also recommended to always use the latest update version of your It is also recommended to always use the latest update version of your
Java VM, because bugs may affect Lucene. An overview of known JVM bugs Java VM, because bugs may affect Lucene. An overview of known JVM bugs
can be found on http://wiki.apache.org/lucene-java/JavaBugs can be found on https://cwiki.apache.org/confluence/display/LUCENE/JavaBugs
With all Java versions it is strongly recommended to not use experimental With all Java versions it is strongly recommended to not use experimental
`-XX` JVM options. `-XX` JVM options.

View File

@ -334,8 +334,7 @@ public class MMapDirectory extends FSDirectory {
private static final BufferCleaner CLEANER; private static final BufferCleaner CLEANER;
static { static {
final Object hack = final Object hack = doPrivileged(MMapDirectory::unmapHackImpl);
AccessController.doPrivileged((PrivilegedAction<Object>) MMapDirectory::unmapHackImpl);
if (hack instanceof BufferCleaner) { if (hack instanceof BufferCleaner) {
CLEANER = (BufferCleaner) hack; CLEANER = (BufferCleaner) hack;
UNMAP_SUPPORTED = true; UNMAP_SUPPORTED = true;
@ -348,6 +347,13 @@ public class MMapDirectory extends FSDirectory {
} }
} }
// Extracted to a method to be able to apply the SuppressForbidden annotation
@SuppressWarnings("removal")
@SuppressForbidden(reason = "security manager")
private static <T> T doPrivileged(PrivilegedAction<T> action) {
return AccessController.doPrivileged(action);
}
@SuppressForbidden(reason = "Needs access to sun.misc.Unsafe to enable hack") @SuppressForbidden(reason = "Needs access to sun.misc.Unsafe to enable hack")
private static Object unmapHackImpl() { private static Object unmapHackImpl() {
final Lookup lookup = lookup(); final Lookup lookup = lookup();
@ -390,16 +396,15 @@ public class MMapDirectory extends FSDirectory {
throw new IllegalArgumentException("unmapping only works with direct buffers"); throw new IllegalArgumentException("unmapping only works with direct buffers");
} }
final Throwable error = final Throwable error =
AccessController.doPrivileged( doPrivileged(
(PrivilegedAction<Throwable>) () -> {
() -> { try {
try { unmapper.invokeExact(buffer);
unmapper.invokeExact(buffer); return null;
return null; } catch (Throwable t) {
} catch (Throwable t) { return t;
return t; }
} });
});
if (error != null) { if (error != null) {
throw new IOException("Unable to unmap the mapped buffer: " + resourceDescription, error); throw new IOException("Unable to unmap the mapped buffer: " + resourceDescription, error);
} }

View File

@ -39,8 +39,7 @@ public class NamedThreadFactory implements ThreadFactory {
* @param threadNamePrefix the name prefix assigned to each thread created. * @param threadNamePrefix the name prefix assigned to each thread created.
*/ */
public NamedThreadFactory(String threadNamePrefix) { public NamedThreadFactory(String threadNamePrefix) {
final SecurityManager s = System.getSecurityManager(); group = getThreadGroup();
group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup();
this.threadNamePrefix = this.threadNamePrefix =
String.format( String.format(
Locale.ROOT, Locale.ROOT,
@ -49,6 +48,17 @@ public class NamedThreadFactory implements ThreadFactory {
threadPoolNumber.getAndIncrement()); threadPoolNumber.getAndIncrement());
} }
@SuppressWarnings("removal")
@SuppressForbidden(reason = "security manager")
private static ThreadGroup getThreadGroup() {
final SecurityManager s = System.getSecurityManager();
if (s != null) {
return s.getThreadGroup();
} else {
return Thread.currentThread().getThreadGroup();
}
}
private static String checkPrefix(String prefix) { private static String checkPrefix(String prefix) {
return prefix == null || prefix.length() == 0 ? "Lucene" : prefix; return prefix == null || prefix.length() == 0 ? "Lucene" : prefix;
} }

View File

@ -584,9 +584,10 @@ public final class RamUsageEstimator {
final Class<?> target = clazz; final Class<?> target = clazz;
final Field[] fields; final Field[] fields;
try { try {
fields = fields = doPrivileged((PrivilegedAction<Field[]>) target::getDeclaredFields);
AccessController.doPrivileged((PrivilegedAction<Field[]>) target::getDeclaredFields); } catch (
} catch (AccessControlException e) { @SuppressWarnings("removal")
AccessControlException e) {
throw new RuntimeException("Can't access fields of class: " + target, e); throw new RuntimeException("Can't access fields of class: " + target, e);
} }
@ -599,6 +600,13 @@ public final class RamUsageEstimator {
return alignObjectSize(size); return alignObjectSize(size);
} }
// Extracted to a method to give the SuppressForbidden annotation the smallest possible scope
@SuppressWarnings("removal")
@SuppressForbidden(reason = "security manager")
private static <T> T doPrivileged(PrivilegedAction<T> action) {
return AccessController.doPrivileged(action);
}
/** Return shallow size of any <code>array</code>. */ /** Return shallow size of any <code>array</code>. */
private static long shallowSizeOfArray(Object array) { private static long shallowSizeOfArray(Object array) {
long size = NUM_BYTES_ARRAY_HEADER; long size = NUM_BYTES_ARRAY_HEADER;

View File

@ -20,19 +20,15 @@ import java.io.IOException;
import org.apache.lucene.store.DataInput; import org.apache.lucene.store.DataInput;
import org.apache.lucene.store.DataOutput; import org.apache.lucene.store.DataOutput;
import org.apache.lucene.util.RamUsageEstimator; import org.apache.lucene.util.RamUsageEstimator;
import org.apache.lucene.util.SuppressForbidden;
/** /**
* An FST {@link Outputs} implementation where each output is a non-negative long value. * An FST {@link Outputs} implementation where each output is a non-negative long value.
* *
* @lucene.experimental * @lucene.experimental
*/ */
@SuppressForbidden(reason = "Uses a Long instance as a marker")
public final class PositiveIntOutputs extends Outputs<Long> { public final class PositiveIntOutputs extends Outputs<Long> {
// Ignore the deprecated constructor. We do want a unique object here. private static final Long NO_OUTPUT = 0L;
@SuppressWarnings({"all"})
private static final Long NO_OUTPUT = new Long(0);
private static final PositiveIntOutputs singleton = new PositiveIntOutputs(); private static final PositiveIntOutputs singleton = new PositiveIntOutputs();

View File

@ -56,20 +56,14 @@ public class TestCharArraySet extends LuceneTestCase {
@SuppressForbidden(reason = "Explicitly checking new Integers") @SuppressForbidden(reason = "Explicitly checking new Integers")
public void testObjectContains() { public void testObjectContains() {
CharArraySet set = new CharArraySet(10, true); CharArraySet set = new CharArraySet(10, true);
Integer val = Integer.valueOf(1); Integer val = 1;
@SuppressWarnings("all")
Integer val1 = new Integer(1);
// Verify explicitly the case of different Integer instances
assertNotSame(val, val1);
set.add(val); set.add(val);
assertTrue(set.contains(val)); assertTrue(set.contains(val));
assertTrue(set.contains(val1)); // another integer
assertTrue(set.contains("1")); assertTrue(set.contains("1"));
assertTrue(set.contains(new char[] {'1'})); assertTrue(set.contains(new char[] {'1'}));
// test unmodifiable // test unmodifiable
set = CharArraySet.unmodifiableSet(set); set = CharArraySet.unmodifiableSet(set);
assertTrue(set.contains(val)); assertTrue(set.contains(val));
assertTrue(set.contains(val1)); // another integer
assertTrue(set.contains("1")); assertTrue(set.contains("1"));
assertTrue(set.contains(new char[] {'1'})); assertTrue(set.contains(new char[] {'1'}));
} }

View File

@ -29,6 +29,7 @@ import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory; import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.store.FilterDirectory; import org.apache.lucene.store.FilterDirectory;
import org.apache.lucene.store.IOContext; import org.apache.lucene.store.IOContext;
import org.apache.lucene.util.SuppressForbidden;
/** /**
* This directory wrapper overrides {@link Directory#copyFrom(Directory, String, String, IOContext)} * This directory wrapper overrides {@link Directory#copyFrom(Directory, String, String, IOContext)}
@ -66,27 +67,26 @@ public final class HardlinkCopyDirectoryWrapper extends FilterDirectory {
// only try hardlinks if we have permission to access the files // only try hardlinks if we have permission to access the files
// if not super.copyFrom() will give us the right exceptions // if not super.copyFrom() will give us the right exceptions
suppressedException = suppressedException =
AccessController.doPrivileged( doPrivileged(
(PrivilegedAction<Exception>) () -> {
() -> { try {
try { Files.createLink(toPath.resolve(destFile), fromPath.resolve(srcFile));
Files.createLink(toPath.resolve(destFile), fromPath.resolve(srcFile)); } catch (FileNotFoundException
} catch (FileNotFoundException | NoSuchFileException
| NoSuchFileException | FileAlreadyExistsException ex) {
| FileAlreadyExistsException ex) { return ex; // in these cases we bubble up since it's a true error condition.
return ex; // in these cases we bubble up since it's a true error condition. } catch (IOException
} catch (IOException // if the FS doesn't support hard-links
// if the FS doesn't support hard-links | UnsupportedOperationException
| UnsupportedOperationException // we don't have permission to use hard-links just fall back to byte copy
// we don't have permission to use hard-links just fall back to byte copy | SecurityException ex) {
| SecurityException ex) { // hard-links are not supported or the files are on different filesystems
// hard-links are not supported or the files are on different filesystems // we could go deeper and check if their filesstores are the same and opt
// we could go deeper and check if their filesstores are the same and opt // out earlier but for now we just fall back to normal file-copy
// out earlier but for now we just fall back to normal file-copy return ex;
return ex; }
} return null;
return null; });
});
tryCopy = suppressedException != null; tryCopy = suppressedException != null;
} }
} }
@ -101,4 +101,11 @@ public final class HardlinkCopyDirectoryWrapper extends FilterDirectory {
} }
} }
} }
// Extracted to a method to give the SuppressForbidden annotation the smallest possible scope
@SuppressWarnings("removal")
@SuppressForbidden(reason = "security manager")
private static <T> T doPrivileged(PrivilegedAction<T> action) {
return AccessController.doPrivileged(action);
}
} }

View File

@ -20,7 +20,6 @@ import java.io.IOException;
import org.apache.lucene.store.DataInput; import org.apache.lucene.store.DataInput;
import org.apache.lucene.store.DataOutput; import org.apache.lucene.store.DataOutput;
import org.apache.lucene.util.RamUsageEstimator; import org.apache.lucene.util.RamUsageEstimator;
import org.apache.lucene.util.SuppressForbidden;
import org.apache.lucene.util.fst.FSTCompiler; import org.apache.lucene.util.fst.FSTCompiler;
import org.apache.lucene.util.fst.Outputs; import org.apache.lucene.util.fst.Outputs;
@ -40,7 +39,6 @@ import org.apache.lucene.util.fst.Outputs;
* *
* @lucene.experimental * @lucene.experimental
*/ */
@SuppressForbidden(reason = "Uses a Long instance as a marker")
public final class UpToTwoPositiveIntOutputs extends Outputs<Object> { public final class UpToTwoPositiveIntOutputs extends Outputs<Object> {
/** Holds two long outputs. */ /** Holds two long outputs. */
@ -76,9 +74,7 @@ public final class UpToTwoPositiveIntOutputs extends Outputs<Object> {
} }
} }
// Ignore the deprecated constructor. We do want a unique object here. private static final Long NO_OUTPUT = 0L;
@SuppressWarnings({"all"})
private static final Long NO_OUTPUT = new Long(0);
private final boolean doShare; private final boolean doShare;

View File

@ -3103,6 +3103,8 @@ public abstract class LuceneTestCase extends Assert {
* execution. If enabled, it needs the following {@link SecurityPermission}: {@code * execution. If enabled, it needs the following {@link SecurityPermission}: {@code
* "createAccessControlContext"} * "createAccessControlContext"}
*/ */
@SuppressForbidden(reason = "security manager")
@SuppressWarnings("removal")
public static <T> T runWithRestrictedPermissions( public static <T> T runWithRestrictedPermissions(
PrivilegedExceptionAction<T> action, Permission... permissions) throws Exception { PrivilegedExceptionAction<T> action, Permission... permissions) throws Exception {
assumeTrue( assumeTrue(

View File

@ -323,46 +323,50 @@ public final class RamUsageTester {
/** Create a cached information about shallow size and reference fields for a given class. */ /** Create a cached information about shallow size and reference fields for a given class. */
@SuppressForbidden(reason = "We need to access private fields of measured objects.") @SuppressForbidden(reason = "We need to access private fields of measured objects.")
private static ClassCache createCacheEntry(final Class<?> clazz) { private static ClassCache createCacheEntry(final Class<?> clazz) {
return AccessController.doPrivileged( @SuppressWarnings("removal")
(PrivilegedAction<ClassCache>) ClassCache classCache =
() -> { AccessController.doPrivileged(
ClassCache cachedInfo; (PrivilegedAction<ClassCache>)
long shallowInstanceSize = RamUsageEstimator.NUM_BYTES_OBJECT_HEADER; () -> {
final ArrayList<Field> referenceFields = new ArrayList<>(32); ClassCache cachedInfo;
for (Class<?> c = clazz; c != null; c = c.getSuperclass()) { long shallowInstanceSize = RamUsageEstimator.NUM_BYTES_OBJECT_HEADER;
if (c == Class.class) { final ArrayList<Field> referenceFields = new ArrayList<>(32);
// prevent inspection of Class' fields, throws SecurityException in Java 9! for (Class<?> c = clazz; c != null; c = c.getSuperclass()) {
continue; if (c == Class.class) {
} // prevent inspection of Class' fields, throws SecurityException in Java 9!
final Field[] fields = c.getDeclaredFields(); continue;
for (final Field f : fields) { }
if (!Modifier.isStatic(f.getModifiers())) { final Field[] fields = c.getDeclaredFields();
shallowInstanceSize = RamUsageEstimator.adjustForField(shallowInstanceSize, f); for (final Field f : fields) {
if (!Modifier.isStatic(f.getModifiers())) {
shallowInstanceSize =
RamUsageEstimator.adjustForField(shallowInstanceSize, f);
if (!f.getType().isPrimitive()) { if (!f.getType().isPrimitive()) {
try { try {
f.setAccessible(true); f.setAccessible(true);
referenceFields.add(f); referenceFields.add(f);
} catch (RuntimeException re) { } catch (RuntimeException re) {
throw new RuntimeException( throw new RuntimeException(
String.format( String.format(
Locale.ROOT, Locale.ROOT,
"Can't access field '%s' of class '%s' for RAM estimation.", "Can't access field '%s' of class '%s' for RAM estimation.",
f.getName(), f.getName(),
clazz.getName()), clazz.getName()),
re); re);
}
}
} }
} }
} }
}
}
cachedInfo = cachedInfo =
new ClassCache( new ClassCache(
RamUsageEstimator.alignObjectSize(shallowInstanceSize), RamUsageEstimator.alignObjectSize(shallowInstanceSize),
referenceFields.toArray(new Field[referenceFields.size()])); referenceFields.toArray(new Field[referenceFields.size()]));
return cachedInfo; return cachedInfo;
}); });
return classCache;
} }
private static long byteArraySize(int len) { private static long byteArraySize(int len) {

View File

@ -19,6 +19,7 @@ package org.apache.lucene.tests.util;
import java.lang.StackWalker.StackFrame; import java.lang.StackWalker.StackFrame;
import java.util.Locale; import java.util.Locale;
import java.util.function.Predicate; import java.util.function.Predicate;
import org.apache.lucene.util.SuppressForbidden;
/** /**
* A {@link SecurityManager} that prevents tests calling {@link System#exit(int)}. Only the test * A {@link SecurityManager} that prevents tests calling {@link System#exit(int)}. Only the test
@ -28,6 +29,8 @@ import java.util.function.Predicate;
* <p>Use this with {@code * <p>Use this with {@code
* -Djava.security.manager=org.apache.lucene.tests.util.TestSecurityManager}. * -Djava.security.manager=org.apache.lucene.tests.util.TestSecurityManager}.
*/ */
@SuppressForbidden(reason = "security manager")
@SuppressWarnings("removal")
public final class TestSecurityManager extends SecurityManager { public final class TestSecurityManager extends SecurityManager {
private static final String JUNIT4_TEST_RUNNER_PACKAGE = "com.carrotsearch.ant.tasks.junit4."; private static final String JUNIT4_TEST_RUNNER_PACKAGE = "com.carrotsearch.ant.tasks.junit4.";