一个对象(某个字段为枚举类型,为了避免采用默认的序列化过程,用@JSONField
指定了序列化器和反序列器,过程见旧博文),将其放到JSONArray
中再序列化JSONArray
对象,用获得的JSON
字符串再反序列化时,发现可以正常反序列化出JSONArray
,而对JSONArray
中的某个元素再反序列化成类对象时,出错。html
一样用旧博文的示例作个简单测试。
基本对象类Article
。java
public class Article { private String title; private String content; @JSONField(serializeUsing = AuditStatusCodec.class, deserializeUsing = AuditStatusCodec.class) private AuditStatus status; public Article(){ } public Article(String title, String content, AuditStatus status){ this.title = title; this.content = content; this.status = status; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } public AuditStatus getStatus() { return status; } public void setStatus(AuditStatus status) { this.status = status; } @Override public String toString() { return "Article{" + "title='" + title + '\'' + ", content='" + content + '\'' + ", status=" + status + '}'; } @Override public boolean equals(Object o) { if (this == o){ return true; } if (o == null || getClass() != o.getClass()){ return false; } Article article = (Article) o; return Objects.equals(title, article.title) && Objects.equals(content, article.content) && status == article.status; } @Override public int hashCode() { return Objects.hash(title, content, status); } }
枚举类型AuditStatus
。json
public enum AuditStatus { /** * 审核中 */ AUDITING(1), /** * 经过 */ PASSED(2), /** * 失败 */ FAILED(3); private int code; AuditStatus(int code){ this.code = code; } public int getCode() { return code; } public static AuditStatus convert(int code){ AuditStatus[] enums = AuditStatus.values(); for(AuditStatus e : enums){ if(e.code == code){ return e; } } return null; } }
以及序列化/反序列化器AuditStatusCodec
缓存
public class AuditStatusCodec implements ObjectSerializer, ObjectDeserializer { @Override public <T> T deserialze(DefaultJSONParser parser, Type type, Object fieldName) { Object value = parser.parse(); return value == null ? (T) value : (T) AuditStatus.convert(TypeUtils.castToInt(value)); } @Override public int getFastMatchToken() { return 0; } @Override public void write(JSONSerializer serializer, Object object, Object fieldName, Type fieldType, int features) throws IOException { serializer.write(((AuditStatus)object).getCode()); } }
按照出问题的状况,写模拟用例:ide
public class FastJsonTest { @Test public void deserializeTest(){ testJSONParse(); testJSONArrayParse(); } protected static void testJSONParse(){ System.out.println("**************Start Test JSON Parse"); Article originalArticle = new Article("Article 1", "This is content", AuditStatus.AUDITING); String jsonStr = JSON.toJSONString(originalArticle); System.out.println("Serialize to json string: " + jsonStr); Article deserializeArticle = JSON.parseObject(jsonStr, Article.class); System.out.println("Deserialize to Java Object: " + deserializeArticle + "; and the status is " + deserializeArticle.getStatus()); //Equals Assert.assertTrue(deserializeArticle.getStatus().equals(AuditStatus.AUDITING)); Assert.assertEquals(originalArticle, deserializeArticle); } protected static void testJSONArrayParse(){ System.out.println("**************Start Test JSONArray Parse"); JSONArray arr = new JSONArray(); Article originArticle = new Article("Article 1", "This is content", AuditStatus.AUDITING); arr.add(originArticle); String jsonArrStr = JSON.toJSONString(arr); System.out.println("Serialize to json array string: " + jsonArrStr); arr = JSON.parseArray(jsonArrStr); Article deserializeArticle = arr.getObject(0, Article.class); System.out.println("Deserialize to json arr, then to java object: " + deserializeArticle + "; ant the status is " + deserializeArticle.getStatus()); //Not Equals Assert.assertFalse(deserializeArticle.getStatus().equals(AuditStatus.AUDITING)); Assert.assertNotEquals(originArticle, deserializeArticle); } }
看控制台输出的状况:测试
**************Start Test JSON Parse Serialize to json string: {"content":"This is content","status":1,"title":"Article 1"} Deserialize to Java Object: Article{title='Article 1', content='This is content', status=AUDITING}; and the status is AUDITING **************Start Test JSONArray Parse Serialize to json array string: [{"content":"This is content","status":1,"title":"Article 1"}] Deserialize to json arr, then to java object: Article{title='Article 1', content='This is content', status=PASSED}; and the status is PASSED
上述代码中testJsonParse
没有把类对象放到JSONArray
中,能够从结果中看出序列化和反序列化过程均正常。而testJSONArrayParse
先把类对象放到JSONArray
中,在从JSONArray
中取出对象反序列化,反序列化的结果就不正常了。this
为何JSONObject
和JSONArray
的反序列化过程获得的结果不一致?二者的反序列过程差别在哪?spa
遇事不决,开始DEBUG
。code
首先,JSON
是一个门面类,提供出一些静态的方法供外部使用。好比说parseObject()
方法。其内部会建立解析器DefaultJSONParser
,并将解析委托给解析器执行。htm
DefualtJSONParser
在建立时接受输入,全局配置及特性,至关于获取到了本次解析全部的数据。同时DefualtJSONParser
的内部建立了一些用于解析的组件,例如JSONLexer
(用于字符串解析)。解析过程在parseObject
中执行,parseObject
会经过ParseConfig
(保存解析配置的一个全局对象)获取到解析器ObjectDeserializer
,并由解析器处理真正的解析过程。
在经过Class
获取ObjectDeserializer
时,首先会肯定ParserConfig
中是否缓存了对应的反序列化器,若是不存在,则会新建一个JavaBeanDeserializer
(对于通常Java对象而言)。在新建过程当中,会解析Class
的属性,并保存在JavaBeanInfo
中。 解析器的解析过程就是对比JSON
字符串中的KEY
和JavaBeanInfo
的过程,把对应的值反序列化出来(判断是否有JSONField
注解,并根据注解的属性处理也在这一步),最终还原对象。
以流程图表示上述过程:
JSONArray.getObject()
会先从JSONArray
中获取出Object
,而后调用TypeUtils
对Object
经过TypeUtils.castToJavaBean()
转型。
TypeUtils
经过根据须要转型的类型从ParserConfig
中获取ObjectDeserializer
反序列化器,对于普通 Java Bean 而言,是JavaBeanDeserializer
。
因为JSONArray
中取出的Object
其实是JSONObject
对象,所以会由JavaBeanDeserializer
反序列化器的createInstance()
方法执行反序列化,获得对象。
以流程图表示上述过程:
deserialize
在反序列化时,会从class
上获取更多的属性,其中就包括JSONField
注解上的信息,而createInstance
获取的信息较少,所以忽略JSONField
所带的信息,致使自定义的反序列化器在反序列化时失效。
为何都是反序列化过程,两者在行为和表现上会有所不一样?官方是如何定义deserialize
和createInstance
的?
上述这些问题还须要查询更多资料来明确。也但愿了解原因的读者进行告知。
解决的办法不先转换成JSONArray
,而后再反序列化对象。而是经过JSON.parseArray
直接转成对象的List
。