`
阿尔萨斯
  • 浏览: 4177284 次
社区版块
存档分类
最新评论

Jackson应用二 Full Data Binding

 
阅读更多

Data Binding第二种应用是Full Data Binding.也就是可以支持自定义的Java类到JSON对象的互相转换。

下面的代码演示了简单的使用方法:

类Response的定义:

import lombok.Getter;
import lombok.Setter;

/**
 *
 * @author chenshu
 */
public class Response {
    
    @Getter @Setter
    private String status;
    
    @Getter @Setter
    private String message;
}

调用代码:

public class App {
    public static void main( String[] args ) throws IOException {
        ObjectMapper mapper = new ObjectMapper(); // create once, reuse
        String jsonSource = "{\"message\":\"Login succeeded!\",\"status\":null}";
        Response response = mapper.readValue(jsonSource, Response.class);
        
        String result = mapper.writeValueAsString(response);
    }
}


先通过命令mvn dependency:sources获取源代码。然后就可以调试进入代码观察。

readValue方法内部代码如下:

    @SuppressWarnings("unchecked")
    public <T> T readValue(String content, Class<T> valueType)
        throws IOException, JsonParseException, JsonMappingException
    {
     // !!! TODO
//    	_setupClassLoaderForDeserialization(valueType);
        return (T) _readMapAndClose(_jsonFactory.createJsonParser(content), _typeFactory.constructType(valueType));
    } 
_typeFactory.constructType(valueType)使用参数Response.class创建一个SimpleType对象(JavaType的子类),创建时有一个LinkedHashMap对象做的缓存,如果已经创建过,则不再重复创建,取出来直接使用,因此还用到了多线程锁。参考TypeFactory.java里面的代码:

    /**
     * @param context Mapping of formal parameter declarations (for generic
     *   types) into actual types
     */
    protected JavaType _fromClass(Class<?> clz, TypeBindings context)
    {
        // Very first thing: small set of core types we know well:
        if (clz == String.class) return CORE_TYPE_STRING;
        if (clz == Boolean.TYPE) return CORE_TYPE_BOOL;
        if (clz == Integer.TYPE) return CORE_TYPE_INT;
        if (clz == Long.TYPE) return CORE_TYPE_LONG;
        
        // Barring that, we may have recently constructed an instance:
        ClassKey key = new ClassKey(clz);
        JavaType result;
        
        synchronized (_typeCache) {
            result = _typeCache.get(key);
        }
        if (result != null) {
            return result;
        }

        // If context was needed, weed do:
        /*
        if (context == null) {
            context = new TypeBindings(this, cls);
        }
        */
        
        // First: do we have an array type?
        if (clz.isArray()) {
            result = ArrayType.construct(_constructType(clz.getComponentType(), null), null, null);
        /* Also: although enums can also be fully resolved, there's little
         * point in doing so (T extends Enum<T>) etc.
         */
        } else if (clz.isEnum()) {
            result = new SimpleType(clz);
        /* Maps and Collections aren't quite as hot; problem is, due
         * to type erasure we often do not know typing and can only assume
         * base Object.
         */
        } else if (Map.class.isAssignableFrom(clz)) {
            result = _mapType(clz);
        } else if (Collection.class.isAssignableFrom(clz)) {
            result =  _collectionType(clz);
        } else {
            result = new SimpleType(clz);
        }
        
        synchronized (_typeCache) {
            _typeCache.put(key, result);
        }
        
        return result;
    }

我没有进一步跟踪,但是推测后面将利用Response.class.getMethods()获得并调用Response的setStatus和setMessage方法。

再看看调用代码:

return (T) _readMapAndClose(_jsonFactory.createJsonParser(content), _typeFactory.constructType(valueType));

_jsonFactory.createJsonParser(content)创建了Jackson Streaming库里面的JsonParser对象。

_jsonFactory.createJsonParser(content)
下面代码来自于Streaming库的JsonFactory.java

    /**
     * Method for constructing parser for parsing
     * contents of given String.
     */
    public JsonParser createJsonParser(String content)
        throws IOException, JsonParseException
    {
	Reader r = new StringReader(content);
        // true -> we own the Reader (and must close); not a big deal
        IOContext ctxt = _createContext(r, true);
        // [JACKSON-512]: allow wrapping with InputDecorator
        if (_inputDecorator != null) {
            r = _inputDecorator.decorate(ctxt, r);
        }
	return _createJsonParser(r, ctxt);
    }
这里只是大概了解一下用到了StringReader读取JSON字符串。因为属于Streaming库的内容,先放一放。

真正从JSON字符串读取对象需要用到叫做反序列化对象的东西,这个东西也是只创建一次,然后缓存。

ObjectMapper.java类里面的代码如下:

    /**
     * Method called to locate deserializer for the passed root-level value.
     */
    protected JsonDeserializer<Object> _findRootDeserializer(DeserializationContext ctxt,
            JavaType valueType)
        throws JsonMappingException
    {
        // First: have we already seen it?
        JsonDeserializer<Object> deser = _rootDeserializers.get(valueType);
        if (deser != null) {
            return deser;
        }
        // Nope: need to ask provider to resolve it
        deser = ctxt.findRootValueDeserializer(valueType);
        if (deser == null) { // can this happen?
            throw new JsonMappingException("Can not find a deserializer for type "+valueType);
        }
        _rootDeserializers.put(valueType, deser);
        return deser;
    }
_rootDeserializers 变量类型是ConcurrentHashMap<JavaType, JsonDeserializer<Object>>,因此也是线程安全的。

结论:

1.每个自定义类型,都只会创建一个JavaType(其实是子类SimpleType),并缓存在LinkedHashMap变量中。该缓存变量位于ObjectMapper对象的TypeFactory变量中。

2.每个自定义类型都只有一个反序列化解析器,缓存在ConcurrentHashMap<JavaType, JsonDeserializer<Object>>变量中,该缓存变量是ObjectMapper的变量。

3.为了保证效率,要尽可能的只使用一个ObjectMapper对象。由于1和2的缓存读取和更新都是线程安全的,其他的代码也是线程安全,因此在多线程环境下使用一个ObjectMapper对象也是安全的。



分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics