2017-09-15 63 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'实例。 –