Skip to content

Commit

Permalink
Ensure that a non-indexed leaf doesn't break generic type resolution
Browse files Browse the repository at this point in the history
This can happen if say some interface extends a JDK interface and there
is no reason the type resolution should fail because of it
  • Loading branch information
geoand committed Apr 28, 2021
1 parent 302475b commit 5cc625e
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
Expand Down Expand Up @@ -65,14 +66,27 @@ private JandexUtil() {
* then the result will contain a single element of class ClassType whose name() would return a DotName for String
*/
public static List<Type> resolveTypeParameters(DotName input, DotName target, IndexView index) {
final ClassInfo inputClassInfo = fetchFromIndex(input, index);
final ClassInfo inputClassInfo;
try {
inputClassInfo = fetchFromIndex(input, index);
} catch (Exception e) {
// keep compatibility with what clients already expect
throw new IllegalArgumentException(e);
}

Type startingType = getType(inputClassInfo, index);
Set<DotName> unindexedClasses = new LinkedHashSet<>();
final List<Type> result = findParametersRecursively(startingType, target,
new HashSet<>(), index);
new HashSet<>(), index, unindexedClasses);
// null means not found
if (result == null) {
return Collections.emptyList();
if (unindexedClasses.isEmpty()) {
// no un-indexed classes means that there were no problems traversing the class and interface hierarchies
return Collections.emptyList();
}
throw new IllegalArgumentException(
"The following classes were not part of the index and could be the reason that the captured generic type of '"
+ target + "' could not be determined: " + unindexedClasses);
}

return result;
Expand All @@ -98,7 +112,7 @@ private static Type getType(ClassInfo inputClassInfo, IndexView index) {
* generics when found, on the way down. Returns null if not found.
*/
private static List<Type> findParametersRecursively(Type type, DotName target,
Set<DotName> visitedTypes, IndexView index) {
Set<DotName> visitedTypes, IndexView index, Set<DotName> unindexedClasses) {
DotName name = type.name();
// cache results first
if (!visitedTypes.add(name)) {
Expand All @@ -123,18 +137,26 @@ private static List<Type> findParametersRecursively(Type type, DotName target,

// superclasses first
Type superClassType = inputClassInfo.superClassType();
List<Type> superResult = findParametersRecursively(superClassType, target, visitedTypes, index);
if (superResult != null) {
// map any returned type parameters to our type arguments on the way down
return mapTypeArguments(superClassType, superResult, index);
try {
List<Type> superResult = findParametersRecursively(superClassType, target, visitedTypes, index, unindexedClasses);
if (superResult != null) {
// map any returned type parameters to our type arguments on the way down
return mapTypeArguments(superClassType, superResult, index);
}
} catch (ClassNotIndexedException e) {
unindexedClasses.add(e.dotName);
}

// interfaces second
for (Type interfaceType : inputClassInfo.interfaceTypes()) {
List<Type> ret = findParametersRecursively(interfaceType, target, visitedTypes, index);
if (ret != null) {
// map any returned type parameters to our type arguments on the way down
return mapTypeArguments(interfaceType, ret, index);
try {
List<Type> ret = findParametersRecursively(interfaceType, target, visitedTypes, index, unindexedClasses);
if (ret != null) {
// map any returned type parameters to our type arguments on the way down
return mapTypeArguments(interfaceType, ret, index);
}
} catch (ClassNotIndexedException e) {
unindexedClasses.add(e.dotName);
}
}

Expand Down Expand Up @@ -260,7 +282,7 @@ private static Type mapGenerics(Type type, Map<String, Type> mapping) {
private static ClassInfo fetchFromIndex(DotName dotName, IndexView index) {
final ClassInfo classInfo = index.getClassByName(dotName);
if (classInfo == null) {
throw new IllegalArgumentException("Class " + dotName + " was not found in the index");
throw new ClassNotIndexedException(dotName);
}
return classInfo;
}
Expand Down Expand Up @@ -344,4 +366,13 @@ public static String getBoxedTypeName(Type type) {
}
return type.toString();
}

private static class ClassNotIndexedException extends RuntimeException {

private final DotName dotName;

public ClassNotIndexedException(DotName dotName) {
this.dotName = dotName;
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.quarkus.deployment.util;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;

import java.io.IOException;
import java.io.InputStream;
Expand Down Expand Up @@ -154,6 +155,20 @@ public void testErasedGenerics() {
checkRepoArg(index, ErasedRepo2.class, Repo.class, A.class);
}

@Test
public void testNonProblematicUnindexed() {
final Index index = index(Single.class, SingleFromInterfaceAndSuperClass.class);
checkRepoArg(index, SingleFromInterfaceAndSuperClass.class, Single.class, String.class);
}

@Test
public void testProblematicUnindexed() {
final Index index = index(Single.class, AbstractSingleImpl.class, ExtendsAbstractSingleImpl.class);
assertThatThrownBy(() -> {
JandexUtil.resolveTypeParameters(name(ExtendsAbstractSingleImpl.class), name(Single.class), index);
}).isInstanceOf(IllegalArgumentException.class);
}

public interface Single<T> {
}

Expand Down

0 comments on commit 5cc625e

Please sign in to comment.