被Spring的JSON序列化困惑

时间:2017-09-15 21:58:14

标签: java json spring spring-mvc resttemplate

我有一个用Java编写的Spring Boot和Spring MVC应用程序,它响应带有包含字节数组的对象的get请求:

public HashedPasswordSpec get() {
    User user = userRepository.findByEmail("example@example.com");
    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}

正如您所看到的,salt被序列化为Base64,但这并不是Gson开箱即用的字节数组。 Spring Boot是否扩展Gson以将字节数组序列化为Base64字符串?如果是这样,RestTemplate是否省略了这个扩展名?它们彼此不兼容吗?我在这里缺少什么?

1 个答案:

答案 0 :(得分:1)

默认情况下,RestTemplateSpring MVC's infrastructure都会注册各种序列化程序/反序列化程序,具体取决于它们在类路径中找到的内容。

具体来说,他们正在寻找杰克逊和Gson的JSON序列化,如果发现它们,他们都更喜欢杰克逊。

在您的情况下,您的服务器将byte[]序列化为Base64字符串这一事实暗示它正在使用Jackson,因为这是其默认策略(请参阅ByteArraySerializer)。

我们可以从您的错误日志中看到RestTemplate无法使用Gson解析JSON。对于类型为Gson的字段,byte[]不使用或期望Base64字符串,它只需要一个包含数字的JSON数组。

因此,您的客户端未将Jackson注册为序列化程序,因为它不在类路径中,或者因为您已注册了不包含Jackson变体的HttpMessageConverter个实例的自定义列表。