Util { public static Type resolveLastTypeParameter(Type genericContext, Class<?> supertype) throws IllegalStateException { Type resolvedSuperType = Types.getSupertype(genericContext, Types.getRawType(genericContext), supertype); checkState(resolvedSuperType instanceof ParameterizedType, "could not resolve %s into a parameterized type %s", genericContext, supertype); Type[] types = ParameterizedType.class.cast(resolvedSuperType).getActualTypeArguments(); for (int i = 0; i < types.length; i++) { Type type = types[i]; if (type instanceof WildcardType) { types[i] = ((WildcardType) type).getUpperBounds()[0]; } } return types[types.length - 1]; } private  Util(); static void checkArgument(boolean expression,
                                   String errorMessageTemplate,
                                   Object... errorMessageArgs); static T checkNotNull(T reference,
                                   String errorMessageTemplate,
                                   Object... errorMessageArgs); static void checkState(boolean expression,
                                String errorMessageTemplate,
                                Object... errorMessageArgs); static boolean isDefault(Method method); static String emptyToNull(String string); @SuppressWarnings("unchecked") static T[] removeValues(T[] values, Predicate<T> shouldRemove, Class<T> type); @SuppressWarnings("unchecked") static T[] toArray(Iterable<? extends T> iterable, Class<T> type); static Collection<T> valuesOrEmpty(Map<String, Collection<T>> map, String key); static void ensureClosed(Closeable closeable); static Type resolveLastTypeParameter(Type genericContext, Class<?> supertype); static Object emptyValueOf(Type type); static String toString(Reader reader); static byte[] toByteArray(InputStream in); static String decodeOrDefault(byte[] data, Charset charset, String defaultValue); static boolean isNotBlank(String value); static boolean isBlank(String value); static final String CONTENT_LENGTH; static final String CONTENT_ENCODING; static final String RETRY_AFTER; static final String ENCODING_GZIP; static final String ENCODING_DEFLATE; static final Charset UTF_8; static final Charset ISO_8859_1; static final Type MAP_STRING_WILDCARD; }
@Test public void resolveLastTypeParameterWhenNotSubtype() throws Exception { Type context = LastTypeParameter.class.getDeclaredField("PARAMETERIZED_LIST_STRING").getGenericType(); Type listStringType = LastTypeParameter.class.getDeclaredField("LIST_STRING").getGenericType(); Type last = resolveLastTypeParameter(context, Parameterized.class); assertEquals(listStringType, last); }
@Test public void lastTypeFromInstance() throws Exception { Parameterized<?> instance = new ParameterizedSubtype(); Type last = resolveLastTypeParameter(instance.getClass(), Parameterized.class); assertEquals(String.class, last); }
@Test public void lastTypeFromAnonymous() throws Exception { Parameterized<?> instance = new Parameterized<Reader>() {}; Type last = resolveLastTypeParameter(instance.getClass(), Parameterized.class); assertEquals(Reader.class, last); }
@Test public void resolveLastTypeParameterWhenWildcard() throws Exception { Type context = LastTypeParameter.class.getDeclaredField("PARAMETERIZED_WILDCARD_LIST_STRING") .getGenericType(); Type listStringType = LastTypeParameter.class.getDeclaredField("LIST_STRING").getGenericType(); Type last = resolveLastTypeParameter(context, Parameterized.class); assertEquals(listStringType, last); }
@Test public void resolveLastTypeParameterWhenParameterizedSubtype() throws Exception { Type context = LastTypeParameter.class.getDeclaredField("PARAMETERIZED_DECODER_LIST_STRING") .getGenericType(); Type listStringType = LastTypeParameter.class.getDeclaredField("LIST_STRING").getGenericType(); Type last = resolveLastTypeParameter(context, ParameterizedDecoder.class); assertEquals(listStringType, last); }
@Test public void unboundWildcardIsObject() throws Exception { Type context = LastTypeParameter.class.getDeclaredField("PARAMETERIZED_DECODER_UNBOUND").getGenericType(); Type last = resolveLastTypeParameter(context, ParameterizedDecoder.class); assertEquals(Object.class, last); }