Spring MVC: Can not deserialize instance of out of START_ARRAY token - spring

I have been beating my head against this for a while now and still no joy. I am new to Spring and could really use some help.
I am trying to use Spring Boot to return a list of codes from a DB table. When I call my REST controller from a URL in a browser...
Example URL: localhost:8081/cis/utl/lookupchoice/O.s/
It returns this:
[
{"lookupId":10,"choiceGroup":"O.s","choiceCode":null,"displayLabel":"Pending","hidden":false,"displayOrder":1},
{"lookupId":11,"choiceGroup":"O.s","choiceCode":null,"displayLabel":"Active","hidden":false,"displayOrder":2},
{"lookupId":12,"choiceGroup":"O.s","choiceCode":null,"displayLabel":"Archived","hidden":false,"displayOrder":3},
{"lookupId":13,"choiceGroup":"O.s","choiceCode":null,"displayLabel":"Placeholder","hidden":false,"displayOrder":4}
]
But, I get an error message when trying to run this from a client controller. The call looks like this:
//
//Compiles but does not work
LookupChoice lookupChoice = restTemplate.getForObject(REST_URI+"/utl/lookupchoice/O.s/",
LookupChoice.class);
The error: nested exception is com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of com.MyPakage.repository.LookupChoice out of START_ARRAY token
Assuming the error occurs because an array is returned instead of a single object, I changed the code to this:
//
//Does not compile
Iterable<LookupChoice> lookupChoice = restTemplate.getForObject(REST_URI+"/utl/lookupchoice/U.r/",
Iterable<LookupChoice.class>);
But, now I get an error in Intellij. It's indicating that an "Expression expected" for the Iterable<LookupChoice.class> param, and I can't get past this.
Thank you for your time and assistance,
Ed
Thanks for your reply. I opted for this and it all seems to work now. Thanks for your help!
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<Object[]> responseEntity;
Object[] lookupChoice;
responseEntity = restTemplate.getForEntity(REST_SERVICE_URI+"/utl/lookupchoice/O.s/" , Object[].class);
lookupChoice = responseEntity.getBody();
model.addAttribute("Status", lookupChoice);

The reason it doesn't compile is because it's impossible in Java to pass a class of generic type parameters because they don't exist at runtime.
You have two options here, either use an array (LookupChoice[]) and convert it to a List<LookupChoice> if necessary:
restTemplate.getForObject(url, LookupChoice[]);
Or you can use the ParameterizedTypeReference:
restTemplate.exchange(url, HttpMethod.GET, null, new ParameterizedTypeReference<List<LookupChoice>>() {}).getBody()
It is an interface though, so either subclass it or use an anonymous class like I did in the code example above.
Also, ParameterizedTypeReference only works on the exchange() method if I'm not mistaken, so you'll get a ResponseEntity in stead of your raw object, so you'll have to use the getBody() method.

Related

ClientResponse(org.springframework.web.reactive.function.client.ClientResponse) showing inconsistency across the classes while using WebClient

I have started using WebClient(org.springframework.web.reactive.function.client.WebClient) for calling rest services. I have 2 classes say Utility.java and ServiceImpl.java.
ServiceImpl.java is where I use WebClient. A post call I am making looks like -
ClientResponse response = webClient.post()
.uri(path)
.body(Mono.just(inputDTO),InputDTO.class)
.exchange()
.block();
(ClientResponse above is org.springframework.web.reactive.function.client.ClientResponse)
(I am using exchange instaed of retrive because I want headers as well as status code)
Now trying to convert this response into some DTO - ResponseDTO.
Mono<ResponseEntity<ResponseDTO>> mono = response.toEntity(ResponseDTO.class);
ResponseEntity<ResponseDTO> resEntity = mono.block();
ResponseDTO myObj = resEntity.getBody();
So myObj is an object of ResponseDTO class.
The issue is - when I perform the conversion of 'response into ResponseDTO.java' in my utility class, I get myObj = null. But if I do it in my ServiceImpl.java (just after calling post API), it returns the proper body (ResponseDTO object).
The same issue occurs even if I perform the conversion and post call operation in two different methods in the ServiceImpl.java.
Do I need to configure something here?
I figured out what was the issue.
After calling REST api, body in the response if flushed out after I read it from the response for the first time. I had a Sysout statement in service implementation class where I was reading the body content.
Recommendation: Read the body content only once and store it in a variable. Use it wherever required.

