国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - 實例解析Json反序列化之ObjectMapper(自定義實現反序列化方法)

實例解析Json反序列化之ObjectMapper(自定義實現反序列化方法)

2021-01-08 12:12皮斯特勞沃 Java教程

這篇文章主要介紹了實例解析Json反序列化之ObjectMapper,json自定義序列化的方法,需要的朋友可以了解下。

     對于服務器端開發人員而言,調用第三方接口獲取數據,將其“代理”轉化并返給客戶端幾乎是家常便飯的事兒。    一般情況下,第三方接口返回的數據類型是json格式,而服務器開發人員則需將json格式的數據轉換成對象,繼而對其進行處理并封裝,以返回給客戶端。

     在不是特別考慮效率的情況下(對于搜索、緩存等情形可以考慮使用thrift和protobuffer),通常我們會選取jackson包中的ObjectMapper類對json串反序列化以得到相應對象。通常會選取readValue(String content, Class<T>valueType)方法進行反序列化。

     ObjectMapper的readValue方法將json串反序列化為對象的過程大致為: 依據傳入的json串和目標對象類型分別創建JsonParse和JavaType,隨后生成DeserializationConfig、DeserializationContext、JsonDeserializer,其中JsonDeserializer的實現類決定將要執行哪一種類型解析(Bean、Map、String等),JsonParse中存儲了待解析字符串及其它信息,在解析的過程中通過token來判斷當前匹配的類型(例如:如果遇到{,將其判斷為對象類型的起始位置;遇到[,將其判斷為集合類型的起始位置),一旦確定了類型,則跳入與之對應的反序列化類中進行處理,得到結果,然后token往后移動,接著解析下一個串。可以看做類似遞歸的方式進行解析,當通過token判斷為一個對象時,則會跳入BeanDeserializer中進行解析,隨后遍歷該對象的所有字段,如果字段是字符串,則跳到StringDeserializer中進行解析,如果字段是數組,則跳到CollectionDeserializer中進行解析,直到解析完整個字符串為止。也可以看做類似而樹的深度遍歷,理解起來還是挺容易的。

下面將簡單介紹ObjectMapper的readValue方法進行反序列化的過程:

a:通過json串和對象類型得到JsonParser和JavaType。

?
1
2
3
4
5
public <T> T readValue(String content, Class<T> valueType)
  throws IOException, JsonParseException, JsonMappingException
{
  return (T) _readMapAndClose(_jsonFactory.createParser(content), _typeFactory.constructType(valueType));
}
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
//獲取json解析器,其中包含帶解析的串
public JsonParser createParser(String content) throws IOException, JsonParseException {
  final int strLen = content.length();
  // Actually, let's use this for medium-sized content, up to 64kB chunk (32kb char)
  if (_inputDecorator != null || strLen > 0x8000 || !canUseCharArrays()) {
    // easier to just wrap in a Reader than extend InputDecorator; or, if content
    // is too long for us to copy it over
    return createParser(new StringReader(content));
  }
  IOContext ctxt = _createContext(content, true);
  char[] buf = ctxt.allocTokenBuffer(strLen);
  content.getChars(0, strLen, buf, 0);
  return _createParser(buf, 0, strLen, ctxt, true);
}
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
//將待解析的類型轉化為JavaType類型
public JavaType constructType(Type type) {
  return _constructType(type, null);
}
  protected JavaType _constructType(Type type, TypeBindings context)
{
  JavaType resultType;
  // simple class?
  if (type instanceof Class<?>) {
    resultType = _fromClass((Class<?>) type, context);
  }
  // But if not, need to start resolving.
  else if (type instanceof ParameterizedType) {
    resultType = _fromParamType((ParameterizedType) type, context);
  }
  else if (type instanceof JavaType) { // [Issue#116]
    return (JavaType) type;
  }
  else if (type instanceof GenericArrayType) {
    resultType = _fromArrayType((GenericArrayType) type, context);
  }
  else if (type instanceof TypeVariable<?>) {
    resultType = _fromVariable((TypeVariable<?>) type, context);
  }
  else if (type instanceof WildcardType) {
    resultType = _fromWildcard((WildcardType) type, context);
  } else {
    // sanity check
    throw new IllegalArgumentException("Unrecognized Type: "+((type == null) ? "[null]" : type.toString()));
  }
  if (_modifiers != null && !resultType.isContainerType()) {
    for (TypeModifier mod : _modifiers) {
      resultType = mod.modifyType(resultType, type, context, this);
    }
  }
  return resultType;
}

b、獲取反序列化配置對象和上下文對象,進行第一步的序列化操作。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
protected Object _readMapAndClose(JsonParser jp, JavaType valueType)
  throws IOException, JsonParseException, JsonMappingException
{
  try {
    Object result;
      DeserializationConfig cfg = getDeserializationConfig();
      DeserializationContext ctxt = createDeserializationContext(jp, cfg);
      //依據valueType得到反序列化的解析器
      // 對象對應的是beanDeserializer map對應的是MapDeserializer 。。。。
      JsonDeserializer<Object> deser = _findRootDeserializer(ctxt, valueType);
      if (cfg.useRootWrapping()) {
        result = _unwrapAndDeserialize(jp, ctxt, cfg, valueType, deser);
      } else {
          //如果是對象,則調到BeanDeserializer類中進行解析
        result = deser.deserialize(jp, ctxt);
      }
      ctxt.checkUnresolvedObjectId();
    }
    // Need to consume the token too
    jp.clearCurrentToken();
    return result;
  } finally {
    try {
      jp.close();
    } catch (IOException ioe) { }
  }
}

c、跳入到BeanDeserializer類中。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
下面以BeanDeserializer為例進行講解:
  @Override
public Object deserialize(JsonParser p, DeserializationContext ctxt)
  throws IOException
{
  JsonToken t = p.getCurrentToken();
  // common case first
  if (t == JsonToken.START_OBJECT) { // TODO: in 2.6, use 'p.hasTokenId()'
    if (_vanillaProcessing) {
      return vanillaDeserialize(p, ctxt, p.nextToken());
    }
    p.nextToken();
    if (_objectIdReader != null) {
      return deserializeWithObjectId(p, ctxt);
    }
    return deserializeFromObject(p, ctxt);
  }
  return _deserializeOther(p, ctxt, t);
}
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
 * Streamlined version that is only used when no "special"
 * features are enabled.
 */
private final Object vanillaDeserialize(JsonParser p,
      DeserializationContext ctxt, JsonToken t)
  throws IOException
{
  final Object bean = _valueInstantiator.createUsingDefault(ctxt);
  // [databind#631]: Assign current value, to be accessible by custom serializers
  p.setCurrentValue(bean);
  for (; t == JsonToken.FIELD_NAME; t = p.nextToken()) {
    String propName = p.getCurrentName();
    p.nextToken();
    if (!_beanProperties.findDeserializeAndSet(p, ctxt, bean, propName)) {
      handleUnknownVanilla(p, ctxt, bean, propName);
    }
  }
  return bean;
}
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
  /**
 * Convenience method that tries to find property with given name, and
 * if it is found, call {@link SettableBeanProperty#deserializeAndSet}
 * on it, and return true; or, if not found, return false.
 * Note, too, that if deserialization is attempted, possible exceptions
 * are wrapped if and as necessary, so caller need not handle those.
 *
 * @since 2.5
 */
public boolean findDeserializeAndSet(JsonParser p, DeserializationContext ctxt,
    Object bean, String key) throws IOException
{
  if (_caseInsensitive) {
    key = key.toLowerCase();
  }
  int index = key.hashCode() & _hashMask;
  Bucket bucket = _buckets[index];
  // Let's unroll first lookup since that is null or match in 90+% cases
  if (bucket == null) {
    return false;
  }
  // Primarily we do just identity comparison as keys should be interned
  if (bucket.key == key) {
    try {
      bucket.value.deserializeAndSet(p, ctxt, bean);
    } catch (Exception e) {
      wrapAndThrow(e, bean, key, ctxt);
    }
    return true;
  }
  return _findDeserializeAndSet2(p, ctxt, bean, key, index);
}
?
1
2
3
4
5
6
7
8
9
10
11
12
13
MethodProperty
  @Override
  public void deserializeAndSet(JsonParser jp, DeserializationContext ctxt,
      Object instance) throws IOException
  {
    Object value = deserialize(jp, ctxt);
    try {
        //將得到的結果放入反序列化對應的對象中
      _setter.invoke(instance, value);
    } catch (Exception e) {
      _throwAsIOE(e, value);
    }
  }
?
1
2
3
4
5
6
7
8
9
10
11
12
13
public final Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOException
 {
   JsonToken t = p.getCurrentToken();
   if (t == JsonToken.VALUE_NULL) {
     return (_nullProvider == null) ? null : _nullProvider.nullValue(ctxt);
   }
   if (_valueTypeDeserializer != null) {
     return _valueDeserializer.deserializeWithType(p, ctxt, _valueTypeDeserializer);
   }
   return _valueDeserializer.deserialize(p, ctxt);
 }
 //如果繼承了JsonDeserializer類重寫了deseriakize方法,則會跳轉到對應注入的類中進行處理
 //不出意外的話最后都會調用 DeserializationContext的readValue(JsonParser p, Class<T> type)方法,然后會根據type的類型跳轉到對應的反序列化類中進行處理。
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
public <T> T readValue(JsonParser p, Class<T> type) throws IOException {
    return readValue(p, getTypeFactory().constructType(type));
  }
  @SuppressWarnings("unchecked")
  public <T> T readValue(JsonParser p, JavaType type) throws IOException {
    //得到最終解析的類型,Map list string。。。。
    JsonDeserializer<Object> deser = findRootValueDeserializer(type);
    if (deser == null) {
    }
    return (T) deser.deserialize(p, this);
  }
  //例如這里如果是一個map,則會調用MapDeserializer的deserizlize方法得到最后的返回結果。
  //對于集合類,會通過token按照順序解析生成一個個的集合對象并放入集合中。
JsonToken t;
    while ((t = p.nextToken()) != JsonToken.END_ARRAY) {
      try {
        Object value;
        if (t == JsonToken.VALUE_NULL) {
          value = valueDes.getNullValue();
        } else if (typeDeser == null) {
          value = valueDes.deserialize(p, ctxt);
        } else {
          value = valueDes.deserializeWithType(p, ctxt, typeDeser);
        }
        if (referringAccumulator != null) {
          referringAccumulator.add(value);
        } else {
          result.add(value);
        }
      } catch (UnresolvedForwardReference reference) {
        if (referringAccumulator == null) {
          throw JsonMappingException
              .from(p, "Unresolved forward reference but no identity info", reference);
        }
        Referring ref = referringAccumulator.handleUnresolvedReference(reference);
        reference.getRoid().appendReferring(ref);
      } catch (Exception e) {
        throw JsonMappingException.wrapWithPath(e, result, result.size());
      }
    }
    return result;

 在不同的業務場景下,第三方接口返回的數據類型可能會發生變化,比如最初第三方業務代碼是使用php實現的,而與之對接的服務器端也是用php實現的。后來,又成立了以Java為開發語言的服務器端開發小組,此時,對接第三方可能會出現問題。第三方返回數據類型的不唯一性,可能會使Java開發人員無法“正常”反序列化第三方接口返回的json串。例如:第三方接口返回的字段中,當字段為空時,返回的是數組;而字段不為空時,返回的卻是對象。這樣,那么通過ObjectMapper進行解析時,就會拋出異常,導致服務器端無法正常將數據返回給客戶端。面對這樣的問題,可能有 以下兩種解決方法:

     第一種解決方法是對bean中每個字段set方法內進行判斷,當解析字符串是一個數組時,則返回空對象;
當解析的字符串不為空時,就會特別的麻煩,默認情況下,會將Json串解析成一個map,其中key為bean中字段的名稱,value為bean的值。這樣,就需要創建一個新的bean,隨后依次從map中取出對應字段的值,然后再set到bean中。顯然,這種方式很麻煩,一旦第三方字段發生變化時,需要不停地維護這段代碼。

     第二種解決方法是繼承JsonDeserialize,并重寫反序列化方法。通過源碼可知,JsonDeserializer抽象類是處理反序列化的類,只需在Bean類中的字段上加入注解@JsonDeserialize(using=xxx.class),并且xxx類要繼承JsonDeserializer類,且重新對應的deserialize方法,在該方法中進行相應處理即可。在該方法中處理待反序列化字段可能出現的多種不同情況,詳情見源碼。

這里需要注意的是:當反序列化字段是一個對象,而第三方返回的數據為一個數組時,在重寫deserialize方法時,如果判斷出當前token指向的是一個數組,而此時需得到空對象。此時,不能直接返回空對象,必須調用readValue方法,目的是將token移動到正確的位置,否則,將創建一些奇怪的對象。

     對于第二種解決方法,下面舉例說明:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
package com.string;
import java.util.Map;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
public class Comment {
  public String id;
  @JsonDeserialize(using = ImgPackSerializer.class)
  public Map<String, String> imgPack;
  @JsonDeserialize(using = CoopSerializer.class)
  public Coop coop;
  public Coop getCoop() {
    return coop;
  }
  public void setCoop(Coop coop) {
    this.coop = coop;
  }
  public Map<String, String> getImgPack() {
    return imgPack;
  }
  public void setImgPack(Map<String, String> imgPack) {
    this.imgPack = imgPack;
  }
  public String getId() {
    return id;
  }
  public void setId(String id) {
    this.id = id;
  }
}
class Coop {
  public Integer age;
  public Integer getAge() {
    return age;
  }
  public void setAge(Integer age) {
    this.age = age;
  }
}
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
package com.string;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.ObjectMapper;
public class TestJson {
  static ObjectMapper OBJECT_MAPPER = new ObjectMapper();
 
  public static void main(String[] args) {
    String s = "{\"code\":\"1\",\"comm\":[{\"imgPack\":{\"abc\":\"abc\"},\"coop\":[]}],\"name\":\"car\"}";
    try {
      Response readValue = OBJECT_MAPPER.readValue(s, Response.class);
      System.err.println(readValue.toString());
    } catch (IOException e) {
      e.printStackTrace();
    }
  }
}
class Response {
  public String code;
  public List<Comment> comm;
  public String name;
 
  public String getName() {
    return name;
  }
  public void setName(String name) {
    this.name = name;
  }
  public String getCode() {
    return code;
  }
  public void setCode(String code) {
    this.code = code;
  }
  public List<Comment> getComm() {
    return comm;
  }
  public void setComm(List<Comment> comm) {
    this.comm = comm;
  }
}
class CoopSerializer extends JsonDeserializer<Coop> {
  @Override
  public Coop deserialize(JsonParser jp, DeserializationContext ctxt)
      throws IOException, JsonProcessingException {
    JsonToken currentToken = jp.getCurrentToken();
    if (currentToken == JsonToken.START_ARRAY) {
      // return null; //error may create more object
      // jp.nextToken(); //error
      return ctxt.readValue(jp, Object.class) == null ? null : null;
    } else if (currentToken == JsonToken.START_OBJECT) {
      return (Coop) ctxt.readValue(jp, Coop.class);
    }
    return null;
  }
}
class ImgPackSerializer extends JsonDeserializer<Map<String, String>> {
  @Override
  public Map<String, String> deserialize(JsonParser jp,
      DeserializationContext ctxt) throws IOException,
      JsonProcessingException {
    JsonToken currentToken = jp.getCurrentToken();
    if (currentToken == JsonToken.START_ARRAY) {
      return ctxt.readValue(jp, Object.class) == null ? null : null;
    } else if (currentToken == JsonToken.START_OBJECT) {
      return (Map<String, String>) ctxt.readValue(jp, Map.class);
    }
    return null;
  }
}

總結

以上就是本文關于實例解析Json反序列化之ObjectMapper(自定義實現反序列化方法)的全部內容,希望對大家有所幫助。歡迎大家參閱本站其他專題,有什么問題可以留言,小編會及時回復大家的。

原文鏈接:http://blog.csdn.net/pistolove/article/details/50868105

延伸 · 閱讀

精彩推薦
Weibo Article 1 Weibo Article 2 Weibo Article 3 Weibo Article 4 Weibo Article 5 Weibo Article 6 Weibo Article 7 Weibo Article 8 Weibo Article 9 Weibo Article 10 Weibo Article 11 Weibo Article 12 Weibo Article 13 Weibo Article 14 Weibo Article 15 Weibo Article 16 Weibo Article 17 Weibo Article 18 Weibo Article 19 Weibo Article 20 Weibo Article 21 Weibo Article 22 Weibo Article 23 Weibo Article 24 Weibo Article 25 Weibo Article 26 Weibo Article 27 Weibo Article 28 Weibo Article 29 Weibo Article 30 Weibo Article 31 Weibo Article 32 Weibo Article 33 Weibo Article 34 Weibo Article 35 Weibo Article 36 Weibo Article 37 Weibo Article 38 Weibo Article 39 Weibo Article 40
主站蜘蛛池模板: 午夜视频网站 | av在线播放网站 | 黄色片网址在线观看 | 中文字幕一区在线 | 欧美日韩成人 | 成人午夜小视频 | 亚洲视频在线免费观看 | 国产中文字幕在线观看 | 一级欧美日韩 | 久久久精品视频免费观看 | 色综合天天综合网国产成人网 | 国产精品美女久久久网av | 一级片在线观看 | caoporn视频 | 欧美久久久久 | 亚洲成人黄色 | 激情综合在线观看 | 国产精品免费av | 中文字幕一区在线观看视频 | 中国大陆高清aⅴ毛片 | 亚洲一区二区三区精品动漫 | a免费网站 | 国产v日产∨综合v精品视频 | 午夜精品久久久久久久久久久久 | 欧美1区2区 | 日韩电影免费在线观看 | 免费视频一区二区 | 日韩精品| 少妇自摸视频 | 另类视频网站 | 成人午夜小视频 | 免费av一区二区三区 | 一区二区三区在线免费视频 | 色天天综合 | аⅴ资源新版在线天堂 | 亚洲精品日韩综合观看成人91 | 91在线视频在线 | 五月婷婷视频 | 精品视频免费在线 | 天天操网址| 成人精品 |