HttpMessageNotReadableException: Could not read JSON: Unrecognized field using Spring for Android

The exception seems to suggest that while the Jackson mapper is trying to create a Loja from the returned json, it encountered a json field with a key of Loja, which it didn't know how to handle (because there are no fields in the Loja java object named "Loja"), so it failed. This seems logical, because it appears that the server is effectively returning this json structure:

{"Loja":{"nome":"teste","xValue":"20","yValue":"30","andar":"1"}}

Because of this, you have two primary options.

  1. Change the object that is passed to getForObject() or
  2. Change the json returned from the server.

For the first one, you can have your client do a getForObject() passing in an Object that contains a Loja.

Something like this class:

class MyObj {
    private Loja Loja;

    public void setLoja(Loja loja) {
        this.Loja = loja;
    }

    public Loja getLoja() {
        return this.Loja;
    }
}

being used with this call:

restTemplate.getForObject(url, MyObj.class);

Alternatively, you could have your server return the Loja objects fields as a part of the model, or better yet, return the instance of the Loja object that you created. Spring is smart enough to utilize Jackson to turn your POJO's into the proper json model you are expecting.

@RequestMapping("/android/played")
public Loja getLoja() {
    System.out.println("Android Resquest.");

    return new Loja("teste", "20", "30", "1");
}

Which would produce this json:

{"nome":"teste","xValue":"20","yValue":"30","andar":"1"}

Which would be readable by your getForObject() method on the client side just the way it is currently.


I have discovered what was wrong with my code. Nicholas was right, my JSON was something like:

{"Loja":{"nome":"teste","xValue":"20","yValue":"30","andar":"1"}}

and the field Loja wasn't being recognized when sent to Android application.

Here's what I did: I created another class called Lojas which has nothing more than a Loja List.

public class Lojas {

    private List<Loja> lojas;

    public Lojas() {
    }

    public List<Loja> getLojas() {
        return lojas;
    }

    public void setLojas(List<Loja> lojas) {
        this.lojas = lojas;
    }
}

in my getLoja() method, I'm returning this brand new method created:

public Lojas getLoja() {
        RestTemplate restTemplate = new RestTemplate();
        restTemplate.getMessageConverters().add(new MappingJacksonHttpMessageConverter());
        restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory());

        String url = BASE_URL + "/android/played.json";
        return restTemplate.getForObject(url, Lojas.class);
    }

this way, I can request an List of Loja object at once. but to do it I had to change server side to always return an List of Loja object:

@RequestMapping("/android/played")
    public ModelAndView getLoja() {
        System.out.println("Android Request.");

        List<Loja> list = new ArrayList<Loja>();
        list.add(new Loja("teste", "20", "30", "1"));
        list.add(new Loja("teste2", "20", "30", "1"));
        ModelAndView mav = new ModelAndView();
        mav.addObject("lojas", list);
        return mav;
    }

I solved this problem making a JSON Post using RestTemplate.

HTTP_HEADERS.setContentType(MediaType.APPLICATION_JSON);

final ObjectWriter ow = new ObjectMapper().writer().withDefaultPrettyPrinter();
final String body = ow.writeValueAsString(convertedFireCsvBeans);
final HttpEntity<String> entity = new HttpEntity<>(body, HTTP_HEADERS);   
final ParameterizedTypeReference<String> responseType = new ParameterizedTypeReference<String>(){};
final ResponseEntity<String> responseEntity = REST_TEMPLATE.exchange(url, HttpMethod.POST, entity, responseType);
if(responseEntity.getStatusCode() != null){
            System.out.println("HTTP STATUS CODE: " + responseEntity.getStatusCode() +
                       "\n"+ responseEntity.getStatusCode().getReasonPhrase());
                    httpStatus = responseEntity.getStatusCode();                    
                }

The main thing is that my HttpEntity I had to set to String.

I hope it can help someone.