static Type aggregationType(Class<?> from, Class<?> searchFor, String methodName, Expression fallback) {
    try {
      final Method method = searchFor.getMethod(methodName);
      Type type = TypeToken.of(from).resolveType(method.getGenericReturnType()).getType();
      if (!(type instanceof ParameterizedType)) {
        throw new IllegalArgumentException(String.format("Expected %s for method %s but got %s", ParameterizedType.class.getSimpleName(), searchFor.getSimpleName() + "." + methodName, type));
      }
      ParameterizedType parameterized = (ParameterizedType) type;
      if (parameterized.getRawType() != Aggregation.class) {
        throw new IllegalArgumentException(String.format("Expected %s but got %s", Aggregation.class, parameterized.getRawType()));
      }

      if (parameterized.getActualTypeArguments().length != 1) {
        throw new IllegalArgumentException(String.format("Expected single type parameter for %s got %d", parameterized, parameterized.getActualTypeArguments().length));
      }

      Type resolved = parameterized.getActualTypeArguments()[0];
      if (resolved instanceof TypeVariable) {
        // still unresolved
        // resolve manually using provided Expression returnType
        return TypeToken.of(searchFor).resolveType(fallback.returnType()).getType();
      }
      return resolved;
    } catch (NoSuchMethodException e) {
      throw new RuntimeException(e);
    }
  }
Gets generic type variable of aggregation interface.
criteria/common/src/org/immutables/criteria/matcher/Matchers.java