summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWolfgang Wiedmeyer <wolfgit@wiedmeyer.de>2016-12-09 02:48:30 +0100
committerWolfgang Wiedmeyer <wolfgit@wiedmeyer.de>2016-12-09 02:48:30 +0100
commitda4fc183b552020e0a04e47f7b8967b0e6c459d0 (patch)
treee5501c31b82258e92993988938e463e9a9a1110a
parent83670cb2f2c25105acd35b6b120c70f86fb8dd89 (diff)
downloadtoolchain_jack-da4fc183b552020e0a04e47f7b8967b0e6c459d0.tar.gz
toolchain_jack-da4fc183b552020e0a04e47f7b8967b0e6c459d0.tar.bz2
toolchain_jack-da4fc183b552020e0a04e47f7b8967b0e6c459d0.zip
Guava build fixes for Java 8
This patch is based on the "Backport Java 8 compile time break workaround." patch[1] that was committed in external/guava. [1] https://github.com/CyanogenMod/android_external_guava/commit/99b0ee6f5b3a3cd22f340e4e84581fbedc81423a Signed-off-by: Wolfgang Wiedmeyer <wolfgit@wiedmeyer.de>
-rw-r--r--guava/src/com/google/common/base/Splitter.java6
-rw-r--r--guava/src/com/google/common/reflect/Types.java90
2 files changed, 87 insertions, 9 deletions
diff --git a/guava/src/com/google/common/base/Splitter.java b/guava/src/com/google/common/base/Splitter.java
index a1c236c3..cd61a579 100644
--- a/guava/src/com/google/common/base/Splitter.java
+++ b/guava/src/com/google/common/base/Splitter.java
@@ -376,7 +376,7 @@ public final class Splitter {
return new Iterable<String>() {
@Override public Iterator<String> iterator() {
- return spliterator(sequence);
+ return splittingIterator(sequence);
}
@Override public String toString() {
return Joiner.on(", ")
@@ -387,7 +387,7 @@ public final class Splitter {
};
}
- private Iterator<String> spliterator(CharSequence sequence) {
+ private Iterator<String> splittingIterator(CharSequence sequence) {
return strategy.iterator(this, sequence);
}
@@ -453,7 +453,7 @@ public final class Splitter {
public Map<String, String> split(CharSequence sequence) {
Map<String, String> map = new LinkedHashMap<String, String>();
for (String entry : outerSplitter.split(sequence)) {
- Iterator<String> entryFields = entrySplitter.spliterator(entry);
+ Iterator<String> entryFields = entrySplitter.splittingIterator(entry);
checkArgument(entryFields.hasNext(), INVALID_ENTRY_MESSAGE, entry);
String key = entryFields.next();
diff --git a/guava/src/com/google/common/reflect/Types.java b/guava/src/com/google/common/reflect/Types.java
index 19264d31..64084e0f 100644
--- a/guava/src/com/google/common/reflect/Types.java
+++ b/guava/src/com/google/common/reflect/Types.java
@@ -26,16 +26,22 @@ import com.google.common.base.Joiner;
import com.google.common.base.Objects;
import com.google.common.base.Predicates;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
import java.io.Serializable;
import java.lang.reflect.Array;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.GenericDeclaration;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Proxy;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.lang.reflect.WildcardType;
+import java.security.AccessControlException;
import java.util.Arrays;
import java.util.Collection;
@@ -145,7 +151,7 @@ final class Types {
*/
static <D extends GenericDeclaration> TypeVariable<D> newTypeVariable(
D declaration, String name, Type... bounds) {
- return new TypeVariableImpl<D>(
+ return newTypeVariableImpl(
declaration,
name,
(bounds.length == 0)
@@ -335,8 +341,76 @@ final class Types {
private static final long serialVersionUID = 0;
}
- private static final class TypeVariableImpl<D extends GenericDeclaration>
- implements TypeVariable<D> {
+private static <D extends GenericDeclaration> TypeVariable<D> newTypeVariableImpl(
+ D genericDeclaration, String name, Type[] bounds) {
+ TypeVariableImpl<D> typeVariableImpl =
+ new TypeVariableImpl<D>(genericDeclaration, name, bounds);
+ @SuppressWarnings("unchecked")
+ TypeVariable<D> typeVariable = Reflection.newProxy(
+ TypeVariable.class, new TypeVariableInvocationHandler(typeVariableImpl));
+ return typeVariable;
+ }
+
+ /**
+ * Invocation handler to work around a compatibility problem between Java 7 and Java 8.
+ *
+ * <p>Java 8 introduced a new method {@code getAnnotatedBounds()} in the {@link TypeVariable}
+ * interface, whose return type {@code AnnotatedType[]} is also new in Java 8. That means that we
+ * cannot implement that interface in source code in a way that will compile on both Java 7 and
+ * Java 8. If we include the {@code getAnnotatedBounds()} method then its return type means
+ * it won't compile on Java 7, while if we don't include the method then the compiler will
+ * complain that an abstract method is unimplemented. So instead we use a dynamic proxy to
+ * get an implementation. If the method being called on the {@code TypeVariable} instance has
+ * the same name as one of the public methods of {@link TypeVariableImpl}, the proxy calls
+ * the same method on its instance of {@code TypeVariableImpl}. Otherwise it throws {@link
+ * UnsupportedOperationException}; this should only apply to {@code getAnnotatedBounds()}. This
+ * does mean that users on Java 8 who obtain an instance of {@code TypeVariable} from {@link
+ * TypeResolver#resolveType} will not be able to call {@code getAnnotatedBounds()} on it, but that
+ * should hopefully be rare.
+ *
+ * <p>This workaround should be removed at a distant future time when we no longer support Java
+ * versions earlier than 8.
+ */
+ private static final class TypeVariableInvocationHandler implements InvocationHandler {
+ private static final ImmutableMap<String, Method> typeVariableMethods;
+ static {
+ ImmutableMap.Builder<String, Method> builder = ImmutableMap.builder();
+ for (Method method : TypeVariableImpl.class.getMethods()) {
+ if (method.getDeclaringClass().equals(TypeVariableImpl.class)) {
+ try {
+ method.setAccessible(true);
+ } catch (AccessControlException e) {
+ // OK: the method is accessible to us anyway. The setAccessible call is only for
+ // unusual execution environments where that might not be true.
+ }
+ builder.put(method.getName(), method);
+ }
+ }
+ typeVariableMethods = builder.build();
+ }
+
+ private final TypeVariableImpl<?> typeVariableImpl;
+
+ TypeVariableInvocationHandler(TypeVariableImpl<?> typeVariableImpl) {
+ this.typeVariableImpl = typeVariableImpl;
+ }
+
+ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ String methodName = method.getName();
+ Method typeVariableMethod = typeVariableMethods.get(methodName);
+ if (typeVariableMethod == null) {
+ throw new UnsupportedOperationException(methodName);
+ } else {
+ try {
+ return typeVariableMethod.invoke(typeVariableImpl, args);
+ } catch (InvocationTargetException e) {
+ throw e.getCause();
+ }
+ }
+ }
+ }
+
+ private static final class TypeVariableImpl<D extends GenericDeclaration> {
private final D genericDeclaration;
private final String name;
@@ -349,18 +423,22 @@ final class Types {
this.bounds = ImmutableList.copyOf(bounds);
}
- @Override public Type[] getBounds() {
+ public Type[] getBounds() {
return toArray(bounds);
}
- @Override public D getGenericDeclaration() {
+ public D getGenericDeclaration() {
return genericDeclaration;
}
- @Override public String getName() {
+ public String getName() {
return name;
}
+ public String getTypeName() {
+ return name;
+ }
+
@Override public String toString() {
return name;
}