Reputation: 8955
I am trying to configure a Java 8 & Spring 4.3.1 app to use RESTful services. I get it to work perfectly with the config below, until I introduce a ContextResolver.
The reason for the ContextResolver is because I need to format a java.time.LocalDateTime
to JSON.
I first tried with annotations on my model bean by adding the @JsonFormat,
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = DATE_FORMAT)
@DateTimeFormat(pattern=DATE_FORMAT)
@Column(name = "JOINING_DATE", nullable = false)
@Type(type="org.hibernate.type.LocalDateTimeType")
private LocalDateTime joiningDate;
and got the following error:
java.lang.NoSuchMethodError: com.fasterxml.jackson.datatype.jsr310.ser.JSR310FormattedSerializerBase.findFormatOverrides(Lcom/fasterxml/jackson/databind/SerializerProvider;Lcom/fasterxml/jackson/databind/BeanProperty;Ljava/lang/Class;)Lcom/fasterxml/jackson/annotation/JsonFormat$Value;
Secondly, I removed the @JsonFormat annotation and tried with a ContextResolver,
ObjectMapperContextResolver.java
package com.jobs.spring.configuration;
import javax.ws.rs.ext.ContextResolver;
import javax.ws.rs.ext.Provider;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
@Provider
public class ObjectMapperContextResolver implements ContextResolver<ObjectMapper> {
private final ObjectMapper MAPPER;
public ObjectMapperContextResolver() {
MAPPER = new ObjectMapper();
MAPPER.registerModule(new JavaTimeModule());
MAPPER.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
}
@Override
public ObjectMapper getContext(Class<?> type) {
return MAPPER;
}
}
and got the following error:
[org.springframework.web.servlet.PageNotFound] (default task-4) No mapping found for HTTP request with URI [/jbosswildfly/employee/list] in DispatcherServlet with name 'rest'
Please can someone advise, I think my Spring configuration may not be correct.
As I said, if I don't use the @JsonFormat annotation or the ContextResolver, I can call the RESTful service successfully (but I need to format the dates).
Thank you
My config as as follows:
pom.xml
.
.
.
<jackson.version>2.8.0</jackson.version>
.
.
.
<!-- JSON -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>${jackson.version}</version>
</dependency>
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.1"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
metadata-complete="false">
<servlet>
<servlet-name>rest</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>rest</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
rest-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd">
<context:component-scan base-package="com.jobs.spring" />
<mvc:annotation-driven />
</beans>
Rest Controller
@CrossOrigin(origins = {"*"})
@RestController
@RequestMapping(EmployeeRESTService.BASE_URI)
public class EmployeeRESTService {
public static final String BASE_URI = "/employee";
@Autowired
private EmployeeService employeeService;
@RequestMapping(value = "/list", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public List<Employee> findAllEmployees() {
return employeeService.findAll();
}
@RequestMapping(value = "/save", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE)
public @ResponseBody String saveEmployee(@RequestBody Employee employee){
Long id = employeeService.save(employee);
return Long.toString(id);
}
}
Upvotes: 3
Views: 7685
Reputation: 8955
SOLVED
By adding the following class, it works now:
package com.jobs.spring.configuration;
import java.text.SimpleDateFormat;
import java.util.List;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
@Configuration
@EnableWebMvc
public class WebConfiguration extends WebMvcConfigurerAdapter {
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
builder.indentOutput(true).dateFormat(new SimpleDateFormat("yyyy-MM-dd"));
converters.add(new MappingJackson2HttpMessageConverter(builder.build()));
converters.add(new MappingJackson2XmlHttpMessageConverter(builder.createXmlMapper(true).build()));
}
}
Upvotes: 3