ServiceComb-Java-Chassis 使用CSERestTemplate访问出现类型转化失败
String jsonResult = restTemplate.getForObject(url, String.class) 出现异常:com.alibaba.fastjson.JSONObject cannot be cast to java.lang.String
java-chassis版本2.6.0
发现在依赖的sdk包中存在ProduceProcessor的SPI配置 FastJsonProduceProcessor StringProduceProcessor org.apache.servicecomb.common.rest.codec.produce.ProduceJsonProcessor org.apache.servicecomb.common.rest.codec.produce.ProduceTextPlainProcessor 前两个可以进行配置关闭,后两个还是会起作用,继而出现异常 java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to com.alibaba.fastjson.JSONObject
restTemplate.getForObject(url, JSONObject.class)
跟踪代码发现,CSERestTemplate中的类型参数和原生RestTemplate中的含义是有很大差异的,因为CSERestTemplate并不支持HttpMessageConverter(它能将响应数据转化为客户端真正想要的数据类型),CSERestTemplate的类型实际则依赖服务端,服务端响应数据结果定义不好、不清晰,客户端跟着摆烂。尤其在这种平台+微服务APP的情况下,上下游存在很大的差别,在开发的方方面面上
CSERestTemplate 只是实现了 RestTemplate 的 get/post等接口(早期选型没做好,对外提供 RestOperations 其实更好), java chassis 与 spring mvc的区别参考: https://github.com/apache/servicecomb-java-chassis/issues/2766 。
平台服务端提供的接口 ,从JavaType responseType = invocation.findResponseType(responseEx.getStatus());获取到responseType大部分都是Object.class,ProduceJsonProcessor转化之后就是个Map;客户端就得自己去完成转换,大量的这类代码。如果平台主动去改服务端,几十个客户端也得跟着动,就因为servicecomb这种类型的强相关
restTemplate.getForObject(url, Map.class) 或者 restTemplate.getForObject(url, Object.class) 可以?
restTemplate.getForObject(url, Map.class)或者restTemplate.getForObject(url, Object.class)可以?
可以的,但是这种写法真的是缺少了RestTemplate中的精华:类型转换,增加了业务层的复杂
restTemplate.getForObject(url, Map.class)或者restTemplate.getForObject(url, Object.class)可以?可以的,但是这种写法真的是缺少了RestTemplate中的精华:类型转换,增加了业务层的复杂 有点先入为主,但是这种东西,不得不承认,用起来很舒服
发现在依赖的sdk包中存在ProduceProcessor的SPI配置 FastJsonProduceProcessor StringProduceProcessor org.apache.servicecomb.common.rest.codec.produce.ProduceJsonProcessor org.apache.servicecomb.common.rest.codec.produce.ProduceTextPlainProcessor 前两个可以进行配置关闭,后两个还是会起作用,继而出现异常 java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to com.alibaba.fastjson.JSONObject
估计你的咨询下你们项目这块的背景。FastJsonProduceProcessor 应该就是处理你说的场景的。 java chassis默认情况下并不支持JsonObject,也不建议这么使用。 详细说明参考: https://servicecomb.apache.org/references/java-chassis/zh_CN/build-provider/interface-constraints.html
restTemplate.getForObject(url, Map.class)或者restTemplate.getForObject(url, Object.class)可以?可以的,但是这种写法真的是缺少了RestTemplate中的精华:类型转换,增加了业务层的复杂 有点先入为主,但是这种东西,不得不承认,用起来很舒服
我理解 JsonObject 和 Map几乎是等价的,所以提了这个。 你期望 restTemplate.getForObject(url, MyCustomBean.class) 这种?为啥都会需要 JsonObject 了? 这个用起来不存在舒服的说法呀。
发现在依赖的sdk包中存在ProduceProcessor的SPI配置 FastJsonProduceProcessor StringProduceProcessor org.apache.servicecomb.common.rest.codec.produce.ProduceJsonProcessor org.apache.servicecomb.common.rest.codec.produce.ProduceTextPlainProcessor 前两个可以进行配置关闭,后两个还是会起作用,继而出现异常 java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to com.alibaba.fastjson.JSONObject
估计你的咨询下你们项目这块的背景。FastJsonProduceProcessor 应该就是处理你说的场景的。 java chassis默认情况下并不支持JsonObject,也不建议这么使用。 详细说明参考: https://servicecomb.apache.org/references/java-chassis/zh_CN/build-provider/interface-constraints.html
跟我们项目没啥关系,我们直接被平台挖的坑绊倒了。我跟完代码后,也慢慢理解为啥他为啥怎么做了:从JavaType responseType = invocation.findResponseType(responseEx.getStatus());获取到responseType大部分都是Object.class,ProduceJsonProcessor转化之后就是个Map,自已搞个FastJsonProduceProcessor 转换成JSONObject(提供了get().asXXX()),好像是比Map取值强转好多l
restTemplate.getForObject(url, Map.class)或者restTemplate.getForObject(url, Object.class)可以?可以的,但是这种写法真的是缺少了RestTemplate中的精华:类型转换,增加了业务层的复杂 有点先入为主,但是这种东西,不得不承认,用起来很舒服
我理解 JsonObject 和 Map几乎是等价的,所以提了这个。 你期望
restTemplate.getForObject(url, MyCustomBean.class)这种?为啥都会需要 JsonObject 了? 这个用起来不存在舒服的说法呀。
从JavaType responseType = invocation.findResponseType(responseEx.getStatus());获取到responseType大部分都是Object.class,能用 MyCustomBean.class接收吗
restTemplate.getForObject(url, Map.class)或者restTemplate.getForObject(url, Object.class)可以?可以的,但是这种写法真的是缺少了RestTemplate中的精华:类型转换,增加了业务层的复杂 有点先入为主,但是这种东西,不得不承认,用起来很舒服
我理解 JsonObject 和 Map几乎是等价的,所以提了这个。 你期望
restTemplate.getForObject(url, MyCustomBean.class)这种?为啥都会需要 JsonObject 了? 这个用起来不存在舒服的说法呀。从JavaType responseType = invocation.findResponseType(responseEx.getStatus());获取到responseType大部分都是Object.class,能用 MyCustomBean.class接收吗
可以。这里取到的类型根据 restTemplate.getForObject(url, MyCustomBean.class) 决定的。
restTemplate.getForObject(url, Map.class)或者restTemplate.getForObject(url, Object.class)可以?可以的,但是这种写法真的是缺少了RestTemplate中的精华:类型转换,增加了业务层的复杂 有点先入为主,但是这种东西,不得不承认,用起来很舒服
我理解 JsonObject 和 Map几乎是等价的,所以提了这个。 你期望
restTemplate.getForObject(url, MyCustomBean.class)这种?为啥都会需要 JsonObject 了? 这个用起来不存在舒服的说法呀。从JavaType responseType = invocation.findResponseType(responseEx.getStatus());获取到responseType大部分都是Object.class,能用 MyCustomBean.class接收吗
可以。这里取到的类型根据
restTemplate.getForObject(url, MyCustomBean.class)决定的。
只保留 org.apache.servicecomb.common.rest.codec.produce.ProduceJsonProcessor org.apache.servicecomb.common.rest.codec.produce.ProduceTextPlainProcessor 出现异常 java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to com.alibaba.fastjson.JSONObject
只保留 org.apache.servicecomb.common.rest.codec.produce.ProduceJsonProcessor org.apache.servicecomb.common.rest.codec.produce.ProduceTextPlainProcessor的情况下还试过: restTemplate.getForObject(url, String.class) 出现异常 java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to String
restTemplate.getForObject(url, Map.class)或者restTemplate.getForObject(url, Object.class)可以?可以的,但是这种写法真的是缺少了RestTemplate中的精华:类型转换,增加了业务层的复杂 有点先入为主,但是这种东西,不得不承认,用起来很舒服
我理解 JsonObject 和 Map几乎是等价的,所以提了这个。 你期望
restTemplate.getForObject(url, MyCustomBean.class)这种?为啥都会需要 JsonObject 了? 这个用起来不存在舒服的说法呀。从JavaType responseType = invocation.findResponseType(responseEx.getStatus());获取到responseType大部分都是Object.class,能用 MyCustomBean.class接收吗
可以。这里取到的类型根据
restTemplate.getForObject(url, MyCustomBean.class)决定的。
我跟代码的时观察到的是:MyCustomBean.class起到的作用只是避免类型的强行转换,实际上类型是由 JavaType responseType = invocation.findResponseType(responseEx.getStatus());决定的
DefaultHttpClientFilter这段代码完成类型的确认和转化
JavaType responseType = invocation.findResponseType(responseEx.getStatus());
result = produceProcessor.decodeResponse(responseEx.getBodyBuffer(), responseType);
Response response = Response.create(responseEx.getStatusType(), result);
CseClientHttpRequest没有进行类型的转化,包装一下就完了
private CseClientHttpResponse invoke(Map<String, Object> swaggerArguments) {
Invocation invocation = prepareInvocation(swaggerArguments);
Response response = doInvoke(invocation);
if (response.isSucceed()) {
return new CseClientHttpResponse(response);
}
throw ExceptionFactory.convertConsumerException(response.getResult());
}
CseHttpMessageConverterExtractor拆取时也没有类型转换
public class CseHttpMessageConverterExtractor<T> implements ResponseExtractor<T> {
@Override
@SuppressWarnings("unchecked")
public T extractData(ClientHttpResponse response) throws IOException {
return (T) ((CseClientHttpResponse) response).getResult();
}
}
CSERestTemplate继承RestTemplate的方法,也没有进行类型转换
@Nullable
protected <T> T doExecute(URI url, @Nullable HttpMethod method, @Nullable RequestCallback requestCallback,
@Nullable ResponseExtractor<T> responseExtractor) throws RestClientException {
Assert.notNull(url, "URI is required");
Assert.notNull(method, "HttpMethod is required");
ClientHttpResponse response = null;
try {
ClientHttpRequest request = createRequest(url, method);
if (requestCallback != null) {
requestCallback.doWithRequest(request);
}
response = request.execute();
handleResponse(url, method, response);
return (responseExtractor != null ? responseExtractor.extractData(response) : null);
}
catch (IOException ex) {
String resource = url.toString();
String query = url.getRawQuery();
resource = (query != null ? resource.substring(0, resource.indexOf('?')) : resource);
throw new ResourceAccessException("I/O error on " + method.name() +
" request for \"" + resource + "\": " + ex.getMessage(), ex);
}
finally {
if (response != null) {
response.close();
}
}
}
restTemplate.postForObject(url, params, JSONObject.class) 没有问题
restTemplate.getForObject(url, JSONObject.class)出现 java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to com.alibaba.fastjson.JSONObject
你能从使用者的角度提供下用法吗? 包括服务端的接口定义、客户端的请求代码示例。 我感觉前面提供的信息,有些是不正确的用法。 对着具体的使用方式, 可能更好的讨论。
比如: String result = restTemplate.getForObject(url, String.class) 这种客户端用法, 适用于服务端的接口定义中返回值类型也是String。 如果不是, 那么则无法工作。