Spring Boot - JUnit Error testing MultiPartFile Image Upload RestController with MockMvc - spring

I'm trying to test a controller class that upload an image. The endpoint receives a long Id and a MultipartFile file. The code of the controller is:
#PostMapping(value = "/{userId}/image")
#ResponseStatus(HttpStatus.OK)
public UserDto uploadProfileImage(#PathVariable Long userId, #RequestParam("image") MultipartFile image) throws EntityNotFoundException {
User user = imageService.uploadImage(userId,image);
return UserMapper.makeDto(user);
}
And the test is:
#Test
public void whenUploadingImageThenReturnTheUser()throws Exception{
MockMultipartFile uploadFile = new MockMultipartFile("uploadFile", new byte[1]);
User user = new User("email#mail.com","pass", "name","lastNmae","description","123123",null);
when(imageService.uploadImage(1L,uploadFile)).thenReturn(user);
MvcResult result = mockMvc.perform(MockMvcRequestBuilders.fileUpload("/v1/users/"+1L+"/image").file(uploadFile).accept(contentType)).andExpect(status().isOk()).andReturn();
String content = result.getResponse().getContentAsString();
UserDto userDto =asObject(content);
assertEquals(userDto.getFirstName(),user.getFirstName());
}
When I run the test the console shows:
java.lang.AssertionError: Status
Expected :200
Actual :400
at org.springframework.test.util.AssertionErrors.fail(AssertionErrors.java:54)
at org.springframework.test.util.AssertionErrors.assertEquals(AssertionErrors.java:81)
at org.springframework.test.web.servlet.result.StatusResultMatchers$10.match(StatusResultMatchers.java:665)
at org.springframework.test.web.servlet.MockMvc$1.andExpect(MockMvc.java:171)
at com.empresa.mascotar.userService.controllers.UserControllerTest.whenUploadingImageThenReturnTheUser(UserControllerTest.java:165)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
I don't know why I get a 400 code response.
Could you help me please?
Thanks!

Related

Springboot #Value not loading

In my sample Springboot project on Github, the #Value property won't get loaded when starting the application. I cannot explain the strange behavior and hope that anyone could help me please to solve it and to avoid such stupid errors?
#RestController
public class PostClient {
#Value(value = "${target.uri}")
public String uri;
private RestTemplate restTemplate = new RestTemplate();
private HttpHeaders headers = new HttpHeaders();
public PostClient() {}
public HttpStatus postNumberPlate(CamImage camImage) {
LinkedMultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
map.add("numplate", camImage.getIdentifier());
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
HttpEntity<LinkedMultiValueMap<String, Object>> requestEntity = new HttpEntity<LinkedMultiValueMap<String,
Object>>(map, headers);
ByteArrayResource resource = new ByteArrayResource(camImage.getData()) {
#Override
public String getFilename() {
return camImage.getIdentifier() + ".png";
}
};
map.add("image", resource);
System.out.println(uri);
ResponseEntity<String> result = restTemplate.exchange(uri,
HttpMethod.POST,
requestEntity, String.class);
return result.getStatusCode();
}
}
The application.properties
target.uri=http://localhost:9001/postoffice
I read that the #Value is a core functionality of Springboot and should work fine. My project is so small, that I wonder what might broke the framework's behavior of automatic value replacement. I found different and similar questions regarding the #Value issue, but a real explanation cannot be found.
I tried to use a #Component Class with getters/setters and tried to #Autowire it into the shown Class, but that didn't work, too.
I'd like to go the proposed way of the Springboot reference, because any hard-coded String will result in problems, when building docker containers, where I must pass a configuration parameter. So I cannot only rely on a fixed application.properties in the classpath.
EDIT:
Running the application looks like:
shell:>one
Euro Plate # unimportant sysout
CamImage [identifier=BNAYG63, data=[B#4f4c4c4b] # generated plate
null # from sysout here should be the address!!
URI is not absolute
Details of the error have been omitted. You can use the stacktrace command to print the full stacktrace.
shell:>stacktrace
java.lang.IllegalArgumentException: URI is not absolute
at java.base/java.net.URL.fromURI(URL.java:674)
at java.base/java.net.URI.toURL(URI.java:1116)
at org.springframework.http.client.SimpleClientHttpRequestFactory.createRequest(SimpleClientHttpRequestFactory.java:145)
at org.springframework.http.client.support.HttpAccessor.createRequest(HttpAccessor.java:87)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:731)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:670)
at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:579)
at dev.semo.npgen.service.PostClient.postNumberPlate(PostClient.java:45)
at dev.semo.npgen.shell.NumberplateClientCommands.one(NumberplateClientCommands.java:62)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.springframework.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:282)
at org.springframework.shell.Shell.evaluate(Shell.java:180)
at org.springframework.shell.Shell.run(Shell.java:142)
at org.springframework.shell.jline.InteractiveShellApplicationRunner.run(InteractiveShellApplicationRunner.java:84)
at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:770)
at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:760)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:318)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1213)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1202)
at dev.semo.npgen.NpgenApplication.main(NpgenApplication.java:10)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49)
I have pulled your source from github and tested. Initially it was throwing error as you mentioned. After I have changed like below it is working fine. You should to autowire the PostClient, because the scanning happened and loaded the defaults while you started the application.
#ShellComponent
public class NumberplateClientCommands {
#Autowired
private PostClient postClient;
.....
#ShellMethod("Sends one simple POST request.")
public String one() throws FileNotFoundException {
NumberPlateUtility np = new NumberPlateUtility();
HttpStatus response = postClient.postNumberPlate(np.completeImage());
if (response == HttpStatus.ACCEPTED) {
return "Request sent successfully.";
}
return String.format("Request failed: %s", response.getReasonPhrase());
}
.......
}
Follow this Code Snip
#Value("${target.uri}")
private String uri;

