[Java] 扩展 Jackson 的 TypeReference 支持泛型参数传递
使用 Jackson 进行复杂类型的反序列化时,可以通过 com.fasterxml.jackson.core.type.TypeReference 来实现,例如:
class User {
String name;
Integer age;
}
class Response<T>{
Integer code;
T data;
String msg;
}
public static <T> T toObject(String data, TypeReference<T> clsType) throws JsonProcessingException {
if (data == null || data.isEmpty()) return null;
val mapper = new ObjectMapper();
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
return mapper.readValue(data, clsType);
}
public static String toJsonString(Object data) {
val mapper = new ObjectMapper();
mapper.configure(SerializationFeature.WRITE_DATE_KEYS_AS_TIMESTAMPS, false);
try {
return mapper.writeValueAsString(data);
} catch (JsonProcessingException e) {
return data.toString();
}
}
// 将对象转为json字符串
String data = toJsonString(new Response(0, new User("小明", 18), "OK"));
// 将 json 字符串还原为 Response<User> 对象
Response<User> obj = toObject(data, new TypeReference<Response<User>>(){})
上面的方式看似一切OK,但没办法实现这样的情况:
public static <T> Response<T> toObject(Class<T> cls, String data) throws JsonProcessingException {
return toObject(data, new TypeReference<Response<T>>(){});
}
// 这样是不行的,泛型 T 的类型没办法传递
Response<User> obj = toObject(User.class, data);
改造 TypeReference, 增加一个带参数的 TypeReference
方法:
import sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
/**
* @author yangyxd
*/
public class TypeReference<T> extends com.fasterxml.jackson.core.type.TypeReference<T>
{
protected final Type type;
// 带参数的方法,支持泛型类传递
protected <E> TypeReference(Class<E> cls) {
Type type = ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
ParameterizedTypeImpl clsInfo = ParameterizedTypeImpl.make(((ParameterizedTypeImpl) type).getRawType(), new Type[]{cls}, null);
this.type = clsInfo;
}
protected TypeReference()
{
Type superClass = getClass().getGenericSuperclass();
if (superClass instanceof Class<?>) { // sanity check, should never happen
throw new IllegalArgumentException("Internal error: TypeReference constructed without actual type information");
}
this.type = ((ParameterizedType) superClass).getActualTypeArguments()[0];
}
@Override
public Type getType() { return type; }
}
这里主要是使用 ParameterizedTypeImpl.make
实现自定义的 ParameterizedTypeImpl,实现想要的功能。
这样可以使用这个带参数的方法:
public static <T> Response<T> toObject(Class<T> cls, String data) throws JsonProcessingException {
return toObject(data, new TypeReference<Response<T>>(cls){});
}