针对泛型参数类型类里面,进行json 转换时,类型丢失的解决办法

类型丢失情况的问题描述:

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]]]

转载于:https://my.oschina.net/u/1428688/blog/2874112

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值