Spring MockMvc Post Test: Comparison Failure

I am trying to perfom a Post test on this method with mockito
#RequestMapping(value = "/add", method = RequestMethod.POST)
public String addBookPost(#ModelAttribute("book") Book book, HttpServletRequest request, Model model) {
bookService.save(book);
MultipartFile bookImage = book.getBookImage();
try {
byte[] bytes = bookImage.getBytes();
String name = book.getId() + ".png";
BufferedOutputStream stream = new BufferedOutputStream(
new FileOutputStream(new File("src/main/resources/static/image/book/" + name)));
stream.write(bytes);
stream.close();
} catch (Exception e) {
e.printStackTrace();
}
So far I have done this below but my result shows I have two different instance of the object save , that is the book I save and expect is not the book I am getting .
#Test
public void addBookClicked() throws Exception {
Book book1 = new Book();
// when(bookService.save(anyObject())).thenReturn(anyObject());
mockMvc.perform(post("/book/add").with(user("admin").password("admin").roles("USER", "ADMIN"))
.accept(MediaType.TEXT_HTML)
.contentType(MediaType.TEXT_HTML))
.andExpect(status().is3xxRedirection()).andDo(print())
.andExpect(view().name("redirect:bookList"))
.andReturn();
Mockito.verify(bookService).save(book1);
}
And what can I do with the try and catch block in the test because it also gives an error in test Null pointer - may be because I am not testing or adding image to the test .
error log
MockHttpServletResponse:
Status = 302
Error message = null
Argument(s) are different! Wanted:
com.valentine.service.BookService#0 bean.save(
com.valentine.domain.Book#4acc5dff
);
-> at com.valentine.adminportal.controller.BookControllerTest.addBookClicked(BookControllerTest.java:80)
Actual invocation has different arguments:
com.valentine.service.BookService#0 bean.save(
com.valentine.domain.Book#10c72a6f
);
-> at com.valentine.adminportal.controller.BookController.addBookPost(BookController.java:50)
Comparison Failure: <Click to see difference>
Argument(s) are different! Wanted:
com.valentine.service.BookService#0 bean.save(
com.valentine.domain.Book#4acc5dff
);
-> at com.valentine.adminportal.controller.BookControllerTest.addBookClicked(BookControllerTest.java:80)
Actual invocation has different arguments:
com.valentine.service.BookService#0 bean.save(
com.valentine.domain.Book#10c72a6f
);
-> at com.valentine.adminportal.controller.BookController.addBookPost(BookController.java:50)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at com.valentine.adminportal.controller.BookControllerTest.addBookClicked(BookControllerTest.java:80)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.springf
In addBookClicked you are not actually posting book1 to your controller. The book1 instance in that test method is only referenced (1) where it is created and (2) where it is verified.
You must pass the serialised form of book1 in the body of the mockMvc.perform() invocation.
Here's an example:
mockMvc.perform(post("/book/add")
.with(user("admin").password("admin").roles("USER", "ADMIN"))
.accept(MediaType.TEXT_HTML)
.content(objectMapper.writeValueAsString(book1))
.contentType(MediaType.TEXT_HTML))
.andExpect(status().is3xxRedirection()).andDo(print())
.andExpect(view().name("redirect:bookList"))
.andReturn();
The objectMapper in this example is an instance of Jackson's ObjectMapper and its responsibility is to serialise the book1 instance to JSON for inclusion in the request body.

