jmockdata
jmockdata copied to clipboard
嵌套泛型会导致堆栈溢出(StackOverflowError)
1、示例
OuterBean
public class OuterBean<T> {
private T result;
public T getResult() {
return result;
}
public void setResult(T result) {
this.result = result;
}
}
ArrayBean
public class ArrayBean<T> {
private List<T> list;
public List<T> getList() {
return list;
}
public void setList(List<T> list) {
this.list = list;
}
}
代码
OuterBean<ArrayBean<BasicBean>> outerBean = JMockData.mock(new TypeReference<OuterBean<ArrayBean<BasicBean>>>() {
});
2、原因
- 1.MockConfig.init只对当前类泛型做了缓存,导致嵌套泛型无法解析,通过getVariableType获取为null
- 2.BaseMocker和ArrayMocker中对于TypeVariable处理获取为name,导致相同名称如T返回相同的Type导致StackOverflowError
3、修复建议
MockConfig.init修改如下
public MockConfig init(Type type) {
if (!(type instanceof ParameterizedType)) {
return this;
}
ParameterizedType paramType = ((ParameterizedType) type);
Class<?> clazz = (Class<?>) paramType.getRawType();
Type[] types = paramType.getActualTypeArguments();
Class<?> supperClazz = clazz;
while (supperClazz != null && !ReflectionUtils.isSystemClass(clazz.getName())) {
TypeVariable<?>[] typeVariables = supperClazz.getTypeParameters();
for (int index = 0; index < typeVariables.length; index++) {
TypeVariable<?> typeVariable = typeVariables[index];
String name = ReflectionUtils.getTypeVariableName(typeVariable);
Type nestType = types[index];
typeVariableCache.put(name, nestType);
if (supperClazz == clazz) {
init(nestType);
}
}
supperClazz = supperClazz.getSuperclass();
}
return this;
}
BaseMocker和ArrayMocker获取name修改如下
public static String getTypeVariableName(TypeVariable<?> typeVariable) {
GenericDeclaration declaration = typeVariable.getGenericDeclaration();
if (!(declaration instanceof Class<?>)) {
throw new MockException("unknown error");
}
return String.format("%s.%s", ((Class<?>) declaration).getName(), typeVariable.getName());
}
public static boolean isSystemClass(String name) {
return name.startsWith("java.") || name.startsWith("javax.");
}
Junit
@Test
public void testNestedGeneric() {
OuterBean<ArrayBean<BasicBean>> outerBean = JMockData.mock(new TypeReference<OuterBean<ArrayBean<BasicBean>>>() {
});
System.out.println(JSON.toJSONString(outerBean, true));
assertNotNull(outerBean);
}
@Test
public void testArrayGeneric() {
ArrayBean<String> outerBean = JMockData.mock(new TypeReference<ArrayBean<String>>() {
});
System.out.println(JSON.toJSONString(outerBean, true));
assertNotNull(outerBean);
}
直接提交PR比较好