spring-projects / spring-boot

Spring Boot
https://spring.io/projects/spring-boot
Apache License 2.0
74.57k stars 40.55k forks source link

Deserialization issue for spring classes that have been migrated to the builder pattern (no constructor) #13828

Closed vivinjoseph9 closed 6 years ago

vivinjoseph9 commented 6 years ago

hi all,

I am getting the below error:

org.springframework.http.converter.HttpMessageConversionException: Type definition error: [simple type, class org.springframework.cloud.servicebroker.model.catalog.Catalog]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `org.springframework.cloud.servicebroker.model.catalog.Catalog` (no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
 at [Source: (PushbackInputStream); line: 1, column: 2]
    at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:238)
    at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.read(AbstractJackson2HttpMessageConverter.java:223)
    at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:100)
    at org.springframework.web.client.RestTemplate$ResponseEntityResponseExtractor.extractData(RestTemplate.java:991)
    at org.springframework.web.client.RestTemplate$ResponseEntityResponseExtractor.extractData(RestTemplate.java:974)
....
....
..
    ResponseEntity<Catalog> response = basicAuthRestTemplate.exchange(getUrl(XBEPaths.SB_CATALOG_PATH), HttpMethod.GET, null,
            Catalog.class);

AND

    ResponseEntity<CreateServiceInstanceResponse> response = basicAuthRestTemplate.exchange(url, HttpMethod.PUT, entity,
            CreateServiceInstanceResponse.class);

for the above call in my test, the call is successful and the reponse is obtained, then this response is deserialized from json to java. that is where the error is thrown

private Object readJavaType(JavaType javaType, HttpInputMessage inputMessage) throws IOException {
    try {
        if (inputMessage instanceof MappingJacksonInputMessage) {
            Class<?> deserializationView = ((MappingJacksonInputMessage) inputMessage).getDeserializationView();
            if (deserializationView != null) {
                return this.objectMapper.readerWithView(deserializationView).forType(javaType).
                        readValue(inputMessage.getBody());
            }
        }
        return this.objectMapper.readValue(inputMessage.getBody(), javaType);
    }
    catch (InvalidDefinitionException ex) {
        throw new HttpMessageConversionException("Type definition error: " + ex.getType(), ex);
    }
    catch (JsonProcessingException ex) {
        throw new HttpMessageNotReadableException("JSON parse error: " + ex.getOriginalMessage(), ex);
    }
} 

Previously this used to work because the classes given in the expected response type(Catalog - package org.springframework.cloud.servicebroker.model.catalog; , CreateServiceInstanceResponse - package org.springframework.cloud.servicebroker.model.instance; etc) had default constructors, however after the migration to the builder pattern the rest call throws a type definition error, due to the lack of a default constructor which it is looking for.

I tried migrating to the latest jackson version, to see if that could resolve the issue , but it dint help. This problem is specific to the classes that have migrated to the builder pattern.

Please do let me know if anyone has come across this , or atleast has a workaround for this problem.

Thanks in advance.

Vivin.

wilkinsona commented 6 years ago

The code in question is not part of Spring Boot. It's part of Spring Cloud Open Service Broker.