Spring rest template 401 error response

I have a rest controller answering on http://localhost:8080/documents.
I should have an authorization header to call it.
So in my client code i have :
HttpHeaders headers = new HttpHeaders();
headers.set(HttpHeaders.AUTHORIZATION, "myToken");
HttpEntity entity = new HttpEntity(null, headers);
restTemplate = new RestTemplate();
restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
restTemplate.getMessageConverters().add(new StringHttpMessageConverter());
response = restTemplate.exchange("http://localhost:8080/documents", HttpMethod.GET, entity, Document[].class);
Everything works fine.
After that i want to test the errors.
So, i remove the authorization header.
When i test with a tool like postman, i receive the 401 response.
But with my rest template, i only receive an IllegalArgumentException.
I alse have tested the ResponseErrorHandler.
public class MyErrorHandler implements ResponseErrorHandler {
#Override
public boolean hasError(ClientHttpResponse clientHttpResponse) throws IOException {
return false; //i've also tried return true
}
#Override
public void handleError(ClientHttpResponse clientHttpResponse) throws IOException {
String theString = IOUtils.toString(clientHttpResponse.getBody());
FunctionalTestException exception = new FunctionalTestException();
Map<String, Object> properties = new HashMap<String, Object>();
properties.put("code", clientHttpResponse.getStatusCode().toString());
properties.put("body", theString);
properties.put("header", clientHttpResponse.getHeaders());
exception.setProperties(properties);
throw exception;
}
}
and in my client i have
restTemplate.setErrorHandler(new MyErrorHandler());
It didn't work.
So my question is how to find my 401 error response using the rest template.
Here is the exception :
java.lang.IllegalArgumentException: invalid start or end
and the stack trace :
sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1455)
sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1441)
sun.net.www.protocol.http.HttpURLConnection.getHeaderField(HttpURLConnection.java:2979)
java.net.HttpURLConnection.getResponseCode(HttpURLConnection.java:489)
org.springframework.http.client.SimpleBufferingClientHttpRequest.executeInternal(SimpleBufferingClientHttpRequest.java:84)
org.springframework.http.client.AbstractBufferingClientHttpRequest.executeInternal(AbstractBufferingClientHttpRequest.java:48)
org.springframework.http.client.AbstractClientHttpRequest.execute(AbstractClientHttpRequest.java:53)
org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:619)
org.springframework.web.client.RestTemplate.execute(RestTemplate.java:580)
org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:498)
org.boite.dq.steps.UnauthorizedUser.callListCategories(UnauthorizedUser.java:61)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:498)
org.jbehave.core.steps.StepCreator$ParametrisedStep.perform(StepCreator.java:733)
org.jbehave.core.embedder.PerformableTree$FineSoFar.run(PerformableTree.java:346)
org.jbehave.core.embedder.PerformableTree$PerformableSteps.perform(PerformableTree.java:1088)
org.jbehave.core.embedder.PerformableTree$AbstractPerformableScenario.performRestartableSteps(PerformableTree.java:953)
org.jbehave.core.embedder.PerformableTree$NormalPerformableScenario.perform(PerformableTree.java:992)
org.jbehave.core.embedder.PerformableTree$PerformableScenario.perform(PerformableTree.java:902)
org.jbehave.core.embedder.PerformableTree$PerformableStory.performScenarios(PerformableTree.java:825)
org.jbehave.core.embedder.PerformableTree$PerformableStory.perform(PerformableTree.java:798)
org.jbehave.core.embedder.PerformableTree.performCancellable(PerformableTree.java:422)
org.jbehave.core.embedder.PerformableTree.perform(PerformableTree.java:393)
org.jbehave.core.embedder.StoryManager$EnqueuedStory.call(StoryManager.java:292)
org.jbehave.core.embedder.StoryManager$EnqueuedStory.call(StoryManager.java:266)
java.util.concurrent.FutureTask.run(FutureTask.java:266)
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
java.lang.Thread.run(Thread.java:745)
The crash is happening in HttpURLConnection::getHeaderField so I'd suspect that one of your response headers is malformed (not what HttpURLConnection expects it to be). Usually a 401 response comes with a WWW-Authenticate response header pointing the agent to the authentication methods supported by the service. I'd suspect that this header causes the crash.
A bug report in Jersey's issue-tracker shows that HttpURLConnection puts some constraints on the WWW-Authentication header format. In this particular case the value causing a similar crash is oauth_problem=token_rejected. A workaround proposed there is:
Workaround is to send valid header values (spec compliant) or using the ApacheConnector

