From d2c86bc0e875df5f572acdc4b2802a446a815789 Mon Sep 17 00:00:00 2001 From: "C. Sean Young" Date: Wed, 5 Aug 2015 14:31:50 -0500 Subject: [PATCH] Backport Java 8 compile time break workaround. Required for building host libraries with OpenJDK 8. Without this, trying to build with Java 8 fails with: external/guava/guava/src/com/google/common/reflect/Types.java:317: error: TypeVariableImpl is not abstract and does not override abstract method getAnnotatedBounds() in TypeVariable private static final class TypeVariableImpl Backport of https://github.com/google/guava/commit/f4aa25e74a9466c2f93a2147a7cf9b01850dd41f See https://github.com/google/guava/issues/1738 Bug: 23074347 Change-Id: I35adc64a339055e1e426af2aa3a41058f9948984 --- guava/src/com/google/common/reflect/Types.java | 98 +++++++++++++++++++++++--- 1 file changed, 90 insertions(+), 8 deletions(-) diff --git a/guava/src/com/google/common/reflect/Types.java b/guava/src/com/google/common/reflect/Types.java index 0f05f78..be358c7 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.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; import java.util.concurrent.atomic.AtomicReference; @@ -146,7 +152,7 @@ private static ClassOwnership detectJvmBehavior() { */ static TypeVariable newArtificialTypeVariable( D declaration, String name, Type... bounds) { - return new TypeVariableImpl( + return newTypeVariableImpl( declaration, name, (bounds.length == 0) @@ -314,8 +320,76 @@ static String toString(Type type) { private static final long serialVersionUID = 0; } - private static final class TypeVariableImpl - implements TypeVariable { + private static TypeVariable newTypeVariableImpl( + D genericDeclaration, String name, Type[] bounds) { + TypeVariableImpl typeVariableImpl = + new TypeVariableImpl(genericDeclaration, name, bounds); + @SuppressWarnings("unchecked") + TypeVariable typeVariable = Reflection.newProxy( + TypeVariable.class, new TypeVariableInvocationHandler(typeVariableImpl)); + return typeVariable; + } + + /** + * Invocation handler to work around a compatibility problem between Java 7 and Java 8. + * + *

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. + * + *

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 typeVariableMethods; + static { + ImmutableMap.Builder 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 { private final D genericDeclaration; private final String name; @@ -328,15 +402,19 @@ static String toString(Type type) { 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; } @@ -351,8 +429,12 @@ static String toString(Type type) { } @Override public boolean equals(Object obj) { - if (obj instanceof TypeVariable) { - TypeVariable that = (TypeVariable) obj; + if (obj != null + && Proxy.isProxyClass(obj.getClass()) + && Proxy.getInvocationHandler(obj) instanceof TypeVariableInvocationHandler) { + TypeVariableInvocationHandler typeVariableInvocationHandler = + (TypeVariableInvocationHandler) Proxy.getInvocationHandler(obj); + TypeVariableImpl that = typeVariableInvocationHandler.typeVariableImpl; return name.equals(that.getName()) && genericDeclaration.equals(that.getGenericDeclaration()); } From ed45f47ed0708b618055a9ec3574aed4c84d34b2 Mon Sep 17 00:00:00 2001 From: Christian Edward Gruber Date: Sun, 8 Dec 2013 07:36:55 -0800 Subject: [PATCH] Rename Splitter.spliterator to splittingIterator, to proactively prevent name shadowing with Java 8. ------------- Created by MOE: http://code.google.com/p/moe-java MOE_MIGRATED_REVID=57671698 --- .../google/common/base/super/com/google/common/base/Splitter.java | 8 ++++---- guava/src/com/google/common/base/Splitter.java | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/guava/src/com/google/common/base/Splitter.java b/guava/src/com/google/common/base/Splitter.java index 21eb33d..ce0fc01 100644 --- a/guava/src/com/google/common/base/Splitter.java +++ b/guava/src/com/google/common/base/Splitter.java @@ -387,7 +387,7 @@ public Splitter trimResults(CharMatcher trimmer) { return new Iterable() { @Override public Iterator iterator() { - return spliterator(sequence); + return splittingIterator(sequence); } @Override public String toString() { return Joiner.on(", ") @@ -398,7 +398,7 @@ public Splitter trimResults(CharMatcher trimmer) { }; } - private Iterator spliterator(CharSequence sequence) { + private Iterator splittingIterator(CharSequence sequence) { return strategy.iterator(this, sequence); } @@ -499,7 +499,7 @@ private MapSplitter(Splitter outerSplitter, Splitter entrySplitter) { public Map split(CharSequence sequence) { Map map = new LinkedHashMap(); for (String entry : outerSplitter.split(sequence)) { - Iterator entryFields = entrySplitter.spliterator(entry); + Iterator entryFields = entrySplitter.splittingIterator(entry); checkArgument(entryFields.hasNext(), INVALID_ENTRY_MESSAGE, entry); String key = entryFields.next();