类型丢失情况的问题描述:
abstract class A<T> {
public String saveJson() {
TestModel a = new TestModel();
a.setName("aaa");
String json = JsonUtil.toJson(a);
return json;
}
public T test() {
String json = saveJson();
return JsonUtil.toObject(json, new TypeReference<T>() {
});
}
}
class TestModel {
int id;
String name;
}
class B extends A<TestModel> {
}
public static void main(String[] args) throws Exception {
B a = new B();
System.err.println(a.test().getClass());
}
Exception in thread "main" java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to com.bc.TestModel
at com.bc.App.main(App.java:11)
继承了A子类调用test方式,返回值类型会丢失,实际上调用test方法返回的是一个LinkedHashMap类型,并不是我们所以为的具体的类型,也就是这里的TestModel类型。
JsonUtil中使用的是jackson的ObjectMapper
解决办法:
1、使用jackson的JavaType做为第二个参数进行转换
mapper.getTypeFactory().constructParametricType(rawType, argumentType); 得到JavaType
mapper.readValue(json, javaType);
//修改后test方法
public T test() {
String json = saveJson();
Class<T> clz = (Class<T>) TypeUtil.getSuperGenricType(this.getClass());
JavaType type = JsonUtil.constructParametricType(clz,new Class<?>[0]);
return JsonUtil.toObject(json, type);
}
//下面是类型获取工具
public static Class<?> getSuperGenricType(final Class<?> clz) {
return getSuperGenricType(clz, 0);
}
public static Class<?> getSuperGenricType(final Class<?> clz, final int index) {
return (Class<?>) getSuperGenricTypes(clz)[index];
}
public static Type[] getSuperGenricTypes(final Class<?> clz) {
Class<?> superClass = clz;
Type type = superClass.getGenericSuperclass();
while (superClass != Object.class && !(type instanceof ParameterizedType)) {
superClass = superClass.getSuperclass();
type = superClass.getGenericSuperclass();
}
if (superClass == Object.class) {
throw new IllegalArgumentException("父类不含泛型类型:" + clz);
}
ParameterizedType genericSuperclass = (ParameterizedType) type;
return genericSuperclass.getActualTypeArguments();
}
2、如果T类型也是泛型,这样就行不能了
比如:class B extends A<List<TestModel>> {}
或是更多泛型类型class B extends A<Map<String,List<TestModel>>> {}
我们可以把T类型理解成一棵树,里面的包裹类型就是他的子节点,把树构造成JavaType
public static JavaType constructParametricType(Class<?> rawType, JavaType... argumentType) {
return mapper.getTypeFactory().constructParametricType(rawType, argumentType);
}
构造树的过程:
public static TypeTreeDTO getSuperArgumentTypes(Class<?> clz) {
return getArgumentTypes(getSuperGenricTypes(clz));
}
public static TypeTreeDTO getArgumentTypes(Type... types) {
Queue<Type> queue = new LinkedList<>();
queue.addAll(Arrays.asList(types));
return getArgumentTypes(queue);
}
private static TypeTreeDTO getArgumentTypes(Queue<Type> queue) {
if (queue.isEmpty()) {
throw new IllegalArgumentException("类型为空");
}
List<TypeTreeDTO> list = new ArrayList<>();
TypeTreeDTO top = null;
int id = 0;
TypeTreeDTO lastParentType = null;
TypeTreeDTO lastType = null;
while (!queue.isEmpty()) {
Type type = queue.poll();
if (type == null) {
if (lastType != null) {
if (lastParentType != null) {
lastType.setPid(lastParentType.getId());
list.add(lastType);
} else {
top = newNode(lastType.getType(), TypeTreeDTO.TOP_ID, 0);
}
}
continue;
}
if (type instanceof ParameterizedType) {
ParameterizedType pt = (ParameterizedType) type;
Class<?> rowType = (Class<?>) pt.getRawType();
lastParentType = lastType;
lastType = newNode(rowType, ++id, lastType != null ? lastType.getId() : 0);
queue.add(null);
queue.addAll(Arrays.asList(pt.getActualTypeArguments()));
continue;
}
if (lastType == null) {
top = newNode(type, TypeTreeDTO.TOP_ID, 0);
} else {
list.add(newNode(type, ++id, lastType.getId()));
}
}
top = TreeUtils.hierarchy(top, list);
return top;
}
//
public class TypeTreeDTO implements BaseTree<TypeTreeDTO> {
public static final int TOP_ID = 1;
int id;
int pid;
Class<?> type;
List<TypeTreeDTO> children;
public List<TypeTreeDTO> getChildren() {
return children;
}
public void setChildren(List<TypeTreeDTO> children) {
this.children = children;
}
public Class<?> getType() {
return type;
}
public void setType(Class<?> type) {
this.type = type;
}
@Override
public boolean isParent(TypeTreeDTO parent) {
return parent.getId() == this.pid;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getPid() {
return pid;
}
public void setPid(int pid) {
this.pid = pid;
}
}
我自己实现的树相关的工具类:
package com.bc.core.helper.tree;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
public abstract class TreeUtils {
public static <T extends BaseTree<T>> List<T> hierarchy(Collection<T> list) {
return hierarchy(list, null);
}
public static <T extends BaseTree<T>> T hierarchy(T top, Collection<T> list) {
return hierarchy(top, list, null);
}
public static <T extends BaseTree<T>> void hierarchy(Queue<T> topNodes, Collection<T> subs) {
hierarchy(topNodes, subs, null);
}
public static <T extends BaseTree<T>> List<T> hierarchy(Collection<T> list, TreeConsumer<T> biConsumer) {
Queue<T> queue = new LinkedList<>();
List<T> subs = findSubs(list);
list.removeAll(subs);
queue.addAll(list);
hierarchy(queue, subs, biConsumer);
return new ArrayList<>(list);
}
public static <T extends BaseTree<T>> T hierarchy(T top, Collection<T> list, TreeConsumer<T> biConsumer) {
Queue<T> queue = new LinkedList<>();
queue.offer(top);
hierarchy(queue, list, biConsumer);
return top;
}
public static <T extends BaseTree<T>> void hierarchy(Queue<T> topNodes, Collection<T> list,
TreeConsumer<T> biConsumer) {
int levelCount = topNodes.size();
int nextLevelCount = 0;
int level = 1;
while (!topNodes.isEmpty()) {
T parent = topNodes.poll();
if (biConsumer != null) {
biConsumer.forEach(parent, level);
}
for (T baseTree : list) {
if (baseTree.isParent(parent)) {
topNodes.offer(baseTree);
nextLevelCount++;
if (parent.getChildren() == null) {
parent.setChildren(new ArrayList<>());
}
parent.getChildren().add(baseTree);
}
}
if (parent.getChildren() != null) {
list.removeAll(parent.getChildren());
}
levelCount--;
if (levelCount == 0) {
level++;
levelCount = nextLevelCount;
}
}
}
public static <T extends BaseTree<T>> void forEach(T top, TreeConsumer<T> biConsumer) {
Queue<T> queue = new LinkedList<>();
queue.add(top);
int levelCount = 1;
int nextLevelCount = 0;
int level = 1;
while (!queue.isEmpty()) {
T parent = queue.poll();
if (biConsumer != null) {
biConsumer.forEach(parent, level);
}
if (parent.getChildren() != null) {
queue.addAll(parent.getChildren());
nextLevelCount = parent.getChildren().size();
}
levelCount--;
if (levelCount == 0) {
level++;
levelCount = nextLevelCount;
}
}
}
private static <T extends BaseTree<T>> List<T> findSubs(Collection<T> list) {
List<T> subs = new ArrayList<>();
for (T sub : list) {
for (T t : list) {
if (sub.isParent(t)) {
subs.add(sub);
break;
}
}
}
return subs;
}
}
TreeUtils使用到的类
import java.util.List;
public interface BaseTree<T> {
public boolean isParent(T parent);
public List<T> getChildren();
public void setChildren(List<T> children);
}
public interface TreeConsumer<T extends BaseTree<T>> {
void forEach(T current, int level);
}
将树转成JavaType和过程:
public static JavaType toJavaType(TypeTreeDTO top) {
List<JavaType> list = new ArrayList<>();
for (TypeTreeDTO c : top.getChildren()) {
if (c == null || c.getChildren().isEmpty()) {
JavaType javaType = constructParametricType(c.getType(), new JavaType[0]);
list.add(javaType);
} else {
list.add(toJavaType(c));
}
}
return constructParametricType(top.getType(), list.toArray(new JavaType[0]));
}
针对class B extends A<Map<String,List<TestModel>>>类
JavaType打印出来的结果:[map type; class java.util.Map, [simple type, class java.lang.String] -> [collection type; class java.util.List, contains [simple type, class com.bc.TestModel]]]