Skip to content

Commit

Permalink
feat(java_common): update shims to more clearly indicated supported v…
Browse files Browse the repository at this point in the history
…ersion (#5590)
  • Loading branch information
shahms committed Apr 20, 2023
1 parent aba8f29 commit d418a5d
Show file tree
Hide file tree
Showing 9 changed files with 95 additions and 74 deletions.
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
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
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
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
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
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
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
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
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);
}
}

0 comments on commit d418a5d

Please sign in to comment.