2017-09-15 62 views
0

我用Java編寫的與Spring引導和Spring MVC,響應與包含字節數組對象的GET請求的應用:在客戶端我試圖由Spring的JSON序列困惑

public HashedPasswordSpec get() { 
    User user = userRepository.findByEmail("[email protected]"); 
    return user.getHashedPasswordSpec(); 
} 

使用相同的類自動反序列化:

RestTemplate restTemplate = new RestTemplate(); 
HashedPasswordSpec spec = restTemplate.getForObject("http://localhost:8080/v1/hashed-password-spec", HashedPasswordSpec.class); 

失敗,出現此錯誤:

Caused by: com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_ARRAY but was STRING at line 1 column 10 path $.salt 
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:224) 
    at com.google.gson.Gson.fromJson(Gson.java:887) 
    at com.google.gson.Gson.fromJson(Gson.java:852) 
    at org.springframework.http.converter.json.GsonHttpMessageConverter.readTypeToken(GsonHttpMessageConverter.java:161) 
    ... 39 more 
Caused by: java.lang.IllegalStateException: Expected BEGIN_ARRAY but was STRING at line 1 column 10 path $.salt 
    at com.google.gson.stream.JsonReader.beginArray(JsonReader.java:350) 
    at com.google.gson.internal.bind.ArrayTypeAdapter.read(ArrayTypeAdapter.java:70) 
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:129) 
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:220) 
    ... 42 more 

saltbyte[]。當我反而得到一個字符串,並打印出來:

String spec = restTemplate.getForObject("http://localhost:8080/v1/hashed-password-spec", String.class); 
System.out.println(spec); 

我看到這一點:

{"salt":"2GKm9SVxsvLmwaydk8heK/eB94HoPR21+2rTmKMjWo0=","algorithm":"SCrypt","cost":12,"blockSize":8,"parallelization":1,"keyLength":256} 

正如你所看到的,鹽被序列爲Base64但是這不是什麼GSON不開箱與字節數組。 Spring Boot是否將Gson擴展爲將字節數組序列化爲Base64字符串?如果是這樣,RestTemplate會忽略此擴展名嗎?它們是否相互矛盾?我在這裏錯過了什麼?

+1

Spring根據類路徑中的內容註冊了默認的序列化器/反序列化器。你的服務器classpath是否包含Jackson?你的客戶端類路徑是否只包含Gson? –

+0

@SotiriosDelimanolis:服務器和客戶端都在類路徑中包含Gson,儘管不是直接通過另一個依賴關係。我不確定傑克遜。 – Pablo

+0

默認情況下,Jackson將'byte []'序列化爲base64字符串iirc。 Gson沒有。所以你的服務器很可能在它的類路徑上有Jackson(它的序列化程序的註冊順序高於Gson)。 –

回答

1

RestTemplateSpring MVC's infrastructure默認情況下根據他們在類路徑中找到的內容註冊各種序列化器/反序列化器。

具體來說,他們正在尋找Jackson和Gson的JSON序列化,如果發現它們都更喜歡Jackson。

就你而言,事實上你的服務器將byte[]序列化爲Base64字符串,提示它使用Jackson,因爲這是它的默認策略(請參閱ByteArraySerializer)。

而且我們可以從錯誤日誌中看到RestTemplate無法解析與Gson的JSON。 Gson不使用,也不期望Base64字符串用於byte[]類型的字段,它只是期望包含數字的JSON數組。

因此,您的客戶沒有將Jackson註冊爲序列化程序,要麼是因爲它不在類路徑中,要麼是因爲您註冊了不包含Jackson變體的HttpMessageConverter實例的自定義列表。

+0

'Jackson2'的排序高於'gson'。那麼解決這個問題的解決方案是什麼?你必須做'gson'來註冊而不是'Jackson2'?刪除Jackson2? Thx –

+1

@MinhKieu是的,你可以從classpath中刪除Jackson,或者你可以手動決定並註冊你想要的'HttpMessageConverter'實例。 –