how to instanceof List<MyType>?

JavaGenerics

Java Problem Overview


How can I get this sort of thing to work? I can check if (obj instanceof List<?>) but not if (obj instanceof List<MyType>). Is there a way this can be done?

Java Solutions


Solution 1 - Java

That is not possible because the datatype erasure at compile time of generics. Only possible way of doing this is to write some kind of wrapper that holds which type the list holds:

public class GenericList <T> extends ArrayList<T>
{
     private Class<T> genericType;

     public GenericList(Class<T> c)
     {
          this.genericType = c;
     }

     public Class<T> getGenericType()
     {
          return genericType;
     }
}

Solution 2 - Java

if(!myList.isEmpty() && myList.get(0) instanceof MyType){
    // MyType object
}

Solution 3 - Java

You probably need to use reflection to get the types of them to check. To get the type of the List: https://stackoverflow.com/questions/1942644/get-generic-type-of-java-util-list

Solution 4 - Java

This could be used if you want to check that object is instance of List<T>, which is not empty:

if(object instanceof List){
    if(((List)object).size()>0 && (((List)object).get(0) instanceof MyObject)){
        // The object is of List<MyObject> and is not empty. Do something with it.
    }
}

Solution 5 - Java

    if (list instanceof List && ((List) list).stream()
                                             .noneMatch((o -> !(o instanceof MyType)))) {}

Solution 6 - Java

If you are verifying if a reference of a List or Map value of Object is an instance of a Collection, just create an instance of required List and get its class...

Set<Object> setOfIntegers = new HashSet(Arrays.asList(2, 4, 5));
assetThat(setOfIntegers).instanceOf(new ArrayList<Integer>().getClass());

Set<Object> setOfStrings = new HashSet(Arrays.asList("my", "name", "is"));
assetThat(setOfStrings).instanceOf(new ArrayList<String>().getClass());

Solution 7 - Java

If this can't be wrapped with generics (@Martijn's answer) it's better to pass it without casting to avoid redundant list iteration (checking the first element's type guarantees nothing). We can cast each element in the piece of code where we iterate the list.

Object attVal = jsonMap.get("attName");
List<Object> ls = new ArrayList<>();
if (attVal instanceof List) {
	ls.addAll((List) attVal);
} else {
	ls.add(attVal);
}

// far, far away ;)
for (Object item : ls) {
	if (item instanceof String) {
		System.out.println(item);
	} else {
		throw new RuntimeException("Wrong class ("+item .getClass()+") of "+item );
	}
}

Solution 8 - Java

You can use a fake factory to include many methods instead of using instanceof:

public class Message1 implements YourInterface {
   List<YourObject1> list;
   Message1(List<YourObject1> l) {
       list = l;
   }
}

public class Message2 implements YourInterface {
   List<YourObject2> list;
   Message2(List<YourObject2> l) {
       list = l;
   }
}

public class FactoryMessage {
    public static List<YourInterface> getMessage(List<YourObject1> list) {
        return (List<YourInterface>) new Message1(list);
    }
    public static List<YourInterface> getMessage(List<YourObject2> list) {
        return (List<YourInterface>) new Message2(list);
    }
}

Solution 9 - Java

The major concern here is that the collections don't keep the type in the definition. The types are only available in runtime. I came up with a function to test complex collections (it has one constraint though).

Check if the object is an instance of a generic collection. In order to represent a collection,

  • No classes, always false
  • One class, it is not a collection and returns the result of instanceof evaluation
  • To represent a List or Set, the type of the list comes next e.g. {List, Integer} for List<Integer>
  • To represent a Map, the key and value types come next e.g. {Map, String, Integer} for Map<String, Integer>

More complex use cases could be generated using the same rules. For example in order to represent List<Map<String, GenericRecord>>, it can be called as

    Map<String, Integer> map = new HashMap<>();
    map.put("S1", 1);
    map.put("S2", 2);
    List<Map<String, Integer> obj = new ArrayList<>();
    obj.add(map);
    isInstanceOfGenericCollection(obj, List.class, List.class, Map.class, String.class, GenericRecord.class);

Note that this implementation doesn't support nested types in the Map. Hence, the type of key and value should be a class and not a collection. But it shouldn't be hard to add it.

    public static boolean isInstanceOfGenericCollection(Object object, Class<?>... classes) {
        if (classes.length == 0) return false;
        if (classes.length == 1) return classes[0].isInstance(object);
        if (classes[0].equals(List.class))
            return object instanceof List && ((List<?>) object).stream().allMatch(item -> isInstanceOfGenericCollection(item, Arrays.copyOfRange(classes, 1, classes.length)));
        if (classes[0].equals(Set.class))
            return object instanceof Set && ((Set<?>) object).stream().allMatch(item -> isInstanceOfGenericCollection(item, Arrays.copyOfRange(classes, 1, classes.length)));
        if (classes[0].equals(Map.class))
            return object instanceof Map &&
                    ((Map<?, ?>) object).keySet().stream().allMatch(classes[classes.length - 2]::isInstance) &&
                    ((Map<?, ?>) object).values().stream().allMatch(classes[classes.length - 1]::isInstance);
        return false;
    }

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionRocky PulleyView Question on Stackoverflow
Solution 1 - JavaMartijn CourteauxView Answer on Stackoverflow
Solution 2 - JavaSatsView Answer on Stackoverflow
Solution 3 - JavaevanwongView Answer on Stackoverflow
Solution 4 - JavaIvo StoyanovView Answer on Stackoverflow
Solution 5 - JavadlaagniechyView Answer on Stackoverflow
Solution 6 - JavaMarcello de SalesView Answer on Stackoverflow
Solution 7 - JavakinjelomView Answer on Stackoverflow
Solution 8 - JavaLeLeView Answer on Stackoverflow
Solution 9 - JavaIraj HedayatiView Answer on Stackoverflow