Currently, I have three classes, Apple, Grape, Banana, and I created a converter class (can convert a string to list) for each of them. Then I realized all those converter classes are basically the same except they take different class types. 
The example of AppleConverter.java
  public class AppleConverter extends StrutsTypeConverter {
  @SuppressWarnings("rawtypes")
  @Override
  public Object convertFromString(Map context, String[] values, Class toClass) {
    final List<Apple> appleList = new ArrayList<>();
    try {
      for (String appleString : values) {
          Apple apple = Apple.valueOf(appleString);
          appleList.add(apple);
      }
    }
    catch (IllegalArgumentException e) {
      throw new TypeConversionException(e);
    }
    return appleList;
  }
  @SuppressWarnings("rawtypes")
  @Override
  public String convertToString(Map context, Object o) {
    if (o == null) {
      return null;
    }
    if (o instanceof List<?>) {
      List<Apple> list = (List<Apple>) o;
      String appleString = list
        .stream()
        .map(e -> String.valueOf(e))
        .collect(Collectors.joining(","));
      return appleString;
    }
    throw new TypeConversionException("wrong");
  }
Basically, GrapdeConverter.java and BananaConverter.java are the same as AppleConverter.java except they take different class types. 
So I tried to create a generic class then those converter classes can inherit it.
My generic class code: 
    public class FruitConverter<T> extends StrutsTypeConverter {
  @SuppressWarnings("rawtypes")
  @Override
  public Object convertFromString(Map context, String[] values, Class toClass) {
    if (ArrayUtils.isEmpty(values)) {
      return null;
    }
    final List<T> objs = new ArrayList<>();
    try {
      for (String objStr : values) {
           Object obj = toClass.getDeclaredMethod("valueOf", String.class).invoke(null, objStr);
          objs.add(obj);
        }
      }
    }
    catch (IllegalArgumentException e) {
      throw new TypeConversionException(e);
    }
    return objs;
  }
  @SuppressWarnings("rawtypes")
  @Override
  public String convertToString(Map context, Object o) {
    if (o == null) {
      return null;
    }
    if (o instanceof List<?>) {
      List<?> list = (List<?>) o;
      String fruitString = list
        .stream()
        .map(e -> String.valueOf(e))
        .collect(Collectors.joining(","));
      return fruitString;
    }
    throw new TypeConversionException("object is not a list of objs");
  }
}
When I called T obj = T.valueOf(objStr);, it throws an error can not resolve method valueOf.
May anyone tell me how to apply generics correctly in this case.
 
     
     
    