Java 被春天迷住了';s JSON序列化

Java 被春天迷住了';s JSON序列化,java,json,spring,spring-mvc,resttemplate,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 restT

我有一个用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
salt
字节[]
。当我得到一个字符串并打印出来时:

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是否会忽略此扩展?他们彼此不相容吗?这里我缺少什么?

根据在类路径上找到的内容,默认情况下,同时注册各种序列化程序/反序列化程序

具体来说,他们正在寻找Jackson和Gson的JSON序列化,如果找到了,他们都更喜欢Jackson

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

我们可以从错误日志中看到,
restemplate
无法使用
Gson
解析JSON
Gson
对于类型为
byte[]
的字段,既不使用也不希望使用Base64字符串,它只希望使用包含数字的JSON数组

因此,您的客户端没有将Jackson注册为序列化程序,这可能是因为它不在类路径上,也可能是因为您注册了不包含Jackson变体的
HttpMessageConverter
实例的自定义列表。

默认情况下,同时注册和,各种序列化程序/反序列化程序取决于它们在类路径上找到的内容

具体来说,他们正在寻找Jackson和Gson的JSON序列化,如果找到了,他们都更喜欢Jackson

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

我们可以从错误日志中看到,
restemplate
无法使用
Gson
解析JSON
Gson
对于类型为
byte[]
的字段,既不使用也不希望使用Base64字符串,它只希望使用包含数字的JSON数组


因此,您的客户端没有将Jackson注册为序列化程序,这可能是因为它不在类路径上,也可能是因为您注册了不包含Jackson变量的
HttpMessageConverter
实例的自定义列表。

Spring根据类路径中的内容注册默认序列化程序/反序列化程序。您的服务器类路径是否包含Jackson?您的客户端类路径是否只包含Gson?@SotiriosDelimanolis:服务器和客户端都通过另一个依赖项在类路径中包含Gson,尽管不是直接包含。我不确定Jackson的情况。默认情况下,Jackson将
byte[]
序列化为base64字符串iirc。格森没有。因此,您的服务器很可能在其类路径上有Jackson(序列化程序的注册顺序高于Gson)。@SotiriosDelimanolis:很高兴知道。。。服务器的类路径中肯定有Jackson(一个spring组件拉它)。我将Jackson添加到客户端,得到了完全相同的错误,Gson试图解析JSON负载。当他在场的时候,他不选择杰克逊而不是格森吗?啊。。。我错过了杰克逊的其他部分。是的,就是这样。谢谢你@SotiriosDelimanolis。您想添加它作为答案,这样我就可以接受它了吗?Spring根据类路径中的内容注册默认的序列化器/反序列化器。您的服务器类路径是否包含Jackson?您的客户端类路径是否只包含Gson?@SotiriosDelimanolis:服务器和客户端都通过另一个依赖项在类路径中包含Gson,尽管不是直接包含。我不确定Jackson的情况。默认情况下,Jackson将
byte[]
序列化为base64字符串iirc。格森没有。因此,您的服务器很可能在其类路径上有Jackson(序列化程序的注册顺序高于Gson)。@SotiriosDelimanolis:很高兴知道。。。服务器的类路径中肯定有Jackson(一个spring组件拉它)。我将Jackson添加到客户端,得到了完全相同的错误,Gson试图解析JSON负载。当他在场的时候,他不选择杰克逊而不是格森吗?啊。。。我错过了杰克逊的其他部分。是的,就是这样。谢谢你@SotiriosDelimanolis。你想把它作为一个答案添加进来,这样我就可以接受了吗?
Jackson2
的顺序比
gson
高。那么,解决这个问题的办法是什么呢?要注册而不是注册
Jackson2
,您需要做什么?拆下千斤顶2?Thx@MinhKieu是的,您可以从类路径中删除Jackson,也可以手动决定并注册所需的
HttpMessageConverter
实例。
Jackson2
的顺序高于
gson
。那么,解决这个问题的办法是什么呢?要注册而不是注册
Jackson2
,您需要做什么?拆下千斤顶2?Thx@MinhKieu是的,您可以从类路径中删除Jackson,也可以手动决定并注册所需的
HttpMessageConverter
实例。