I am trying to use Spring's DomainClassConverter feature with my Spring MVC project. (I have only very basic knowledge of Spring MVC and Spring, apologies in advance for any naive question here).
From the API docs:
The DomainClassConverter allows you to use domain types in your Spring MVC controller
method signatures directly, so that you don't have to manually lookup the instances via
the repository: (PS: Example 1.20)
What I understood from the above is that I don't have to write a finder method and the Spring supplies the User
object. So these are the steps I did:
Included the below line of XML in applicationcontext.xml
.
<bean class="org.springframework.data.web.config.SpringDataWebConfiguration" />
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<list>
<bean class="com.rl.userservice.controller.UserConverter"/>
</list>
</property>
Included this dependency in my pom.xml
per the Spring Data REST doc:
<dependencies> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-rest-webmvc</artifactId> <version>2.0.0.BUILD-SNAPSHOT</version> </dependency> </dependencies>
My controller looks like the below:
@Controller @RequestMapping(value = "/api/newuser") public class NewUserServiceController { @Autowired NewUserRepository newUserRepository; @RequestMapping("/{id}") public String showUserForm(@PathVariable("id") NewUser newUser, Model model) { model.addAttribute("newUser", newUser); return "userForm"; } }
Repository is like this:
@Repository public interface NewUserRepository extends JpaRepository<NewUser, Integer> { }
This is my converter service:
final class UserConverter implements Converter<Integer, NewUser> {
NewUserRepository newUserRepository;
public NewUser convert(Integer username) {
return newUserRepository.findOne(username);
}
}
When I run the program tomcat starts successful, but when accessing the URL localhost:8080/userservice/api/newuser/1 I get the below exception:
type Exception report
message
description The server encountered an internal error () that prevented it from fulfilling this request.
exception
org.springframework.beans.ConversionNotSupportedException: Failed to convert value of type 'java.lang.String' to required type
'com.mpp.userservice.domain.NewUser'; nested exception is
java.lang.IllegalStateException: Cannot convert value of type
[java.lang.String] to required type
[com.mpp.userservice.domain.NewUser]: no matching editors or
conversion strategy found
org.springframework.beans.TypeConverterSupport.doConvert(TypeConverterSupport.java:71)
org.springframework.beans.TypeConverterSupport.convertIfNecessary(TypeConverterSupport.java:45)
org.springframework.validation.DataBinder.convertIfNecessary(DataBinder.java:595)
org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver.resolveArgument(AbstractNamedValueMethodArgumentResolver.java:101)
org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:77)
org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:162)
org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:123)
org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104)
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:745)
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:686)
org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:80)
org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:925)
org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:856)
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:936)
org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:827)
javax.servlet.http.HttpServlet.service(HttpServlet.java:617)
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:812)
javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
root cause
java.lang.IllegalStateException: Cannot convert value of type [java.lang.String] to required type
[com.mpp.userservice.domain.NewUser]: no matching editors or
conversion strategy found
org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java:264)
org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java:93)
org.springframework.beans.TypeConverterSupport.doConvert(TypeConverterSupport.java:61)
org.springframework.beans.TypeConverterSupport.convertIfNecessary(TypeConverterSupport.java:45)
org.springframework.validation.DataBinder.convertIfNecessary(DataBinder.java:595)
org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver.resolveArgument(AbstractNamedValueMethodArgumentResolver.java:101)
org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:77)
org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:162)
org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:123)
org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104)
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:745)
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:686)
org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:80)
org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:925)
org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:856)
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:936)
org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:827)
javax.servlet.http.HttpServlet.service(HttpServlet.java:617)
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:812)
javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
note The full stack trace of the root cause is available in the Apache Tomcat/6.0.29 logs.
mpp.
Though not the best code, here's my controller:
public @ResponseBody ResponseEntity<ModelMap> getUserTypeJSON(@PathVariable("userID" String userID, HttpServletResponse response) {
UserType UserType = UserTypeRepository.findOne(id);
model.addAttribute("Name",UserType.getName());
...
}
There is an example here that I referenced, but this is using custom converter but does not seem to be using the domain converter service. Please advise. Is this the way to go if I want to reduce boilerplate code of writing CRUD operations? What is the real benefit of this DomainClassConverter
when I can get the data in in the other way?
Updated per Oliver Gierke suggestion - still does not work, same error
The document describes:
<mvc:annotation-driven conversion-service="conversionService" /> <bean class="org.springframework.data.repository.support.DomainClassConverter"> <constructor-arg ref="conversionService" /> </bean>
So I updated my applicationcontext.xml
as below, but the same issue:
<mvc:annotation-driven conversion-service="conversionService"/> <bean class="org.springframework.data.repository.support.DomainClassConverter"> <constructor-arg ref="conversionService" /> </bean> <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean"> <property name="converters"> <list> <bean class="com.rl.userservice.controller.UserConverter"/> </list> </property> </bean>
Still the same issue.
Update: DomainClassConverter works with Java Config, but not the XML way (at least experimented with a lot of combinations suggested here and else where on the internet). Just for the others who might be interested and get some useful info here's the code used.
pom.xml (Might require clean-up)
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-rest-webmvc</artifactId>
<version>2.0.0.M1</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>1.4.3.RELEASE</version>
</dependency>
The controller file (Might require clean-up)
@RequestMapping("/domain/{id}")
public @ResponseBody ResponseEntity<ModelMap> showDomainUserForm(@PathVariable("id") User userMatch, HttpServletResponse response) {
// some code omitted…
ModelMap model = new ModelMap();
model.addAttribute("DOMAIN-MAP","Domain Controller Service");
model.addAttribute("Name",userMatch.getName());
model.addAttribute("Phone",userMatch.getPhone());
// some code omitted…
}
The Java Config file assembled using examples from resource1 and resource2. (Might require clean-up)
package com.rl.userservice.controller;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.repository.support.DomainClassConverter;
import org.springframework.format.support.FormattingConversionService;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
@Configuration
@ComponentScan
@EnableWebMvc
public class WebConfig extends WebMvcConfigurationSupport{
@Bean
public RequestMappingHandlerMapping requestMappingHandlerMapping() {
RequestMappingHandlerMapping handlerMapping = super.requestMappingHandlerMapping();
handlerMapping.setUseSuffixPatternMatch(false);
handlerMapping.setUseTrailingSlashMatch(false);
return handlerMapping;
}
@Bean
public DomainClassConverter<?> domainClassConverter() {
return new DomainClassConverter<FormattingConversionService>(mvcConversionService());
}
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
}
Add the below bean definition in the applicationContext.xml
<bean class="com.rl.userservice.controller.WebConfig"/>
A URL is a String
, so {id}
is a String
too. Therefore your service must be able to convert a String
to NewUser
, not an Integer
as yours does.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With