Response Error 500 in Spring (HttpStatus field null pointer)

I have build a rest web service using spring. I am getting 500 server error when the service is called.
Controller class :
#RequestMapping(value = "/wordlist", method = RequestMethod.GET)
public ResponseEntity getList(#RequestHeader("wordid") int wordId) {
ResponseList responseObejct = wordService.getList(wordId);
return ResponseEntity.status(responseObejct.getStatusCode()).body(responseObejct.getResponseWordList());
}
DaoImplementation :
String listHql = "from Word where wordId > ? or wordId = ?";
Query query = session.createQuery(listHql);
query.setParameter(0, wordId);
query.setParameter(1, wordId);
query.setMaxResults(30);
if(query.list().size()>0){
response.setStatusCode(HttpStatus.OK);
response.setResponseWordList((ArrayList<Word>)query.list());
} else {
response.setStatusCode(HttpStatus.NOT_FOUND);
}
session.getTransaction().commit();
ResponseList.java (for response)
public class ResponseList {
private ArrayList<Word> responseWordList;
private HttpStatus statusCode ;
public ArrayList<Word> getResponseWordList() {
return responseWordList;
}
public void setResponseWordList(ArrayList<Word> responseWordList) {
this.responseWordList = responseWordList;
}
public HttpStatus getStatusCode() {
return statusCode;
}
public void setStatusCode(HttpStatus statusCode) {
this.statusCode = statusCode;
}
}
Error is:
ava.lang.IllegalArgumentException: Can not set final org.springframework.http.HttpStatus field
org.springframework.http.ResponseEntity.statusCode to java.util.ArrayList
sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:167)
sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:171)
sun.reflect.UnsafeFieldAccessorImpl.ensureObj(UnsafeFieldAccessorImpl.java:58)
sun.reflect.UnsafeQualifiedObjectFieldAccessorImpl.get(UnsafeQualifiedObjectFieldAccessorImpl.java:38)
java.lang.reflect.Field.get(Field.java:393)
com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.write(ReflectiveTypeAdapterFactory.java:86)
com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:195)
com.google.gson.Gson.toJson(Gson.java:586)
com.google.gson.Gson.toJson(Gson.java:565)
org.springframework.http.converter.json.GsonHttpMessageConverter.writeInternal(GsonHttpMessageConverter.java:199)
org.springframework.http.converter.AbstractGenericHttpMessageConverter.write(AbstractGenericHttpMessageConverter.java:100)
org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:222)
org.springframework.web.servlet.mvc.method.annotation.HttpEntityMethodProcessor.handleReturnValue(HttpEntityMethodProcessor.java:183)
org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite.handleReturnValue(HandlerMethodReturnValueHandlerComposite.java:80)
org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:126)
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:817)
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:731)
org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:959)
org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:893)
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:968)
org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:859)
javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:844)
javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)
I cannot understand why the error is coming. Please help.
The way you are calling ResponseEntity.status() is not valid.
It says
The method status(HttpStatus) is undefined for the type
ResponseEntity
To fix this try returning a ResponseEntity from your controller method like :
#RequestMapping(value = "/wordlist", method = RequestMethod.GET)
public ResponseEntity<ResponseList> getList(#RequestHeader("wordid") int wordId) {
ResponseList responseObejct = wordService.getList(wordId);
ResponseEntity<ResponseList> responseEntity = new ResponseEntity<>(responseObejct, HttpStatus.OK);
return responseEntity;
}
I ran into the same issue, and it turned out that this was fixed in Spring 4.3.1.
However, I cannot find a JIRA issue for that. Maybe it is a side-effect on another fix.
If you still have the problem (or if anyone else steps into this), please try again with 4.3.1 or higher.

