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

feat(java_common): update shims to more clearly indicated supported version #5590

Merged
merged 2 commits into from
Apr 20, 2023
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,8 @@ public final class Jdk15CompatibilityShims implements JdkCompatibilityShims {
public Jdk15CompatibilityShims() {}

@Override
public CompatibilityClass getCompatibility() {
Runtime.Version version = Runtime.version();
if (version.compareToIgnoreOptional(minVersion) >= 0) {
// We don't know when this class will cease being compatible.
return CompatibilityClass.COMPATIBLE;
}
return CompatibilityClass.INCOMPATIBLE;
public CompatibilityRange getCompatibileRange() {
return new CompatibilityRange(minVersion);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,8 @@ public final class Jdk9CompatibilityShims implements JdkCompatibilityShims {
public Jdk9CompatibilityShims() {}

@Override
public CompatibilityClass getCompatibility() {
Runtime.Version version = Runtime.version();
if (version.compareToIgnoreOptional(minVersion) >= 0
&& version.compareToIgnoreOptional(maxVersion) < 0) {
return CompatibilityClass.COMPATIBLE;
}
return CompatibilityClass.INCOMPATIBLE;
public CompatibilityRange getCompatibileRange() {
return new CompatibilityRange(minVersion, maxVersion);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;

/** JdkCompatibilityShims implementation for JDK9-compatible releases. */
@AutoService(JdkCompatibilityShims.class)
Expand All @@ -32,12 +33,8 @@ public final class ReflectiveJdkCompatibilityShims implements JdkCompatibilitySh
public ReflectiveJdkCompatibilityShims() {}

@Override
public CompatibilityClass getCompatibility() {
Runtime.Version version = Runtime.version();
if (version.compareToIgnoreOptional(minVersion) >= 0) {
return CompatibilityClass.FALLBACK;
}
return CompatibilityClass.INCOMPATIBLE;
public CompatibilityRange getCompatibileRange() {
return new CompatibilityRange(minVersion, Optional.empty(), CompatibilityLevel.FALLBACK);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,13 @@
@AutoService(JdkCompatibilityShims.class)
public final class Jdk15CompatibilityShims implements JdkCompatibilityShims {
private static final Runtime.Version minVersion = Runtime.Version.parse("15");
private static final Runtime.Version maxVersion = Runtime.Version.parse("20");

public Jdk15CompatibilityShims() {}

@Override
public CompatibilityClass getCompatibility() {
Runtime.Version version = Runtime.version();
if (version.compareToIgnoreOptional(minVersion) >= 0) {
// We don't know when this class will cease being compatible.
return CompatibilityClass.COMPATIBLE;
}
return CompatibilityClass.INCOMPATIBLE;
public CompatibilityRange getCompatibileRange() {
return new CompatibilityRange(minVersion, maxVersion);
}

/** Return the list of expressions from a JCCase object */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,8 @@ public final class Jdk20CompatibilityShims implements JdkCompatibilityShims {
public Jdk20CompatibilityShims() {}

@Override
public CompatibilityClass getCompatibility() {
Runtime.Version version = Runtime.version();
if (version.compareToIgnoreOptional(minVersion) >= 0) {
// We don't know when this class will cease being compatible.
return CompatibilityClass.COMPATIBLE;
}
return CompatibilityClass.INCOMPATIBLE;
public CompatibilityRange getCompatibileRange() {
return new CompatibilityRange(minVersion);
}

/** Return the list of expressions from a JCCase object */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,8 @@ public final class Jdk9CompatibilityShims implements JdkCompatibilityShims {
public Jdk9CompatibilityShims() {}

@Override
public CompatibilityClass getCompatibility() {
Runtime.Version version = Runtime.version();
if (version.compareToIgnoreOptional(minVersion) >= 0
&& version.compareToIgnoreOptional(maxVersion) < 0) {
return CompatibilityClass.COMPATIBLE;
}
return CompatibilityClass.INCOMPATIBLE;
public CompatibilityRange getCompatibileRange() {
return new CompatibilityRange(minVersion, maxVersion);
}

/** Return the list of expressions from a JCCase object */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import com.sun.tools.javac.tree.JCTree.JCExpression;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
import java.util.Optional;

/** Shims for providing source-level compatibility between JDK versions. */
@AutoService(JdkCompatibilityShims.class)
Expand All @@ -33,15 +34,8 @@ public final class ReflectiveJdkCompatibilityShims implements JdkCompatibilitySh
public ReflectiveJdkCompatibilityShims() {}

@Override
public CompatibilityClass getCompatibility() {
Runtime.Version version = Runtime.version();
if (version.compareToIgnoreOptional(minVersion) >= 0) {
// We don't know when this class will cease being compatible,
// but should not be the first choice if there is a better implementation
// available.
return CompatibilityClass.FALLBACK;
}
return CompatibilityClass.INCOMPATIBLE;
public CompatibilityRange getCompatibileRange() {
return new CompatibilityRange(minVersion, Optional.empty(), CompatibilityLevel.FALLBACK);
}

/** Return the list of expressions from a JCCase object */
Expand Down
3 changes: 3 additions & 0 deletions kythe/java/com/google/devtools/kythe/util/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,9 @@ java_library(
java_library(
name = "ordered_compatibility_service",
srcs = ["OrderedCompatibilityService.java"],
deps = [
"//third_party/guava",
],
)

# Sources used to test Java extraction in //kythe/release:release_test.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

package com.google.devtools.kythe.util;

import com.google.common.collect.Streams;
import java.util.Comparator;
import java.util.Optional;
import java.util.ServiceLoader;

Expand All @@ -26,39 +28,88 @@
public interface OrderedCompatibilityService {

/** The compatibility level of the provider. */
public enum CompatibilityClass {
public enum CompatibilityLevel {
/** This provider is incompatible with the current runtime. */
INCOMPATIBLE,
/**
* This provider is compatible with the current runtime and should be preferred over a fallback,
* if any.
*/
COMPATIBLE,
/**
* This provider is compatible with the current runtime, but should only be used if a COMPATIBLE
* provider can't be found.
*/
FALLBACK
};
FALLBACK,
/**
* This provider is compatible with the current runtime and should be preferred over a fallback,
* if any.
*/
COMPATIBLE
}

/** Indicates the range of runtime versions with which these shims are compatible. */
public static class CompatibilityRange {
private final Runtime.Version minVersion;
private final Optional<Runtime.Version> maxVersion;
private final CompatibilityLevel level;

public CompatibilityRange(Runtime.Version minVersion) {
this(minVersion, Optional.empty(), CompatibilityLevel.COMPATIBLE);
}

public CompatibilityRange(Runtime.Version minVersion, Runtime.Version maxVersion) {
this(minVersion, Optional.of(maxVersion), CompatibilityLevel.COMPATIBLE);
}

public CompatibilityRange(
Runtime.Version minVersion,
Optional<Runtime.Version> maxVersion,
CompatibilityLevel level) {
this.minVersion = minVersion;
this.maxVersion = maxVersion;
this.level = level;
}

/** Returns the minimum known compatible runtime version. */
public Runtime.Version getMinVersion() {
return minVersion;
}

/** Returns the maximum known compatible runtime version, if any. */
public Optional<Runtime.Version> getMaxVersion() {
return maxVersion;
}

/** Returns the compatibility level. */
public CompatibilityLevel getCompatibilityLevel() {
return level;
}
}

/** Returns the compatibility level of the service provider. */
CompatibilityClass getCompatibility();
CompatibilityRange getCompatibileRange();

public static <S extends OrderedCompatibilityService> Optional<S> loadBest(Class<S> klass) {
S fallback = null;
for (S provider : ServiceLoader.load(klass)) {
if (provider == null) continue;
switch (provider.getCompatibility()) {
case INCOMPATIBLE:
continue;
case COMPATIBLE:
// Use the first compatible provider, if any.
return Optional.of(provider);
case FALLBACK:
if (fallback == null) fallback = provider;
break;
}
}
return Optional.ofNullable(fallback);
Runtime.Version version = Runtime.version();
return Streams.stream(ServiceLoader.load(klass))
// Filter out incompatible providers.
.filter(p -> isCompatible(version, p.getCompatibileRange()))
// Then find the best.
.max(OrderedCompatibilityService::compareProviders);
}

private static boolean isCompatible(Runtime.Version version, CompatibilityRange range) {
return range.getCompatibilityLevel() != CompatibilityLevel.INCOMPATIBLE
&& version.compareToIgnoreOptional(range.getMinVersion()) >= 0
&& range.getMaxVersion().map(max -> version.compareToIgnoreOptional(max) < 0).orElse(true);
}

private static int compareCompatibilityRanges(CompatibilityRange lhs, CompatibilityRange rhs) {
return Comparator.comparing(CompatibilityRange::getCompatibilityLevel)
.thenComparing(CompatibilityRange::getMinVersion, Runtime.Version::compareToIgnoreOptional)
.compare(lhs, rhs);
}

private static <S extends OrderedCompatibilityService> int compareProviders(S lhs, S rhs) {
return Comparator.comparing(
OrderedCompatibilityService::getCompatibileRange,
OrderedCompatibilityService::compareCompatibilityRanges)
.compare(lhs, rhs);
}
}