差異處

這裏顯示兩個版本的差異處。

連向這個比對檢視

java:jackson:annotation:jsonserialize:module_annotation [2018/06/03 16:29]
tony [基於第一個做法 - 改進xml輸出]
java:jackson:annotation:jsonserialize:module_annotation [2023/06/25 09:48]
行 1: 行 1:
-{{tag>​java jackson}} 
-====== Jackson - Convert the value fields with special char ====== 
-===== Problem ===== 
-這陣子在擴充Rest API的功能時,聽同事說某功能輸出xml格式下,因內容使用unicode,導致無法正常在瀏覽器上顯示。xml並非不支援unicode,而是因為瀏覽器只支援xml 1.0;我們資料剛好不在1.0所規範的範圍內,因此瀏覽器才把它認為不合法。 
-===== Research ===== 
-為什麼Json沒這問題呢?​ 對於Json來說,unicode內容有兩種選擇:​ 
-  - 以代碼顯示:​ \u0001\u0002\u0003。 
-  - 以原始樣式顯示:​ 即欄位定義為unicode type。 
-而xml在瀏覽器接收到代碼後,會做轉換;無法轉換時,就會報錯。在花些時間研究後,得知Amazon的Simple DB針對client傳遞或是要回應給client的資料,如果有這種情況,會將內容做base64的encoding。雖然對user來說是個小effort,但也不失為一個解法。 
-===== How to? ===== 
-假設我們的Event Bean物件是這樣子:​ 
-<code java> 
-public class Event { 
- private Date date; 
-  
- private String message; 
-  
- public Date getDate(){ 
- return date; 
- } 
-  
- public void setDate(Date date){ 
- this.date = date; 
- } 
-  
- public String getMessage(){ 
- return message; 
- } 
-  
- public void setMessage(String message){ 
- this.message = message; 
- } 
-} 
-</​code>​ 
-當message中包含對xml不合法的字元,就會發生我所敘述的問題。 
-==== 第一個方法 - 直接操作message ==== 
-最簡單的方法,當然就是直接將message做base64的encoding。但如果直接把值塞到物件內,可能會讓使用到的client必須自行去decoding。因此,如果選擇使用這種方式,建議使用@JsonSerialize與@JsonDeserialize:​ 
-<code java> 
-    @JsonSerialize(using=Base64StringSerializer.class) 
-    @JsonDeserialize(using=Base64StringDeserializer.class) 
-    private String message; 
-</​code>​ 
-這方法可以讓物件在輸出為xml或json格式時,才被做encoding;如果user將值給塞回來時,也會透過descerializer還原為好操作的內容。 
-==== 基於第一個做法 - 改進xml輸出 ==== 
-使用第一個方法message所輸出的xml會長這樣子:​ 
-<code xml> 
-<​message>​dGVzdAECAw==</​message>​ 
-</​code>​ 
-對於沒讀使用手冊的user來說,可能無法知道它是經過encoding;因此比較好的顯示方式為:​ 
-<code xml> 
-<message encoding="​base64">​dGVzdAECAw==</​message>​ 
-</​code>​ 
-這時在做序列化時,就要區分xml與json的做法:​ (Base64StringSerializer) 
-<code java> 
-@Override 
-public void serialize(String value, JsonGenerator jgen, 
- SerializerProvider provider) throws IOException { 
- String encodingVal = new String(Base64.getEncoder().encode(value.getBytes()));​ 
- if( jgen instanceof ToXmlGenerator ) { 
- ToXmlGenerator xgen = (ToXmlGenerator) jgen; 
-  
- xgen.writeStartObject();​ 
- xgen.setNextIsAttribute(true);​ 
- xgen.writeFieldName("​type"​);​ 
- xgen.writeString("​base64"​);​ 
- xgen.setNextIsAttribute(false);​ 
-  
- xgen.setNextIsUnwrapped(true);​ 
- xgen.writeFieldName("​value"​);​ 
- xgen.writeObject(encodingVal);​ 
- xgen.setNextIsUnwrapped(false);​ 
-  
- xgen.writeEndObject();​ 
- } else { 
- jgen.writeString(encodingVal);​  
- } 
-} 
-</​code>​ 
-反序列化時,就是把輸入的base64轉回去,這部分看需求決定需不需要做:​ (Base64StringDeserializer) 
-<code java> 
-public class Base64StringDeserializer extends StdDeserializer<​String>​ { 
  
- private static final long serialVersionUID = 1L; 
- 
- public Base64StringDeserializer() { 
- super(String.class);​ 
- } 
- 
- @Override 
- public String deserialize(JsonParser parser, DeserializationContext context) 
- throws IOException,​ JsonProcessingException { 
- String text = parser.getValueAsString();​ 
- return new String(Base64.getDecoder().decode(text));​ 
- } 
-} 
-</​code>​ 
-我的範例是把json與xml格式中的message都透過base64做轉換,假如想把對json與xml的操作分開,可以透過jackson提供的module功能。在第二個個方法中會使用到,這部分你們可以自行嘗試。 
-==== 第二個做法 - 宣告一個EncodingText物件 ==== 
- 
- 
- 
-===== Reference ===== 
-  * [[https://​en.wikipedia.org/​wiki/​Valid_characters_in_XML|Valid_characters_in_XML]] 
-  * [[https://​zh.wikipedia.org/​wiki/​Unicode#​XML.E5.92.8CUnicode|XML & Unicode]] 
-  * [[http://​docs.aws.amazon.com/​AmazonSimpleDB/​latest/​DeveloperGuide/​InvalidCharacters.html|Amazon Simple DB - InvalidCharacters]] 
-  * [[http://​stackoverflow.com/​questions/​19847094/​jackson-xml-annotations-string-element-with-attribute|jackson-xml-annotations-string-element-with-attribute]] 
- 
- 
-=====    ===== 
----- 
-\\ 
-~~DISQUS~~