How to make Jackson read this invalid JSON? - json

In a Spring Boot app, using Spring Cloud OpenFeign, I'm about to read an endpoint for a Talend server but just noticed this isn't valid JSON (missing double quotes around the word transactions):
{
transactions: [
"some-uuid",
"another-one-uuid",
"and-so-on-uuid"
]
}
My model class:
#Data
#SuperBuilder
#NoArgsConstructor
#JsonInclude(JsonInclude.Include.ALWAYS)
public class Transactions {
private List<String> transactions;
}
My service/client class:
#Service
#FeignClient(value = "nativeTalend", url = "http://talend-server:8180/talendmdm/services/rest/")
public interface TalendNativeAPI {
#GetMapping(path = "transactions", produces = MediaType.APPLICATION_JSON_VALUE)
Transactions transactions();
}
Note: it needs the "produces" in the #GetMapping annotation because otherwise the server answers with a 500 HTTP error...
Here is the OpenFeign log:
[TalendNativeAPI#transactions] ---> GET http://talend-server:8180/talendmdm/services/rest/transactions HTTP/1.1
[TalendNativeAPI#transactions] Accept: application/json
[TalendNativeAPI#transactions] Authorization: Basic ==xxx==xxx==xxx==
[TalendNativeAPI#transactions] ---> END HTTP (0-byte body)
[TalendNativeAPI#transactions] <--- HTTP/1.1 200 (282ms)
[TalendNativeAPI#transactions] cache-control: no-cache
[TalendNativeAPI#transactions] content-type: application/json;charset=UTF-8
[TalendNativeAPI#transactions] date: Sun, 27 Sep 2020 13:54:50 GMT
[TalendNativeAPI#transactions] expires: Thu, 01 Jan 1970 00:00:00 GMT
[TalendNativeAPI#transactions] pragma: No-cache
[TalendNativeAPI#transactions] set-cookie: JSESSIONID=XXX_XXX_XXX; Path=/talendmdm; HttpOnly
[TalendNativeAPI#transactions] transfer-encoding: chunked
[TalendNativeAPI#transactions] x-content-type-options: nosniff
[TalendNativeAPI#transactions] x-frame-options: DENY
[TalendNativeAPI#transactions] x-xss-protection: 1; mode=block
[TalendNativeAPI#transactions] <--- END HTTP (17-byte body)
and the exception stacktrace (I run this through a unit test):
feign.codec.DecodeException: Error while extracting response for type [class my.company.app.Transactions] and content type [application/json;charset=UTF-8]; nested exception is org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Unexpected character ('t' (code 116)): was expecting double-quote to start field name; nested exception is com.fasterxml.jackson.core.JsonParseException: Unexpected character ('t' (code 116)): was expecting double-quote to start field name
at [Source: (ByteArrayInputStream); line: 1, column: 3]
at feign.SynchronousMethodHandler.decode(SynchronousMethodHandler.java:180)
at feign.SynchronousMethodHandler.executeAndDecode(SynchronousMethodHandler.java:140)
at feign.SynchronousMethodHandler.invoke(SynchronousMethodHandler.java:78)
at feign.ReflectiveFeign$FeignInvocationHandler.invoke(ReflectiveFeign.java:103)
at com.sun.proxy.$Proxy147.transactions(Unknown Source)
at my.company.app.TalendIntegrationTest.test_noTransactions(TalendIntegrationTest.java:26)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
Caused by: org.springframework.web.client.RestClientException: Error while extracting response for type [class my.company.app.Transactions] and content type [application/json;charset=UTF-8]; nested exception is org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Unexpected character ('t' (code 116)): was expecting double-quote to start field name; nested exception is com.fasterxml.jackson.core.JsonParseException: Unexpected character ('t' (code 116)): was expecting double-quote to start field name
at [Source: (ByteArrayInputStream); line: 1, column: 3]
at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:117)
at org.springframework.cloud.openfeign.support.SpringDecoder.decode(SpringDecoder.java:59)
at org.springframework.cloud.openfeign.support.ResponseEntityDecoder.decode(ResponseEntityDecoder.java:62)
at feign.optionals.OptionalDecoder.decode(OptionalDecoder.java:36)
at feign.SynchronousMethodHandler.decode(SynchronousMethodHandler.java:176)
... 36 more
Caused by: org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Unexpected character ('t' (code 116)): was expecting double-quote to start field name; nested exception is com.fasterxml.jackson.core.JsonParseException: Unexpected character ('t' (code 116)): was expecting double-quote to start field name
at [Source: (ByteArrayInputStream); line: 1, column: 3]
at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:245)
at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.read(AbstractJackson2HttpMessageConverter.java:227)
at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:102)
... 40 more
Caused by: com.fasterxml.jackson.core.JsonParseException: Unexpected character ('t' (code 116)): was expecting double-quote to start field name
at [Source: (ByteArrayInputStream); line: 1, column: 3]
at com.fasterxml.jackson.core.JsonParser._constructError(JsonParser.java:1804)
at com.fasterxml.jackson.core.base.ParserMinimalBase._reportError(ParserMinimalBase.java:693)
at com.fasterxml.jackson.core.base.ParserMinimalBase._reportUnexpectedChar(ParserMinimalBase.java:591)
at com.fasterxml.jackson.core.json.UTF8StreamJsonParser._handleOddName(UTF8StreamJsonParser.java:1996)
at com.fasterxml.jackson.core.json.UTF8StreamJsonParser._parseName(UTF8StreamJsonParser.java:1647)
at com.fasterxml.jackson.core.json.UTF8StreamJsonParser.nextToken(UTF8StreamJsonParser.java:733)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:155)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4014)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3085)
at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:239)
... 42 more
How can I configure/"fix" Jackson to make it still read this falsy JSON from this specific endpoint (with the whole context of Spring Boot + Spring Cloud OpenFeign + Jackson auto-declared bean (by Spring)?
Thanks.

The ALLOW_UNQUOTED_FIELD_NAMES feature should do the trick:
public class Unquote {
public static void main(String[] args) throws Exception {
ObjectMapper om = new ObjectMapper()
.configure(com.fasterxml.jackson.core.JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
JsonNode tree = om.readTree("{transactions:[\"some.uuid\"]}".getBytes());
System.out.println(tree);
}
}
This answer explains how to do this in the Spring context:
Configuring ObjectMapper in Spring

Related

exception in post request in springboot throwing json phrasing error

i am sending post request through postman request to my spring boot application but it encounters the following error message
2022-08-03 11:30:51.637 WARN 7140 --- [nio-9002-exec-7] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Unexpected character (' ' (code 160)): was expecting double-quote to start field name; nested exception is com.fasterxml.jackson.core.JsonParseException: Unexpected character (' ' (code 160)): was expecting double-quote to start field name<EOL> at [Source: (org.springframework.util.StreamUtils$NonClosingInputStream); line: 2, column: 3]]
this is my postman request
{   "operationClient": "03",   "module": "03",   "moduleName": "ECH",   "operation": "10",   "ip": "127.0.0.1",   "channelId": "5",   "connectionType": "1" }
my API call request
localhost:9002/cms/online/v1/channel/operation
my controller class of spring-boot
#PostMapping(value = "/operation", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<ResponseBean> doChannelOperation(#RequestBody #Valid RequestBean requestBean) throws Exception {
System.out.println(requestBean.toString());
ResponseBean responseBean = services.sendRequest(requestBean);
return new ResponseEntity<>(responseBean, HttpStatus.OK);
}

How SpringBoot returns errorResponse in JSON format?

I am newbie in implementing SpringBoot+RestfulWebservice.In my project, exceptions are handled globally using #ControllerAdvice and Custom class is created to set the error code and error message in String format.We are passing the error object to HTTPResponse and returing the response.But I am wondering how the errormessages are converted in JSON format as , we are not explicitly using any httpMessageConverter.
- Is Spring Boot internally do the conversion?
Please help me in understanding the behavior. Give me some insights,though you feel like its basic question.
Basically Spring Boot defaults to JSON for all the things when you don't provide specifics around content-type negotiation.
As per the spring boot documentation on error handling here using #ControllerAdvice defaults to producing JSON formatted errors. From the docs:
You can also define a class annotated with #ControllerAdvice to customize the JSON document to return for a particular controller and/or exception type, as shown in the following example:
This page on mkyong.com has a good write up about how to customise the ControllerAdvice error handling.
As an example of JSON usage, this very bare bones controller will do its best to render any POJO as JSON (note if you just provide a primitive like a long it will simply return the primitive in text, but set the content-type as application/json)
#RequestMapping("api/time")
#RestController
public class TestApi {
#GetMapping
public Map<String, Long> time(){
Map<String, Long> res = new HashMap<String, Long>();
res.put("time_in_nanos", System.nanoTime());
return res;
}
}
example:
$ curl -v http://localhost:8080/api/time
* Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 8080 (#0)
> GET /api/time HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.64.1
> Accept: */*
>
< HTTP/1.1 200
< Content-Type: application/json;charset=UTF-8
< Transfer-Encoding: chunked
< Date: Tue, 04 Feb 2020 04:18:35 GMT
<
* Connection #0 to host localhost left intact
{"time_in_nanos":47078744054692}
That's for default requests (ie no Accept header, or Accept: */*), if you specify application/xml or something else it typically wont work:
$ curl -v http://localhost:8080/api/time --header 'Accept: application/xml'
* Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 8080 (#0)
> GET /api/time HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.64.1
> Accept: application/xml
>
< HTTP/1.1 406
< Content-Length: 0
< Date: Tue, 04 Feb 2020 04:17:38 GMT
<
* Connection #0 to host localhost left intact
* Closing connection 0
By default springboot registers the following HttpMessageConverters on startup :
ByteArrayHttpMessageConverter – converts byte arrays
StringHttpMessageConverter – converts Strings
ResourceHttpMessageConverter – converts org.springframework.core.io.Resource for any type of octet stream
SourceHttpMessageConverter – converts javax.xml.transform.Source
FormHttpMessageConverter – converts form data to/from a MultiValueMap<String, String>.
Jaxb2RootElementHttpMessageConverter – converts Java objects to/from XML (added only if JAXB2 is present on the classpath)
MappingJackson2HttpMessageConverter – converts JSON (added only if Jackson 2 is present on the classpath)
MappingJacksonHttpMessageConverter – converts JSON (added only if Jackson is present on the classpath)
AtomFeedHttpMessageConverter – converts Atom feeds (added only if Rome is present on the classpath)
RssChannelHttpMessageConverter – converts RSS feeds (added only if Rome is present on the classpath)
So, if you are returning an object from your controller advice , spring will automatically by default call the Jackson converter to convert the object into a valid Json response.
Basically springboot checks the MIME type to decide which implementation of HttpMessageConverter to use.Also, it will depend on the "Accept" header to decide the type of data that the caller is expecting.If it's a request thatis received springboot will use the "Content-type" header to decide the type of data that is send.

Why is JSON payload for int-http:outbound-gateway give 400 Bad Request?

Why is JSON payload for int-http:outbound-gateway give 400 Bad Request?
Below request works fine on Chrome Rest Client with 3 headers specified in inObjgateway and JSON value of Obj
public class Obj {
#JsonProperty("phone")
private String phoneNo;
#JsonProperty("orderNumber")
private String orderNmb;
}
Application Context Code Snippet is
<int:gateway id="inObjGateway" service-interface="com.XXX.xx.IObjGateway"
default-request-channel="smsHttpRequestChannel" default-reply-timeout="10000">
<int:default-header name="content-Type" value="application/json" />
<int:default-header name="authorization" value="someWE6JHRhcGwzc0MwZDNCcsome"/>
<int:default-header name="accept" value="application/json" />
</int:gateway>
<int:payload-type-router input-channel="httpRequestChannel">
<int:mapping type="com.xxx.xx.json.entity.Obj" channel="httpObjToJsonChannel"/>
</int:payload-type-router>
<int:channel id="httpRequestChannel"/>
<int:channel id="httpOutChannel"/>
<int:channel id="httpObjToJsonChannel"/>
<int:object-to-json-transformer auto-startup="true"
id="objectToJsonTxr" input-channel="httpObjToJsonChannel"
output-channel="smsHttpOutChannel"/>
<bean id="httpRequestFactory" class="org.springframework.http.client.HttpComponentsClientHttpRequestFactory">
<property name="connectTimeout" value="${connectionTimeout}"/>
<property name="readTimeout" value="${connectionTimeout}"/>
</bean>
<bean id="jackson2http" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/>
<int-http:outbound-gateway request-channel="httpOutChannel" encode-uri="false"
url="http://www.someurl.com/something"
http-method="POST" auto-startup="true" request-factory="httpRequestFactory"
reply-channel="loggingChannel" message-converters="jackson2http"
reply-timeout="10000" />
Below line in detailed logs after show correct conversion from Object to JSON-:
Writing [{"phoneNo":"1617xxxxxxx","orderNmb":"2073xxxxx"}] as "application/json"
Detailed logs
org.springframework.beans.factory.support.DefaultListableBeanFactory : Returning cached instance of singleton bean 'integrationEvaluationContext'
org.springframework.integration.router.PayloadTypeRouter : (inner bean)#53c8bb96 received message: GenericMessage [payload=com.xxxx.json.entity.Obj#235a8276, headers={timestamp=1430802166667, id=f3c3577d-bf44-b54d-b5e6-6b3f88a5746b, content-Type=application/json, accept=application/json, authorization=someWE6JHRhcGwzc0MwZDNCcsome}]
org.springframework.beans.factory.support.DefaultListableBeanFactory : Returning cached instance of singleton bean 'ObjHttpObjToJsonChannel'
org.springframework.integration.transformer.MessageTransformingHandler : org.springframework.integration.transformer.MessageTransformingHandler#0 received message: GenericMessage [payload=com.xxxx.json.entity.Obj#235a8276, headers={timestamp=1430802166667, id=f3c3577d-bf44-b54d-b5e6-6b3f88a5746b, content-Type=application/json, accept=application/json, authorization=someWE6JHRhcGwzc0MwZDNCcsome}]
org.springframework.integration.http.outbound.HttpRequestExecutingMessageHandler : org.springframework.integration.http.outbound.HttpRequestExecutingMessageHandler#2 received message: GenericMessage [payload={"phoneNo":"16173313826","orderNmb":"2070000383","firstName":"A"}, headers={timestamp=1430802166759, id=7584cee1-8392-c71c-75f4-026d423e26c2, json__TypeId__=class com.xxxx.json.entity.Obj, content-Type=application/json, accept=application/json, authorization=someWE6JHRhcGwzc0MwZDNCcsome, contentType=application/json}]
org.springframework.integration.http.support.DefaultHttpHeaderMapper : outboundHeaderNames=[Accept, Accept-Charset, Accept-Encoding, Accept-Language, Accept-Ranges, Authorization, Cache-Control, Connection, Content-Length, Content-Type, Cookie, Date, Expect, From, Host, If-Match, If-Modified-Since, If-None-Match, If-Range, If-Unmodified-Since, Max-Forwards, Pragma, Proxy-Authorization, Range, Referer, TE, Upgrade, User-Agent, Via, Warning]
org.springframework.integration.http.support.DefaultHttpHeaderMapper : headerName=[timestamp] WILL NOT be mapped
org.springframework.integration.http.support.DefaultHttpHeaderMapper : headerName=[id] WILL NOT be mapped
org.springframework.integration.http.support.DefaultHttpHeaderMapper : headerName=[json__typeid__] WILL NOT be mapped
org.springframework.integration.http.support.DefaultHttpHeaderMapper : headerName=[content-type] WILL be mapped, matched pattern=content-type
org.springframework.integration.http.support.DefaultHttpHeaderMapper : setting headerName=[content-Type], value=application/json
org.springframework.integration.http.support.DefaultHttpHeaderMapper : headerName=[accept] WILL be mapped, matched pattern=accept
org.springframework.integration.http.support.DefaultHttpHeaderMapper : setting headerName=[accept], value=application/json
org.springframework.integration.http.support.DefaultHttpHeaderMapper : headerName=[authorization] WILL be mapped, matched pattern=authorization
org.springframework.integration.http.support.DefaultHttpHeaderMapper : setting headerName=[authorization], value=someWE6JHRhcGwzc0MwZDNCcsome
org.springframework.integration.http.support.DefaultHttpHeaderMapper : headerName=[contenttype] WILL be mapped, matched pattern=contenttype
org.springframework.integration.http.support.DefaultHttpHeaderMapper : setting headerName=[contentType], value=application/json
org.springframework.web.client.RestTemplate : Created POST request for "http://www.someurl.com/something"
org.springframework.web.client.RestTemplate : Writing [{"phoneNo":"1617xxxxxxx","orderNmb":"2073xxxxx"}] as "application/json" using [org.springframework.http.converter.json.MappingJackson2HttpMessageConverter#774490f3]
org.springframework.web.client.RestTemplate : POST request for "http://www.someurl.com/something" resulted in 400 (Bad Request); invoking error handler
org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver : Resolving exception from handler [public org.springframework.web.servlet.ModelAndView com.xxxx.page.controller.ObjController.sendObj(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse,javax.servlet.http.HttpSession) throws com.xxxx.utils.exception.SomePageException]: org.springframework.web.client.HttpClientErrorException: 400 Bad Request
org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver : Resolving exception from handler [public org.springframework.web.servlet.ModelAndView com.xxxx.page.controller.ObjController.sendObj(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse,javax.servlet.http.HttpSession) throws com.xxxx.utils.exception.SomePageException]: org.springframework.web.client.HttpClientErrorException: 400 Bad Request
org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver : Resolving exception from handler [public org.springframework.web.servlet.ModelAndView com.xxxx.page.controller.ObjController.sendObj(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse,javax.servlet.http.HttpSession) throws com.xxxx.utils.exception.SomePageException]: org.springframework.web.client.HttpClientErrorException: 400 Bad Request
org.springframework.web.servlet.handler.SimpleMappingExceptionResolver : Resolving exception from handler [public org.springframework.web.servlet.ModelAndView com.xxxx.page.controller.ObjController.sendObj(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse,javax.servlet.http.HttpSession) throws com.xxxx.utils.exception.SomePageException]: org.springframework.web.client.HttpClientErrorException: 400 Bad Request
org.springframework.web.servlet.handler.SimpleMappingExceptionResolver : Resolving to view 'error' for exception of type [org.springframework.web.client.HttpClientErrorException], based on exception mapping [java.lang.Exception]
org.springframework.web.servlet.handler.SimpleMappingExceptionResolver : Exposing Exception as model attribute 'exception'
org.springframework.web.servlet.DispatcherServlet : Handler execution resulted in exception - forwarding to resolved error view: ModelAndView: reference to view with name 'error'; model is {exception=org.springframework.web.client.HttpClientErrorException: 400 Bad Request}
org.springframework.web.client.HttpClientErrorException: 400 Bad Request
at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:91)
at org.springframework.web.client.RestTemplate.handleResponseError(RestTemplate.java:588)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:546)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:517)
at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:462)
at org.springframework.integration.http.outbound.HttpRequestExecutingMessageHandler.handleRequestMessage(HttpRequestExecutingMessageHandler.java:422)
at org.springframework.integration.handler.AbstractReplyProducingMessageHandler.handleMessageInternal(AbstractReplyProducingMessageHandler.java:99)
at org.springframework.integration.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:78)
at org.springframework.integration.dispatcher.AbstractDispatcher.tryOptimizedDispatch(AbstractDispatcher.java:116)
at org.springframework.integration.dispatcher.UnicastingDispatcher.doDispatch(UnicastingDispatcher.java:101)
at org.springframework.integration.dispatcher.UnicastingDispatcher.dispatch(UnicastingDispatcher.java:97)
at org.springframework.integration.channel.AbstractSubscribableChannel.doSend(AbstractSubscribableChannel.java:77)
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:277)
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:239)
at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:115)
at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:45)
at org.springframework.messaging.core.AbstractMessageSendingTemplate.send(AbstractMessageSendingTemplate.java:95)
at org.springframework.integration.handler.AbstractMessageProducingHandler.sendOutput(AbstractMessageProducingHandler.java:248)
at org.springframework.integration.handler.AbstractMessageProducingHandler.produceOutput(AbstractMessageProducingHandler.java:171)
at org.springframework.integration.handler.AbstractMessageProducingHandler.sendOutputs(AbstractMessageProducingHandler.java:119)
at org.springframework.integration.handler.AbstractReplyProducingMessageHandler.handleMessageInternal(AbstractReplyProducingMessageHandler.java:105)
at org.springframework.integration.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:78)
at org.springframework.integration.dispatcher.AbstractDispatcher.tryOptimizedDispatch(AbstractDispatcher.java:116)
at org.springframework.integration.dispatcher.UnicastingDispatcher.doDispatch(UnicastingDispatcher.java:101)
at org.springframework.integration.dispatcher.UnicastingDispatcher.dispatch(UnicastingDispatcher.java:97)
at org.springframework.integration.channel.AbstractSubscribableChannel.doSend(AbstractSubscribableChannel.java:77)
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:277)
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:239)
at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:115)
at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:45)
at org.springframework.messaging.core.AbstractMessageSendingTemplate.send(AbstractMessageSendingTemplate.java:95)
at org.springframework.integration.router.AbstractMessageRouter.handleMessageInternal(AbstractMessageRouter.java:164)
at org.springframework.integration.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:78)
at org.springframework.integration.dispatcher.AbstractDispatcher.tryOptimizedDispatch(AbstractDispatcher.java:116)
at org.springframework.integration.dispatcher.UnicastingDispatcher.doDispatch(UnicastingDispatcher.java:101)
at org.springframework.integration.dispatcher.UnicastingDispatcher.dispatch(UnicastingDispatcher.java:97)
at org.springframework.integration.channel.AbstractSubscribableChannel.doSend(AbstractSubscribableChannel.java:77)
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:277)
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:239)
at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:115)
at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:45)
at org.springframework.messaging.core.AbstractMessageSendingTemplate.send(AbstractMessageSendingTemplate.java:95)
at org.springframework.messaging.core.AbstractMessageSendingTemplate.convertAndSend(AbstractMessageSendingTemplate.java:133)
at org.springframework.messaging.core.AbstractMessageSendingTemplate.convertAndSend(AbstractMessageSendingTemplate.java:125)
at org.springframework.integration.gateway.MessagingGatewaySupport.send(MessagingGatewaySupport.java:302)
at org.springframework.integration.gateway.GatewayProxyFactoryBean.invokeGatewayMethod(GatewayProxyFactoryBean.java:417)
at org.springframework.integration.gateway.GatewayProxyFactoryBean.doInvoke(GatewayProxyFactoryBean.java:374)
at org.springframework.integration.gateway.GatewayProxyFactoryBean.invoke(GatewayProxyFactoryBean.java:365)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
at com.sun.proxy.$Proxy102.sendObj(Unknown Source)
at com.xxxx.page.controller.ObjController.sendObj(ObjController.java:59)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:215)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:132)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:749)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:689)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:83)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:938)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:870)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:961)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:852)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:617)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:837)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:723)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:293)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:861)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:606)
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489)
at java.lang.Thread.run(Thread.java:662)
The Wireshark packet trace difference from what I observed is as below.
Working request trace from Postman Rest Client!
No. Time Source Destination Protocol Length Info
16733 484.996811000 10.1.XX.XXX 192.XX.XX.XXX HTTP 1126 POST /chapi/v1/some HTTP/1.1 HTTP/1.1 (application/json)
Frame 16733: 1126 bytes on wire (9008 bits), 1126 bytes captured (9008 bits) on interface 1
Ethernet II, Src: HewlettP_2d:4e:49 (a0:2b:xx:xx:xx:49), Dst: Cisco_ff:fc:04 (00:08:xx:xx:fx:04)
Internet Protocol Version 4, Src: 10.1.XX.XXX (10.1.XX.XXX), Dst: 192.XX.XX.XXX (192.XX.XX.XXX)
Transmission Control Protocol, Src Port: 60374 (60374), Dst Port: 80 (80), Seq: 2921, Ack: 1, Len: 1072
[3 Reassembled TCP Segments (3992 bytes): #16728(1460), #16729(1460), #16733(1072)]
[Frame: 16728, payload: 0-1459 (1460 bytes)]
[Frame: 16729, payload: 1460-2919 (1460 bytes)]
[Frame: 16733, payload: 2920-3991 (1072 bytes)]
[Segment count: 3]
[Reassembled TCP length: 3992]
[Reassembled TCP Data: 504f5354202f6d6f62696c6553657276696365732f737470...]
Hypertext Transfer Protocol
POST /chapi/v1/some HTTP/1.1\r\n
Host: something.com\r\n
Connection: keep-alive\r\n
Content-Length: 94\r\n
Accept: application/json\r\n
Cache-Control: no-cache\r\n
Origin: chrome-extension://fdmmgilgnpjigdojojpjoooidkmcomcm\r\n
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36\r\n
Authorization: someWE6JHRhcGwzc0MwZDNCcsome\r\n
Content-Type: application/json\r\n
Accept-Encoding: gzip, deflate\r\n
Accept-Language: en-US,en;q=0.8\r\n
[truncated]Cookie: _br_mzv=eyIxIjozLCIyIjox
\r\n
[Full request URI: http://www.something.com//chapi/v1/some ]
[HTTP request 1/1]
[Response in frame: 16746]
JavaScript Object Notation: application/json
Object
Member Key: "phone"
String value: 1617xxxXXXX
Member Key: "orderNumber"
String value: 12xxXXXXX
Member Key: "application"
String value: orderPickup
Request not working from Application as per above code configuration !
No. Time Source Destination Protocol Length Info
89769 2664.453624000 10.1.XX.XXX 192.XX.XX.XXX HTTP 491 POST /chapi/v1/some HTTP/1.1 (application/json)
Frame 89769: 491 bytes on wire (3928 bits), 491 bytes captured (3928 bits) on interface 1
Ethernet II, Src: HewlettP_xx:xx:49 (a0:2b:xx:xx:xx:49), Dst: Cisco_ff:fc:04 (00:08:xx:xx:fx:04)
Internet Protocol Version 4, Src: 10.1.XX.XXX (10.1.XX.XXX), Dst: 192.XX.XX.XXX (192.XX.XX.XXX)
Transmission Control Protocol, Src Port: 60618 (60618), Dst Port: 80 (80), Seq: 1, Ack: 1, Len: 437
Hypertext Transfer Protocol
POST /chapi/v1/some HTTP/1.1\r\n
Accept: application/json\r\n
authorization: someWE6JHRhcGwzc0MwZDNCcsome\r\n
Content-Type: application/json\r\n
Content-Length: 91\r\n
Host: something.com\r\n
Connection: Keep-Alive\r\n
User-Agent: Apache-HttpClient/4.3.6 (java 1.5)\r\n
Accept-Encoding: gzip,deflate\r\n
\r\n
[Full request URI: http://www.something.com/chapi/v1/some]
[HTTP request 1/1]
[Response in frame: 89778]
JavaScript Object Notation: application/json
Line-based text data: application/json
"{\"phoneNo\":\"1617xxxXXXX\",\"orderNmb\":\"207xxXXXX\",\"application\":\"orderPickup\"}"
Any pointers appreciated!
Questions like this are too general; you need to provide more details.
This requires you to use some basic debugging skills.
Step 1: Look at the server side logs to see what it is complaining about.
If that doesn't yield the solution,
Step 2: Compare a network monitor trace of the "good" and "bad" requests and figure out what's different between them. If you see what's different and can't figure out how to configure the gateway to replicate the "good" request then come back here with that specific question.
You can get a network trace with Wireshark or the eclipse TCP/IP Monitor, etc.
EDIT:
As you can see from the trace, you are doing two JSON conversions.
Remove the object-to-json-transformer and just let the outbound gateway do the conversion.

How to use the Fluent API of Apache HttpClient to read UTF-8 coded website?

String html = Request.Get("https://kokos.pl/")
.execute().returnContent().asString();
System.out.println(html);
What I obtain in the 12th line is:
<title>Szybkie po??yczki got??wkowe, po??yczki spo??eczno??ciowe - Kokos.pl</title>
while it should be:
<title>Szybkie pożyczki gotówkowe, pożyczki społecznościowe - Kokos.pl</title>
[DEBUG] DefaultClientConnection - Sending request: GET / HTTP/1.1
[DEBUG] headers - >> GET / HTTP/1.1
[DEBUG] headers - >> Host: kokos.pl
[DEBUG] headers - >> Connection: Keep-Alive
[DEBUG] headers - >> User-Agent: Apache-HttpClient/4.2.5 (java 1.5)
[DEBUG] DefaultClientConnection - Receiving response: HTTP/1.1 200 OK
[DEBUG] headers - << HTTP/1.1 200 OK
[DEBUG] headers - << Server: nginx
[DEBUG] headers - << Date: Thu, 01 Aug 2013 12:04:12 GMT
[DEBUG] headers - << Content-Type: text/html
[DEBUG] headers - << Connection: keep-alive
...
The response message returned by the server for this URI does not explicitly specify the charset of the content. In such cases HttpClient is forced to use the default charset encoding for HTTP content, which is ISO-8859-1 and not UTF-8.
Unfortunately the only way to override the default content charset used by fluent API is by using a custom response handler
ResponseHandler<String> myHandler = new ResponseHandler<String>() {
#Override
public String handleResponse(
final HttpResponse response) throws IOException {
return EntityUtils.toString(response.getEntity(), Consts.UTF_8);
}
};
String html = Request.Get("https://kokos.pl/").execute().handleResponse(myHandler);
System.out.println(html);

JSON Invalid UTF-8 middle byte

This error happens when the (Jackson, this case) JSON engine tries to parse some JSON that is not encoded in UTF-8.
How to tell the engine that it should expect something different from UTF-8, such as UTF-16?
HttpHeaders requestHeaders = createSomeHeader();
RestTemplate restTemplate = new RestTemplate();
HttpEntity<?> requestEntity = new HttpEntity<Object>(requestHeaders);
String url = "someurl"
ResponseEntity<MyObject[]> arrayResponseEntity = restTemplate.exchange(url, HttpMethod.GET, requestEntity, MyObject[].class);
error log:
Caused by: org.springframework.http.converter.HttpMessageNotReadableException: Could not read JSON: Invalid UTF-8 middle byte 0x20
at [Source: org.apache.http.conn.EofSensorInputStream#44d397b0; line: 92, column: 42]; nested exception is org.codehaus.jackson.JsonParseException: Invalid UTF-8 middle byte 0x20
at [Source: org.apache.http.conn.EofSensorInputStream#44d397b0; line: 92, column: 42]
at org.springframework.http.converter.json.MappingJacksonHttpMessageConverter.readInternal(MappingJacksonHttpMessageConverter.java:138)
at org.springframework.http.converter.AbstractHttpMessageConverter.read(AbstractHttpMessageConverter.java:154)
at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:74)
at org.springframework.web.client.RestTemplate$ResponseEntityResponseExtractor.extractData(RestTemplate.java:622)
at org.springframework.web.client.RestTemplate$ResponseEntityResponseExtractor.extractData(RestTemplate.java:608)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:449)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:404)
at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:380)
... 4 more
Caused by: org.codehaus.jackson.JsonParseException: Invalid UTF-8 middle byte 0x20
at [Source: org.apache.http.conn.EofSensorInputStream#44d397b0; line: 92, column: 42]
at org.codehaus.jackson.JsonParser._constructError(JsonParser.java:1213)
at org.codehaus.jackson.impl.JsonParserMinimalBase._reportError(JsonParserMinimalBase.java:375)
at org.codehaus.jackson.impl.Utf8StreamParser._reportInvalidOther(Utf8StreamParser.java:2132)
at org.codehaus.jackson.impl.Utf8StreamParser._reportInvalidOther(Utf8StreamParser.java:2139)
at org.codehaus.jackson.impl.Utf8StreamParser._decodeUtf8_3fast(Utf8StreamParser.java:1962)
I got this exception when in the Java Client Application I was serializing a JSON like this
String json = mapper.writeValueAsString(contentBean);
and on the Server Side I was using Spring Boot as REST Endpoint.
Exception was:
nested exception is com.fasterxml.jackson.databind.JsonMappingException: Invalid UTF-8 start byte 0xaa
My problem was, that I was not setting the correct encoding on the HTTP Client.
This solved my problem:
updateRequest.setHeader("Content-Type", "application/json;charset=UTF-8");
StringEntity entity= new StringEntity(json, "UTF-8");
updateRequest.setEntity(entity);
Android set content type HttpPost
JSON data must be encoded as UTF-8, UTF-16 or UTF-32. The JSON decoder can determine the encoding by examining the first four octets of the byte stream:
00 00 00 xx UTF-32BE
00 xx 00 xx UTF-16BE
xx 00 00 00 UTF-32LE
xx 00 xx 00 UTF-16LE
xx xx xx xx UTF-8
It sounds like the server is encoding data in some illegal encoding (ISO-8859-1, windows-1252, etc.)
I got this after saving the JSON file using Notepad2, so I had to open it with Notepad++ and then say "Convert to UTF-8". Then it worked.
On the off chance it may help others I'll share a related anecdote.
I encountered this exact error (Invalid UTF-8 middle byte 0x3f) running a PowerShell script via the PowerShell Integrated Script Environment (ISE). The identical script, executed outside the ISE, works fine. The code uses the Confluence v3 and v5.x REST APIs and this error is logged on the Confluence v5.x server - presumably because the ISE somehow mucks with the request.
This awnser solved my problem. Below is a copy of it:
Make sure to start you JVM with -Dfile.encoding=UTF-8. You JVM
defaults to the operating system charset
This is a JVM argument which could be added, for example, either to JBoss standalone or JBoss running from Eclipse.
In my case, this problem happened isolatelly on only one of my team people's computer. All the others was working without this problem.
I had this problem inconsistently between different platforms, as I got JSON as String from Mapper and did the writing myself. Sometimes it went into file as ansi and other times correctly as UTF8. I switched to
mapper.writeValue(file, data);
letting Mapper do the file operations, and it started working fine.
client text protocol
POST http://127.0.0.1/bom/create HTTP/1.1
Content-Type: application/json
User-Agent: PostmanRuntime/7.25.0
Accept: */*
Postman-Token: 50ecfbfe-741f-4a2b-a3d3-cdf162ada27f
Host: 127.0.0.1
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Content-Length: 405
{
"fwoid": 1,
"list": [
{
"bomIndex": "10001",
"desc": "带GH 1.25 13pin 公座带针 白色",
"pn": "084.0001.0036",
"preUse": 1,
"type": "追觅 除螨仪-开关PCB组件"
},
{
"bomIndex": "10002",
"desc": "紫米音箱-商品码标签",
"pn": "Z.08.013.0051",
"preUse": 1,
"type": "E060A0302301"
}
]
}
HTTP/1.1 200 OK
Connection: keep-alive
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Content-Type: application/json
Date: Mon, 01 Jun 2020 11:23:42 GMT
Content-Length: 40
{"code":"0","message":"BOM保存成功"}
a springboot Controller code as below:
#PostMapping("/bom/create")
#ApiOperation(value = "保存BOM")
#BusinessOperation(module = "BOM",methods = "解析BOM")
public JsonResult save(#RequestBody BOMSaveQuery query)
{
return bomService.saveBomList(query);
}
when i debug on loopback interface,it works ok. while deploy on internet server via bat command, i got an error
ServletInvocableHandlerMethod - Could not resolve parameter [0] in public XXXController.save(com.h2.mes.query.BOMSaveQuery): JSON parse error: Invalid UTF-8 middle byte 0x3f; nested exception is com.fasterxml.jackson.databind.JsonMappingException: Invalid UTF-8 middle byte 0x3f
at [Source: (PushbackInputStream); line: 9, column: 32] (through reference chain: com.h2.mes.query.BOMSaveQuery["list"]->java.util.ArrayList[0]->com.h2.mes.vo.BOMVO["type"])
2020-06-01 15:37:50.251 MES [XNIO-1 task-13] WARN o.s.w.s.m.s.DefaultHandlerExceptionResolver - Resolved [org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Invalid UTF-8 middle byte 0x3f; nested exception is com.fasterxml.jackson.databind.JsonMappingException: Invalid UTF-8 middle byte 0x3f
at [Source: (PushbackInputStream); line: 9, column: 32] (through reference chain: com.h2.mes.query.BOMSaveQuery["list"]->java.util.ArrayList[0]->com.h2.mes.vo.BOMVO["type"])]
2020-06-01 15:37:50.251 MES [XNIO-1 task-13] DEBUG o.s.web.servlet.DispatcherServlet - Completed 400 BAD_REQUEST
2020-06-01 15:37:50.251 MES [XNIO-1 task-13] DEBUG o.s.web.servlet.DispatcherServlet - "ERROR" dispatch for POST "/error", parameters={}
add a jvm arguement works for me.
java -Dfile.encoding=UTF-8