Spring Rest Service Return Type

I have a rest service in spring which can return a string or a json. For this in my js code while sending the ajax request, i have specified datatype as "*". I wanted to know how can i handle this in spring service
All produces type are available in org.springframework.http.MediaType and for your requirement you can pass */*.
Constant for that is MediaType.ALL_VALUE in java code.
But if you know that your service always return JSON then I prefer to use MediaType.APPLICATION_JSON_UTF8_VALUE instead of MediaType.ALL_VALUE.
you can add attribute " produces" on your RequestMapping annotation:
#RequestMapping(value = "/yourPath", method = GET,
produces = { "application/json", "application/xml",....all what you want as type})

Swagger TypeError: Failed to execute 'fetch' on 'Window': Request with GET/HEAD method cannot have body

I have added Swagger to my Spring Boot 2 application:
This is my Swagger config:
#Configuration
#EnableSwagger2
public class SwaggerConfig {
#Bean
public Docket api() {
// #formatter:off
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.any())
.paths(PathSelectors.any())
.build();
// #formatter:on
}
}
This is Maven dependency:
<!-- Swagger2 -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.8.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.8.0</version>
</dependency>
When I try to invoke for example http://localhost:8080/api/actuator/auditevents it fails with the following error:
TypeError: Failed to execute 'fetch' on 'Window': Request with GET/HEAD method cannot have body.
What am I doing wrong and how to fix it ?
I ran into this issue. Here is how I resolved it:
I had a method like this:
[HttpGet]
public IEnumerable<MyObject> Get(MyObject dto)
{
...
}
and I was getting the error. I believe swagger UI is interpreting the Get parameters as FromBody, so it uses the curl -d flag. I added the [FromQuery] decorator and the problem was resolved:
[HttpGet]
public IEnumerable<MyObject> Get([FromQuery]MyObject dto)
{
...
}
FYI this also changes the UI experience for that method. instead of supplying json, you will have a form field for each property of the parameter object.
The error message actually says what the problem is. You post data with curl using the -d option while trying to use GET.
If you use the -d option curl will do POST.
If you use -X GET option curl will do GET.
The HTTP GET method is for requesting a representation of the specified resource. Requests using GET should only retrieve data and hence cannot have body.
More info on GET vs POST
I had same problem with my .net core 2.0 solution and GET method that takes element id as header key or search for it by parameters in body. That is not the best way to implement but it's kind of special case.
As mentioned in this discussion. The HTTP spec does not forbid using body on a GET, but swagger is not implementing it like this. Even if there are APIs that work fine with body in GET Requests.
What more, the swagger frontend adds this body object into request even if it is null/undefined/empty object. It is -d "body_content_here" parameter. So in my case when i only search by id and body is empty, it still sends empty object (-d "{}") and throws mentioned error.
Possible solutions:
Start using postman app for this request - It will work fine. Tested.
Consider moving more advanced GET request (like search with criteria) to the independent POST Method
Use swagger generated CURL request request without -d parameter
Don't pass method type in Get method.
let res = await fetch("http://localhost:8080/employee_async",{
method: "POST",
body:JSON.stringify(data),
mode:"cors",
headers: {"Content-type":"application/json;charset=utf-8"}})
This is used for post only, If we don't assign any method type node automatically considered as Get method
To avoid this error be sure to annotate parameters in your controller with #RequestParam, like
#GetMapping("/get")
public Response getData(#RequestParam String param)
Looking at swagger exception/error message , looks like you are calling Get method with a set of input body. As per documentation of GET method doesn't accept any body. You need to change the GET method to POST method. It should work.
Maybe the problem is with the mapping of the method, make sure to use
#RequestMapping(value = "/<your path>" , method = RequestMethod.POST)
and put the data as body with #RequestBody
I also got the same error on the Swagger UI. My problem was I have mistakenly marked the Api Method as GET and send data in the request body. Once I change the annotation #GET to #POST issue got resolved.
Because you used GET http method with body.
If you want to have Json body, etc you need to use POST http method,
For example in your controller class, top of your method:
#PostMapping(value = "/save")
public ResponseEntity<HttpStatus> savePerson(#RequestBody Person person)
{...}
Use GET without body.
Pass Paremeters with [FromQuery] in Methods InPut
I was having this issue when trying to use Swagger UI on a Ruby On Rails app. I fixed it by changing the information container on the curl command. This is a example line:
parameter name: :body, in: :body, schema: {'$ref' => '#/definitions/ActivitiesFilter'}, required: true
into
parameter name: :attribute_name1, in: :query, required: true
parameter name: :attribute_name2, in: :query, required: true
parameter name: :attribute_name3, in: :query, required: true
note that you have to add as many lines as attributes are defined on your schema inside swagger_helper
This errors happens with wrong argument type. Just change "[FromBody]" to "[FromQuery]".
I faced similar issue; now, it's resolved.
You cannot pass parameter to HTTPGET thru Body.
To pass parameter to HTTPGet, there are 2 ways either use [FromRoute] or [FromQuery].
If u use [FromRoute], then
[HttpGet("{param1}/{param2}")]
public Person Get([FromRoute]string param1, string param2)
{
}
For PersonController,
from client side your url should be:
http://localhost:000/api/person/value1/value2
If u want to use [FromQuery]
[HttpGet]
public Person Get([FromQuery]string param1, string param2)
{
}
from client side your url should be:
http://localhost:000/api/person?param1=value1&param2=value2

Is it possible to return value from Spring AspectJ?

I'm returning value from my controller. Let it be ResponseEntity<String> type.
Controller returns:
new ResponseEntity<String>("{\"msg\":\"success\"}",HttpStatus.OK);
Following value goes to my spring aspect. I am receiving this object in following code:
#AfterReturning(pointcut = "somePointcut()",returning = "retVal")
public ResponseEntity<String> adviceTest3(Object retVal) {
//here i have access to controller's object
return new ResponseEntity<String>("{\"msg\":\"changed value within aspect\"}",HttpStatus.OK);
}
I'm aware that there is #AfterReturning. Is it any way manipulate data and achieve that?
With #AfterReturning, no. Quote from the documentation
An after returning advice has access to the return value (which it cannot modify), invoked method, methods arguments and target.
You could use #Around instead.

Spring mvc controller null return handler

#RequestMapping(method = RequestMethod.GET)
#ResponseBody
public List<Country> getListOfCountries() {
return countryService.listAll();
}
It displays a json view of the object but if the service return null, then I want to display an error message, Any suggestions pls?
First of all, even if this does not directly answer the question, your objects should never ever return null instead of empty collections - you can find the reasoning in Effective Java 2nd Edition, Item 43 / p.201
So, if the situation when no countries were found is normal it must be processed by the client JS code that will check the count and display the respective message.
If something has gone wrong you can throw an exception(as Biju has pointed out +1) - I believe that it's the service who should throw the exception because it knows the reason why it happened, and not to return null anyway.
I'd like to add that in Spring 3.2(in pre Spring 3.2 returning response body is complicated) you can set an #ExceptionHandler that will both return JSON and set the HTTP status code which can be later processed by the client. I think that returning a custom JSON response with some error code is most optimal here.
#RequestMapping("/test")
#ResponseBody
public List<Country> getListOfCountries() {
//assuming that your service throws new NoCountriesFoundException();
//when something goes wrong
return countryService.listAll();
}
#ExceptionHandler(NoCountriesFoundException.class)
ResponseEntity<String> test() {
return new ResponseEntity<String>(
"We are sorry, our server does not know any countries yet.",
HttpStatus.I_AM_A_TEAPOT );
}
Then in the JS code, you can do specific processing depending on the returned status code.
Also, to avoid declaration of the same #ExceptionHandler in different controllers, in Spring 3.2 you can put #ExceptionHandler inside a #ControllerAdvice annotated class.
For details, see http://static.springsource.org/spring/docs/current/spring-framework-reference/htmlsingle/#mvc-exceptionhandlers and http://www.springsource.org/node/3738 for 3.2 specific things
You have a couple of options I think:
If you return a null back, it will be returned as an empty string "", you can probably look for that and handle it.
Return a wrapper type on top of your list, this way if the wrapped list is null something like this will be returned back to the client {"countries":null} which can be more easily handled at the javascript end.
Throw an exception, which will propagate as a 500 status code back to the client, you can then have an error handler on the javascript side to handle this scenario.

Resources