Reputation: 1030
I am getting the exception in the title, even after adding all the code found online in other solutions (I've added the HttpMessageConverters
as well as the APPLICATION_JSON
accept header.)
public MyObject myMethod(String arg) {
String uri = BASE_URI + "/var?arg=" + arg;
restTemplate.setMessageConverters(getMessageConverters());
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
HttpEntity<String> entity = new HttpEntity<>(headers);
ResponseEntity<MyObject> response = restTemplate.exchange(uri, HttpMethod.GET, entity, MyObject.class);
MyObject resource = response.getBody();
return resource;
}
private List<HttpMessageConverter<?>> getMessageConverters() {
List<HttpMessageConverter<?>> converters =
new ArrayList<>();
converters.add(new MappingJackson2HttpMessageConverter());
converters.add(new StringHttpMessageConverter(Charset.forName("UTF-8")));
return converters;
}
MyObject:
public class MyObject {
private String test;
//more fields
@JsonCreator
public MyObject(String test) { //more args
this.test = test;
//more assignments
}
Anyone have any idea?
EDIT: relevant dependencies in pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-integration</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.8</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.8</version>
</dependency>
Upvotes: 0
Views: 10524
Reputation: 6216
By default spring or springboot configures the following message converters during 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 MappingJackson2HttpMessageConverter – converts JSON MappingJacksonHttpMessageConverter – converts JSON AtomFeedHttpMessageConverter – converts Atom feeds RssChannelHttpMessageConverter – converts RSS feeds
But for the Jackson converters to be added , spring has to detect that jackson is present in the classpath, so by adding jackson dependency to your application,the converter should be automatically configured, unless you are explicitly preventing the auto configuration by using the @EnableWebMVC
annotation.
Also,ensure that if you are using a rest endpoint, the method is annotated correctly, that is either use @RestController
for the class or else you will have to provide the @ResponseBody
annotation to indicate spring that it is a rest endpoint.
From the documentation:
Annotation indicating a method parameter should be bound to the body of the web request. The body of the request is passed through an HttpMessageConverter to resolve the method argument depending on the content type of the request. Optionally, automatic validation can be applied by annotating the argument with
@Valid
. Supported for annotated handler methods in Servlet environments.
Upvotes: 2
Reputation: 25936
Note that for the HttpMessageConverter to be eligible for mapping, it's canRead method must return true.
In the case of AbstractJackson2HttpMessageConverter (parent of MappingJackson2HttpMessageConverter), it checks not only MediaType, but also if Jackson can deserialize the object.
@Override
public boolean canRead(Type type, @Nullable Class<?> contextClass, @Nullable MediaType mediaType) {
if (!canRead(mediaType)) {
return false;
}
JavaType javaType = getJavaType(type, contextClass);
AtomicReference<Throwable> causeRef = new AtomicReference<>();
if (this.objectMapper.canDeserialize(javaType, causeRef)) {
return true;
}
logWarningIfNecessary(javaType, causeRef.get());
return false;
}
Now, I believe your JsonCreator
is incorrect.
NOTE: when annotating creator methods (constructors, factory methods), method must either be:
- Single-argument constructor/factory method without JsonProperty annotation for the argument: if so, this is so-called "delegate creator", in which case Jackson first binds JSON into type of the argument, and then calls creator. This is often used in conjunction with JsonValue (used for serialization).
- Constructor/factory method where every argument is annotated with either JsonProperty or JacksonInject, to indicate name of property to bind to
Upvotes: 0