[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){});
}

END

posted @ 2023-03-16 16:43  我爱我家喵喵  阅读(2499)  评论(0编辑  收藏  举报