泛型

Jackson中泛型处理

在序列化和反序列化的过程中,泛型是永远离不开的主题,泛型的类型参考如下:

index Name Example
1 ParameterizedType 参数化类型,即泛型;例如:List、Map<K,V>等带有参数化的对象,自定义的如Box也是
2 TypeVariable 类型变量,即泛型中的变量;例如:T、K、V等变量,可以表示任何类;在这需要强调的是,TypeVariable代表着泛型中的变量,而ParameterizedType则代表整个泛型
3 GenericArrayType 泛型数组类型,用来描述ParameterizedTypeTypeVariable类型的数组;即List[]T[]
4 Class ClassType的一个实现类,属于原始类型,是Java反射的基础,对Java类的抽象
5 WildcardType 泛型表达式(或者通配符表达式,即? extend Number、? super Integer这样的表达式;WildcardType虽然是Type的子接口,但却不是Java类型中的一种

类型

Jackson的类型转化接口使用方法(几个常用的方法)

public <T> T readValue(JsonParser p, Class<T> valueType)
        throws IOException, JsonParseException, JsonMappingException
{
    return (T) _readValue(getDeserializationConfig(), p, _typeFactory.constructType(valueType));
}

@Override
@SuppressWarnings("unchecked")
public <T> T readValue(JsonParser p, TypeReference<?> valueTypeRef)
    throws IOException, JsonParseException, JsonMappingException
{
    return (T) _readValue(getDeserializationConfig(), p, _typeFactory.constructType(valueTypeRef));
}

@Override
@SuppressWarnings("unchecked")
public final <T> T readValue(JsonParser p, ResolvedType valueType)
    throws IOException, JsonParseException, JsonMappingException
{
    return (T) _readValue(getDeserializationConfig(), p, (JavaType) valueType);
}

public <T> T readValue(JsonParser p, JavaType valueType)
    throws IOException, JsonParseException, JsonMappingException
{
    return (T) _readValue(getDeserializationConfig(), p, valueType);
}

最长接受的参数是:Class、JavaType、TypeReference。

JavaType

Jackson中可能是最终的类型吧,TypeReference最终还是会转化为JavaType,那么什么是JavaType呢?

Base class for type token classes used both to contain information and as keys for deserializers.
Instances can (only) be constructed by
com.fasterxml.jackson.databind.type.TypeFactory.
Since 2.2 this implements {@link java.lang.reflect.Type} to allow
it to be pushed through interfaces that only expose that type.

用于包含信息和作为反序列化器的键的类型标记类的基类。只能通过TypeFactory来实例化。通常的使用或者构造方式是:

// 1. 通过objectMapper.construct
JavaType javaType = JacksonConstant.OM.constructType(type);

// 2. 通过TypeProvier
JavaType javaType1 = TypeFactory.defaultInstance().constructType(type);

其实方式1本质上是2,源代码如下:

public JavaType constructType(Type t) {
    //本质还是通过TypeFactory来实现的
    return _typeFactory.constructType(t);
}

那么TypeFactory是如何实例化入参的呢?因为在反序列化的过程中,我们的入参是Type,但正如我们上面所述的,Type类包含了五个子类, Class, ParameterizedType, TypeVariable,WildCard,GenericArrayType,查看源码:

protected JavaType _fromAny(ClassStack context, Type type, TypeBindings bindings)
    {
        JavaType resultType;

        // simple class?
        if (type instanceof Class<?>) {
            // Important: remove possible bindings since this is type-erased thingy
            resultType = _fromClass(context, (Class<?>) type, EMPTY_BINDINGS);
        }
        // But if not, need to start resolving.
        else if (type instanceof ParameterizedType) {
            resultType = _fromParamType(context, (ParameterizedType) type, bindings);
        }
        else if (type instanceof JavaType) { // [databind#116]
            // no need to modify further if we already had JavaType
            return (JavaType) type;
        }
        else if (type instanceof GenericArrayType) {
            resultType = _fromArrayType(context, (GenericArrayType) type, bindings);
        }
        else if (type instanceof TypeVariable<?>) {
            resultType = _fromVariable(context, (TypeVariable<?>) type, bindings);
        }
        else if (type instanceof WildcardType) {
            resultType = _fromWildcard(context, (WildcardType) type, bindings);
        } else {
            // sanity check
            throw new IllegalArgumentException("Unrecognized Type: "+((type == null) ? "[null]" : type.toString()));
        }
        // 21-Feb-2016, nateB/tatu: as per [databind#1129] (applied for 2.7.2),
        //   we do need to let all kinds of types to be refined, esp. for Scala module.
        if (_modifiers != null) {
            TypeBindings b = resultType.getBindings();
            if (b == null) {
                b = EMPTY_BINDINGS;
            }
            for (TypeModifier mod : _modifiers) {
                JavaType t = mod.modifyType(resultType, type, b, this);
                if (t == null) {
                    throw new IllegalStateException(String.format(
                            "TypeModifier %s (of type %s) return null for type %s",
                            mod, mod.getClass().getName(), resultType));
                }
                resultType = t;
            }
        }
        return resultType;
    }

Jackson本身会根据类型来生成JavaType,记录相关的信息。总结来说:JavaType,Jackson自定义的一个记录入参Type的相关类的信息和其他和序列化相关的信息的类。

TypeReference

public abstract class TypeReference<T> implements Comparable<TypeReference<T>>
{
    protected final Type _type;

    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");
        }
        _type = ((ParameterizedType) superClass).getActualTypeArguments()[0];
    }

    public Type getType() { return _type; }
}

通用的使用方式是:

Map<String, Staff> json2Map = JacksonConstant.OM.readValue(staffMapJson, new TypeReference<Map<String, Staff>>() {
    });

构建一个内部匿名类,名字是运行类下的$number,继承了TypeReference<Map<String,Staff»,保存了最原始的数据类型,通过:

getClass().getGenericSuperclass()

获取parameterizedType,类型为TypeReference,通过parameterizedType.getActualTypeArguments()[0],获取最终的类型: Map<String, Staff>,这样的话就保留了需要的类型。

使用

入参为class

Staff staff1 = mapper.readValue(jsonInString, Staff.class);
//Pretty print
String prettyStaff1 = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(staff1);

入参为type

如果入参的是type,但是实际上是class的话,那么需要构建JavaType

Object obj = JacksonConstant.OM.readValue(json, JacksonConstant.OM.constructType(type));

if (obj instanceof Staff) {
    return (Staff) obj;
}

如果入参为ParameterizedType的话,如果Map<K,V>,那么需要转化为TypeReference,代码case如下:

Map<String, Staff> json2Map = JacksonConstant.OM.readValue(staffMapJson, new TypeReference<Map<String, Staff>>() {
});

同理可得,对于List的反序列化可以推断为如下:

public static List<Staff> json2List() throws IOException {
    String json = "[{\"name\":\"rb.x\",\"age\":1,\"position\":\"sh\",\"salary\":100.23,\"skills\":[\"java\",\"mysql\"]}]";

    //在反序列化为List的过程中,list<T> 和Map<K,V>本质上是parameterizedType
    List<Staff> staffList = JacksonConstant.OM.readValue(json, new TypeReference<List<Staff>>() {
    });
    System.out.println(staffList.size());
    return staffList;
}
上一页
下一页