首页 > 技术文章 > Jackson

ant-xu 2019-10-22 15:10 原文

json将java带泛型的字符串读取。

在json转java的过程中常见 TypeReference<List<String>>(){}作为mapper读取字符串转java类型的参数。该类的构造函数如下。该类由jackson提供。

package com.fasterxml.jackson.core.type;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

//This generic abstract class is used for obtaining full generics type information
//by sub-classing; 截取的注释,该类通过子类来获取完整的泛型类型
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");
        }

        /* 22-Dec-2008, tatu: Not sure if this case is safe -- I suspect
         *   it is possible to make it fail?
         *   But let's deal with specific
         *   case when we know an actual use case, and thereby suitable
         *   workarounds for valid case(s) and/or error to throw
         *   on invalid one(s).
         */
         //获取真实的泛型参数(到这已经是父类的泛型参数了),感觉就是直接取出了<>中的内容
        _type = ((ParameterizedType) superClass).getActualTypeArguments()[0];
    }

    public Type getType() { return _type; }
    
    /**
     * The only reason we define this method (and require implementation
     * of <code>Comparable</code>) is to prevent constructing a
     * reference without type information.
     */
    @Override
    public int compareTo(TypeReference<T> o) { return 0; }
    // just need an implementation, not a good one... hence ^^^
}

上面类型在使用时是:TypeReference<List<String>>(){} 其实就是获取了这个类的List<String>这一部分,将其中获取类的代码拿出测试后,

package com.shixun;

import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Map;

public class fanxing {
    
    public static void main(String[] args) {
        fanxing x = new fanxing();
        Class cls = x.getClass();
        Method [] methods = cls.getDeclaredMethods();
        for(Method m: methods) {
            System.out.println(m);
        }
        
        System.out.println("验证部分");
        B pair = new B();  //因为获取的是父类,所以子类没有传递泛型参数
        Double x1 = new Double(1.0);
        Double x2 = new Double(2.0);
        System.out.println("是否和Integer一样由缓存"+(x1==x2));
    }
    
    
    public static <T> T add(T x,T y){    //输出Object Object
        return y;
    }
}

class Pair<K,V>{
    private K k;
    private V v;
    public K getK() {
        return k;
    }
    public void setK(K k) {
        this.k = k;
    }
    public V getV() {
        return v;
    }
    public void setV(V v) {
        this.v = v;
    }
}

class B<A, C, V, K> extends Pair<Map<String, Object>,V>{
    public B() {
        super();
        Type superClass = getClass().getGenericSuperclass();
        Type [] type = ((ParameterizedType) superClass).getActualTypeArguments();
        for(Type t: type) {
            System.out.print(t);
        }
        System.out.println();
        System.out.println(((ParameterizedType) superClass).getActualTypeArguments()[0]);
    }
}

输出的结果如下

public static void com.shixun.fanxing.main(java.lang.String[])
public static java.lang.Object com.shixun.fanxing.add(java.lang.Object,java.lang.Object)
验证部分
java.util.Map<java.lang.String, java.lang.Object>V  //其中一个类型是V
上面是获取父类的类型,下面是获取第一个
java.util.Map<java.lang.String, java.lang.Object>
是否和Integer一样由缓存false

如果形参是String,则取得Java.lang.String。

/////////////////////////////////////////////////////

在json转java类型的时候主要用public <T> T readValue(String content, Class<T> valueType)或者public <T> T readValue(String content, JavaType valueType)或者public <T> T readValue(String content, TypeReference valueTypeRef)在这样三个重载的方法中,第一个方法中放入要转成的对应对象的Class对象就行。但是对于含有泛型的类型例如:List<String>或者HashMap<String, Bean>对于第一个方法来说就只能获取List.Class或者HashMap.Class,其中的泛型类型则会丢失,能不能用呢,测试后发现是可以用的(个人认为会用Object来作为所有数据的类型,如果这时候在赋值给List<String>估计会进行类型的强制转换),所有才有了之后的两个重载的方法,因为后面的方法保存了泛型类型的信息,所以速度比较快也更精确。后面两种重载方法的使用方法如下。

CollectionType javaType = mapper.getTypeFactory() .constructCollectionType(List.class, Person.class); 
List<Person> personList = mapper.readValue(jsonInString, javaType); 
List<Person> personList = mapper.readValue(jsonInString, new TypeReference<List<Person>>(){});

MapType javaType = mapper.getTypeFactory().constructMapType(HashMap.class,String.class, Person.class); 
Map<String, Person> personMap = mapper.readValue(jsonInString, javaType); 
Map<String, Person> personMap = mapper.readValue(jsonInString, new TypeReference<Map<String, Person>>(){});

并且后面两种方法的接受的泛型类中的泛型参数填什么都可以,(第三个是的,第二个没试)就是TypeReference中的泛型参数一定要正确,但接收的Map<String, Person>即便写成Map<Integer, Integer>也可以接收(估计这时候会涉及到类型的强制转换)。因为源码点进入后如下

@SuppressWarnings({ "unchecked", "rawtypes" })
public <T> T readValue(String content, TypeReference valueTypeRef)
    throws IOException, JsonParseException, JsonMappingException
{
    return (T) _readMapAndClose(_jsonFactory.createParser(content), _typeFactory.constructType(valueTypeRef));
} 

@SuppressWarnings("unchecked")
public <T> T readValue(String content, JavaType valueType)
    throws IOException, JsonParseException, JsonMappingException
{
    return (T) _readMapAndClose(_jsonFactory.createParser(content), valueType);
}

整个过程T都没有被赋值,要想给T赋值如下即可

Map<String, Object> temp = mapper.<Map<String, Object>>readValue(new File("newPerson.json"), new TypeReference<Map<String, Object>>(){});

////////////////////////////////////////////////////////////////////

常用方法

mapper.writeValue(new File("newPerson.json"), personDataMap); 将对象写如流中

mapper.writeValueAsString(value),将对象转换为String并返回。

下面是json到对象的转换

public <T> T readValue(String content, Class<T> valueType)

public <T> T readValue(String content, JavaType valueType)

public <T> T readValue(String content, TypeReference valueTypeRef)

下面是从Web服务器到页面

未整理杂项,搜索mapper https://www.cnblogs.com/ant-xu/p/11485270.html

推荐阅读