private static Converter<List<String>, Object> createCollectionConverter(Type resultType) {
    final Class<?> rawType = getRawClass(resultType);

    // Collection. It must be List or Set
    if (rawType != List.class && rawType != Set.class && rawType != SortedSet.class) {
      return null;
    }

    // Must be ParameterizedType
    if (!(resultType instanceof ParameterizedType)) {
      return null;
    }

    // Must have 1 type parameter
    ParameterizedType type = (ParameterizedType) resultType;
    if (type.getActualTypeArguments().length != 1) {
      return null;
    }

    // For SortedSet, the entry type must be Comparable.
    Type elementType = type.getActualTypeArguments()[0];
    if (rawType == SortedSet.class && !Comparable.class.isAssignableFrom(getRawClass(elementType))) {
      return null;
    }

    // Get the converter for the collection element.
    final Converter<List<String>, Object> elementConverter = createQueryParamConverter(elementType);
    if (elementConverter == null) {
      return null;
    }

    return new Converter<List<String>, Object>() {
      @Override
      public Object convert(List<String> values) throws Exception {
        Collection<? extends Comparable> collection;
        if (rawType == List.class) {
          collection = new ArrayList<>();
        } else if (rawType == Set.class) {
          collection = new LinkedHashSet<>();
        } else {
          collection = new TreeSet<>();
        }

        for (String value : values) {
          add(collection, elementConverter.convert(Collections.singletonList(value)));
        }
        return collection;
      }

      @SuppressWarnings("unchecked")
      private <T> void add(Collection<T> builder, Object element) {
        builder.add((T) element);
      }
    };
  }
private static Converter < List < String > , Object > createCollectionConverter ( Type resultType ) { final Class < ? > rawType = getRawClass ( resultType ) ; if ( rawType != List . class && rawType != Set . class && rawType != SortedSet . class ) { return null ; } if ( ! ( resultType instanceof ParameterizedType ) ) { return null ; } ParameterizedType type = ( ParameterizedType ) resultType ; if ( type . getActualTypeArguments ( ) . length != 1 ) { return null ; } Type elementType = type . getActualTypeArguments ( ) [ 0 ] ; if ( rawType == SortedSet . class && ! Comparable . class . isAssignableFrom ( getRawClass ( elementType ) ) ) { return null ; } final Converter < List < String > , Object > elementConverter = createQueryParamConverter ( elementType ) ; if ( elementConverter == null ) { return null ; } return new Converter < List < String > , Object > ( ) { @ Override public Object convert ( List < String > values ) throws Exception { Collection < ? extends Comparable > collection ; if ( rawType == List . class ) { collection = new ArrayList < > ( ) ; } else if ( rawType == Set . class ) { collection = new LinkedHashSet < > ( ) ; } else { collection = new TreeSet < > ( ) ; } for ( String value : values ) { add ( collection , elementConverter . convert ( Collections . singletonList ( value ) ) ) ; } return collection ; } @ SuppressWarnings ( "unchecked" ) private < T > void add ( Collection < T > builder , Object element ) { builder . add ( ( T ) element ) ; } } ; }
Creates a converter function that converts value into a {@link List}, {@link Set} or {@link SortedSet}.

@return A converter function or {@code null} if the given type is not a {@link ParameterizedType} with raw type as
{@link List}, {@link Set} or {@link SortedSet}. Also, for {@link SortedSet} type, if the element type
doesn't implements {@link Comparable}, {@code null} is returned.