HTTP Status 500 - Request processing failed; nested exception is java.lang.IllegalStateException

I am working on a Spring MVC application and have an issue with the validation. I need to create an user and it is a 2 step process(meaning 2 jsps with the same controller). The jsps have 2 different commandNames. So when I created the validator for the first model and initialize it, the first page loads fine. For testing, I am not using an if condition, but forwarding to next page. I get an error as the controller tries to load the validator with the current commandName object and it fails.
When I enter the url http://ip:port/data, the page loads as there is no validation, it is just initial load
When I try to submit the page without entering the firstName and submit, the method #RequestMapping(value = "/user") is called and the the next page 2 is supposed to be loaded. But the page 2 fails.
binder.getTarget() prints UserData the first time which is right
binder.getTarget() prints userinfo the 2nd time, when the next page is loading and it fails with the error
StackTrace:
HTTP Status 500 - Request processing failed; nested exception is java.lang.IllegalStateException: Invalid target for Validator [.validator.UserDataValidator#4366febc]: .model.UserInfo#4e3a061b
type Exception report
message Request processing failed; nested exception is java.lang.IllegalStateException: Invalid target for Validator [.validator.UserDataValidator#4366febc]: .model.UserInfo#4e3a061b
description The server encountered an internal error that prevented it from fulfilling this request.
exception
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is java.lang.IllegalStateException: Invalid target for Validator [.validator.UserDataValidator#4366febc]: .model.UserInfo#4e3a061b
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:978)
org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:868)
javax.servlet.http.HttpServlet.service(HttpServlet.java:648)
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:842)
javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77)
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:85)
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
root cause
java.lang.IllegalStateException: Invalid target for Validator [.validator.UserDataValidator#4366febc]: .model.UserInfo#4e3a061b
org.springframework.validation.DataBinder.assertValidators(DataBinder.java:516)
org.springframework.validation.DataBinder.setValidator(DataBinder.java:507)
.controller.AccountDataController.initBinder(AccountDataController.java:65)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:606)
org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:221)
org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:137)
org.springframework.web.method.annotation.InitBinderDataBinderFactory.initBinder(InitBinderDataBinderFactory.java:62)
org.springframework.web.bind.support.DefaultDataBinderFactory.createBinder(DefaultDataBinderFactory.java:53)
org.springframework.web.method.annotation.ModelFactory.updateBindingResult(ModelFactory.java:251)
Any suggestions on how to handle this would be helpful. Is there a way to make this work - having 2 different commandNames and trying to validate using one controller or do I need to update the commandName to one object and that object has all the classes inside it.
e.g.
class Parent{
UserData UserData;
UserInfo userInfo;
getter & setter
}
My Controller:
#Controller
#SessionAttributes("userData")
public class AController {
#Autowired
#Qualifier("userDataValidator")
private Validator validator;
#InitBinder
private void initBinder(WebDataBinder binder) {
System.out.println("getTarget: "+binder.getTarget()); ------------
binder.setValidator(validator);
}
#RequestMapping(value = "/data", method = RequestMethod.GET)
public String initForm(Model model){
UserData userData = new UserData();
model.addAttribute("userData", userData);
return "page1";
}//
#RequestMapping(value = "/user", method=RequestMethod.POST )
public String details(Model model, #Validated UserData userData, BindingResult result) {
*****
model.addAttribute("userinfo", userinfo);
return "page2";
}//
**EDIT**
#RequestMapping(value = "/create", method=RequestMethod.POST )
*****************
public String create(Model model, Userinfo userinfo, UserData userData) {
*********************user creation
}
**EDIT**
}
My JSPs
page1.jsp
<form:form method="POST" action="user" commandName="userData">
<form:label path="firstName"><b>Name</b></form:label> <br />
<form:input class="formLabel" path="firstName" />
****
</form>
page2.jsp
<form:form method="POST" action="create" commandName="userinfo">
***********fields
</form>
My validator
public class UserDataValidator implements Validator{
public boolean supports(Class<?> paramClass) {
return UserData.class.equals(paramClass);
}
public void validate(Object obj, Errors errors) {
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "firstName", "valid.firstName");
}
}
My Model
UserData.java
public class UserData {
String firstName;
getter & setter for firstName
}
Let me know if any more details are needed. Thanks.

Resources