CompletableFuture<Void> (@Nullable Type subType, @NotNull String superType, CompletableFuture<Boolean> res) { if (subType == null || res.isDone()) { return completedFuture(null); } if (typeEquals(subType, superType)) { res.complete(true); return completedFuture(null); // early return } if (subType instanceof ClassType) { return allOf( superclass((ClassType)subType).thenCompose(s -> instanceOfObject(s, superType, res)), interfaces((ClassType)subType).thenCompose( interfaces -> allOf(interfaces.stream().map(i -> instanceOfObject(i, superType, res)).toArray(CompletableFuture[]::new)))); } if (subType instanceof InterfaceType) { return allOf( superinterfaces((InterfaceType)subType).thenCompose( interfaces -> allOf(interfaces.stream().map(i -> instanceOfObject(i, superType, res)).toArray(CompletableFuture[]::new)))); } if (subType instanceof ArrayType && superType.endsWith("[]")) { try { String superTypeItem = superType.substring(0, superType.length() - 2); Type subTypeItem = ((ArrayType)subType).componentType(); return instanceOf(subTypeItem, superTypeItem, false).thenAccept(r -> { if (r) res.complete(true); }); } catch (ClassNotLoadedException e) { //LOG.info(e); } } return completedFuture(null); }