Android
java 8 error in marshmallow
bumnux
2016. 11. 14. 19:03
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<D extends GenericDeclaration> index 0f05f78..be358c7 100644 | |||
--- a external/guava/guava/src/com/google/common/reflect/Types.java | |||
+++ b external/guava/guava/src/com/google/common/reflect/Types.java | |||
@@ -19,30 +19,36 @@ | |||
19 | 19 | import static com.google.common.base.Preconditions.checkArgument; | |
20 | 20 | import static com.google.common.base.Preconditions.checkNotNull; | |
21 | 21 | import static com.google.common.collect.Iterables.transform; | |
22 | 22 | ||
23 | 23 | import com.google.common.annotations.VisibleForTesting; | |
24 | 24 | import com.google.common.base.Function; | |
25 | 25 | import com.google.common.base.Joiner; | |
26 | 26 | import com.google.common.base.Objects; | |
27 | 27 | import com.google.common.base.Predicates; | |
28 | 28 | import com.google.common.collect.ImmutableList; | |
29 | +import com.google.common.collect.ImmutableMap; | ||
29 | 30 | import com.google.common.collect.Iterables; | |
30 | 31 | ||
31 | 32 | import java.io.Serializable; | |
32 | 33 | import java.lang.reflect.Array; | |
33 | 34 | import java.lang.reflect.GenericArrayType; | |
34 | 35 | import java.lang.reflect.GenericDeclaration; | |
36 | +import java.lang.reflect.InvocationHandler; | ||
37 | +import java.lang.reflect.InvocationTargetException; | ||
38 | +import java.lang.reflect.Method; | ||
35 | 39 | import java.lang.reflect.ParameterizedType; | |
40 | +import java.lang.reflect.Proxy; | ||
36 | 41 | import java.lang.reflect.Type; | |
37 | 42 | import java.lang.reflect.TypeVariable; | |
38 | 43 | import java.lang.reflect.WildcardType; | |
44 | +import java.security.AccessControlException; | ||
39 | 45 | import java.util.Arrays; | |
40 | 46 | import java.util.Collection; | |
41 | 47 | import java.util.concurrent.atomic.AtomicReference; | |
42 | 48 | ||
43 | 49 | import javax.annotation.Nullable; | |
44 | 50 | ||
45 | 51 | /** | |
46 | 52 | * Utilities for working with {@link Type}. | |
47 | 53 | * | |
48 | 54 | * @author Ben Yu | |
@@ -139,21 +145,21 @@ | |||
139 | 145 | throw new AssertionError(); | |
140 | 146 | } | |
141 | 147 | } | |
142 | 148 | ||
143 | 149 | /** | |
144 | 150 | * Returns a new {@link TypeVariable} that belongs to {@code declaration} with | |
145 | 151 | * {@code name} and {@code bounds}. | |
146 | 152 | */ | |
147 | 153 | static <D extends GenericDeclaration> TypeVariable<D> newArtificialTypeVariable( | |
148 | 154 | D declaration, String name, Type... bounds) { | |
149 | - return new TypeVariableImpl<D>( | ||
155 | + return newTypeVariableImpl( | ||
150 | 156 | declaration, | |
151 | 157 | name, | |
152 | 158 | (bounds.length == 0) | |
153 | 159 | ? new Type[] { Object.class } | |
154 | 160 | : bounds); | |
155 | 161 | } | |
156 | 162 | ||
157 | 163 | /** Returns a new {@link WildcardType} with {@code upperBound}. */ | |
158 | 164 | @VisibleForTesting static WildcardType subtypeOf(Type upperBound) { | |
159 | 165 | return new WildcardTypeImpl(new Type[0], new Type[] { upperBound }); | |
@@ -307,59 +313,135 @@ | |||
307 | 313 | ParameterizedType that = (ParameterizedType) other; | |
308 | 314 | return getRawType().equals(that.getRawType()) | |
309 | 315 | && Objects.equal(getOwnerType(), that.getOwnerType()) | |
310 | 316 | && Arrays.equals( | |
311 | 317 | getActualTypeArguments(), that.getActualTypeArguments()); | |
312 | 318 | } | |
313 | 319 | ||
314 | 320 | private static final long serialVersionUID = 0; | |
315 | 321 | } | |
316 | 322 | ||
317 | - private static final class TypeVariableImpl<D extends GenericDeclaration> | ||
318 | - implements TypeVariable<D> { | ||
323 | + private static <D extends GenericDeclaration> TypeVariable<D> newTypeVariableImpl( | ||
324 | + D genericDeclaration, String name, Type[] bounds) { | ||
325 | + TypeVariableImpl<D> typeVariableImpl = | ||
326 | + new TypeVariableImpl<D>(genericDeclaration, name, bounds); | ||
327 | + @SuppressWarnings("unchecked") | ||
328 | + TypeVariable<D> typeVariable = Reflection.newProxy( | ||
329 | + TypeVariable.class, new TypeVariableInvocationHandler(typeVariableImpl)); | ||
330 | + return typeVariable; | ||
331 | + } | ||
332 | + | ||
333 | + /** | ||
334 | + * Invocation handler to work around a compatibility problem between Java 7 and Java 8. | ||
335 | + * | ||
336 | + * <p>Java 8 introduced a new method {@code getAnnotatedBounds()} in the {@link TypeVariable} | ||
337 | + * interface, whose return type {@code AnnotatedType[]} is also new in Java 8. That means that we | ||
338 | + * cannot implement that interface in source code in a way that will compile on both Java 7 and | ||
339 | + * Java 8. If we include the {@code getAnnotatedBounds()} method then its return type means | ||
340 | + * it won't compile on Java 7, while if we don't include the method then the compiler will | ||
341 | + * complain that an abstract method is unimplemented. So instead we use a dynamic proxy to | ||
342 | + * get an implementation. If the method being called on the {@code TypeVariable} instance has | ||
343 | + * the same name as one of the public methods of {@link TypeVariableImpl}, the proxy calls | ||
344 | + * the same method on its instance of {@code TypeVariableImpl}. Otherwise it throws {@link | ||
345 | + * UnsupportedOperationException}; this should only apply to {@code getAnnotatedBounds()}. This | ||
346 | + * does mean that users on Java 8 who obtain an instance of {@code TypeVariable} from {@link | ||
347 | + * TypeResolver#resolveType} will not be able to call {@code getAnnotatedBounds()} on it, but that | ||
348 | + * should hopefully be rare. | ||
349 | + * | ||
350 | + * <p>This workaround should be removed at a distant future time when we no longer support Java | ||
351 | + * versions earlier than 8. | ||
352 | + */ | ||
353 | + private static final class TypeVariableInvocationHandler implements InvocationHandler { | ||
354 | + private static final ImmutableMap<String, Method> typeVariableMethods; | ||
355 | + static { | ||
356 | + ImmutableMap.Builder<String, Method> builder = ImmutableMap.builder(); | ||
357 | + for (Method method : TypeVariableImpl.class.getMethods()) { | ||
358 | + if (method.getDeclaringClass().equals(TypeVariableImpl.class)) { | ||
359 | + try { | ||
360 | + method.setAccessible(true); | ||
361 | + } catch (AccessControlException e) { | ||
362 | + // OK: the method is accessible to us anyway. The setAccessible call is only for | ||
363 | + // unusual execution environments where that might not be true. | ||
364 | + } | ||
365 | + builder.put(method.getName(), method); | ||
366 | + } | ||
367 | + } | ||
368 | + typeVariableMethods = builder.build(); | ||
369 | + } | ||
370 | + | ||
371 | + private final TypeVariableImpl<?> typeVariableImpl; | ||
372 | + | ||
373 | + TypeVariableInvocationHandler(TypeVariableImpl<?> typeVariableImpl) { | ||
374 | + this.typeVariableImpl = typeVariableImpl; | ||
375 | + } | ||
376 | + | ||
377 | + @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { | ||
378 | + String methodName = method.getName(); | ||
379 | + Method typeVariableMethod = typeVariableMethods.get(methodName); | ||
380 | + if (typeVariableMethod == null) { | ||
381 | + throw new UnsupportedOperationException(methodName); | ||
382 | + } else { | ||
383 | + try { | ||
384 | + return typeVariableMethod.invoke(typeVariableImpl, args); | ||
385 | + } catch (InvocationTargetException e) { | ||
386 | + throw e.getCause(); | ||
387 | + } | ||
388 | + } | ||
389 | + } | ||
390 | + } | ||
391 | + | ||
392 | + private static final class TypeVariableImpl<D extends GenericDeclaration> { | ||
319 | 393 | ||
320 | 394 | private final D genericDeclaration; | |
321 | 395 | private final String name; | |
322 | 396 | private final ImmutableList<Type> bounds; | |
323 | 397 | ||
324 | 398 | TypeVariableImpl(D genericDeclaration, String name, Type[] bounds) { | |
325 | 399 | disallowPrimitiveType(bounds, "bound for type variable"); | |
326 | 400 | this.genericDeclaration = checkNotNull(genericDeclaration); | |
327 | 401 | this.name = checkNotNull(name); | |
328 | 402 | this.bounds = ImmutableList.copyOf(bounds); | |
329 | 403 | } | |
330 | 404 | ||
331 | - @Override public Type[] getBounds() { | ||
405 | + public Type[] getBounds() { | ||
332 | 406 | return toArray(bounds); | |
333 | 407 | } | |
334 | 408 | ||
335 | - @Override public D getGenericDeclaration() { | ||
409 | + public D getGenericDeclaration() { | ||
336 | 410 | return genericDeclaration; | |
337 | 411 | } | |
338 | 412 | ||
339 | - @Override public String getName() { | ||
413 | + public String getName() { | ||
414 | + return name; | ||
415 | + } | ||
416 | + | ||
417 | + public String getTypeName() { | ||
340 | 418 | return name; | |
341 | 419 | } | |
342 | 420 | ||
343 | 421 | @Override public String toString() { | |
344 | 422 | return name; | |
345 | 423 | } | |
346 | 424 | ||
347 | 425 | @Override public int hashCode() { | |
348 | 426 | return genericDeclaration.hashCode() ^ name.hashCode(); | |
349 | 427 | } | |
350 | 428 | ||
351 | 429 | @Override public boolean equals(Object obj) { | |
352 | 430 | if (NativeTypeVariableEquals.NATIVE_TYPE_VARIABLE_ONLY) { | |
353 | 431 | // equal only to our TypeVariable implementation with identical bounds | |
354 | - if (obj instanceof TypeVariableImpl) { | ||
355 | - TypeVariableImpl<?> that = (TypeVariableImpl<?>) obj; | ||
432 | + if (obj != null | ||
433 | + && Proxy.isProxyClass(obj.getClass()) | ||
434 | + && Proxy.getInvocationHandler(obj) instanceof TypeVariableInvocationHandler) { | ||
435 | + TypeVariableInvocationHandler typeVariableInvocationHandler = | ||
436 | + (TypeVariableInvocationHandler) Proxy.getInvocationHandler(obj); | ||
437 | + TypeVariableImpl<?> that = typeVariableInvocationHandler.typeVariableImpl; | ||
356 | 438 | return name.equals(that.getName()) | |
357 | 439 | && genericDeclaration.equals(that.getGenericDeclaration()) | |
358 | 440 | && bounds.equals(that.bounds); | |
359 | 441 | } | |
360 | 442 | return false; | |
361 | 443 | } else { | |
362 | 444 | // equal to any TypeVariable implementation regardless of bounds | |
363 | 445 | if (obj instanceof TypeVariable) { | |
364 | 446 | TypeVariable<?> that = (TypeVariable<?>) obj; | |
365 | 447 | return name.equals(that.getName()) |