Reputation: 767
I am making use of this cool thing Spring offers: Spring RESTWebService (Version of spring is 3). If I access the URL from browser I can see the JSON response, but from a Client endpoint (Android application) iIreceive this error message:
Caused by: org.springframework.web.client.ResourceAccessException:
I/O error: Can not deserialize instance of MyObject out of START_ARRAY token
at [Source: org.apache.http.conn.EofSensorInputStream@4076e940; line: 1,
column: 1]; nested exception is org.codehaus.jackson.map.JsonMappingException:
Can not deserialize instance of MyObject out of START_ARRAY token
at [Source: org.apache.http.conn.EofSensorInputStream@4076e940; line: 1, column: 1]
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:466)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:414)
at org.springframework.web.client.RestTemplate.getForEntity(RestTemplate.java:234)
at com.be.android.locateconsultants.resources.AsyncTaskRESTServiceCaller.doInBackground(AsyncTaskRESTServiceCaller.java:43)
at com.be.android.locateconsultants.resources.AsyncTaskRESTServiceCaller.doInBackground(AsyncTaskRESTServiceCaller.java:1)
at android.os.AsyncTask$2.call(AsyncTask.java:252)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
... 4 more
Caused by: org.codehaus.jackson.map.JsonMappingException: Can not deserialize
instance of MyObject out of START_ARRAY token
at [Source: org.apache.http.conn.EofSensorInputStream@4076e940; line: 1, column: 1]
at org.codehaus.jackson.map.deser.StdDeserializationContext.mappingException(StdDeserializationContext.java:198)
at org.codehaus.jackson.map.deser.BeanDeserializer.deserializeUsingCreator(BeanDeserializer.java:565)
at org.codehaus.jackson.map.deser.BeanDeserializer.deserialize(BeanDeserializer.java:365)
at org.codehaus.jackson.map.ObjectMapper._readMapAndClose(ObjectMapper.java:2395)
at org.codehaus.jackson.map.ObjectMapper.readValue(ObjectMapper.java:1655)
at org.springframework.http.converter.json.MappingJacksonHttpMessageConverter.readInternal(MappingJacksonHttpMessageConverter.java:135)
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:632)
at org.springframework.web.client.RestTemplate$ResponseEntityResponseExtractor.extractData(RestTemplate.java:618)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:459)
... 10 more
MyObject structure is the same as the one from the server side application.
I have tried to request the server like this:
final String url = ".....";
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<Consultant> responseEntity = restTemplate.getForEntity(
url, Consultant.class);
Or like this:
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<String> entity = new HttpEntity<String>(headers);
ResponseEntity<MyObject> response = restTemplate
.exchange("....",HttpMethod.GET, entity, MyObject.class);
System.out.println("RESPONSE: " + response.getBody());
But still the same error as above. Can't figure out what I am missing at this point, any idea or hints would be great. Thank you.
Upvotes: 23
Views: 99709
Reputation: 12797
If you want to serialize an array from a json like:
[
{"foo":"bar"}, {"foo1":"bar1"}
]
You must configure the value deserializer to accept an array in the method signature.
@Bean
public ConsumerFactory<String, DTO[]> consumerFactory() {
Map<String, Object> props = new HashMap<>();
props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG,
bootstrapAddress);
props.put(ConsumerConfig.GROUP_ID_CONFIG,
groupId);
props.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "latest");
props.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, true);
props.put(ConsumerConfig.ALLOW_AUTO_CREATE_TOPICS_CONFIG, true);
return new DefaultKafkaConsumerFactory<>(props,
new StringDeserializer(),
new JsonDeserializer<>(DTO[].class));
}
@Bean
public ConcurrentKafkaListenerContainerFactory<String, DTO[]>
kafkaListenerContainerFactory() {
ConcurrentKafkaListenerContainerFactory<String, DTO[]> factory =
new ConcurrentKafkaListenerContainerFactory<>();
factory.setConsumerFactory(consumerFactory());
return factory;
}
And in your consumer:
@KafkaListener(topics = "foo-topic", groupId = "foo-group")
void listen(DTO[] dtos) {
}
No type reference or other things needed. I think underneath, ObjectArrayDeserializer
is used.
Note that in this way, you will need to put all configs into java code, and (maybe) all configs by YAML will not work for consumer. I am not sure but you can try to combine code config and YAML config.
Upvotes: 0
Reputation: 4797
a file foo.json contains a batch of data like this:
[{"A":"TYMH","B":"datab","C":"DLJQ","D":"datad"}, {"A":"TYMH","B":"datab","C":"DLJQ","D":"datad"}]
The following statement gives you an ArrayList of LinkedHashMap, where A B C D are the keys.
List list = mapper.readValue(new File("D:\\...\\foo.json"), List.class);
Upvotes: 0
Reputation: 2400
This is related to Jackson and the way you're attempting to deserialize and initialize a container from an array.
While my usage context is a bit different, this may help some who get here from searching for Jackson-specific deserialization errors.
I had to do it like this:
List<Consultant> consultants = Arrays.asList(
mapper.readValue(myJson.toString(), Consultants[].class)
);
Upvotes: 9
Reputation: 238
Solution in a similar situation was to map to Consultant[].class
This applies if you try to deserialize a JSON array of your mapped objects.
Upvotes: 18
Reputation: 16082
You should map it to List<Consultant>
rather than to Consultant.class
.
Upvotes: 23