Unable to fix: 'java.lang.String' to required type 'java.util.Collection' - spring

I'm getting this error when I submit my form and cannot figure out why this is happening. I believe the taglib should be handling this. I've tried changing the value passed in my jsp to itemValue="id" but it has no affect.
org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 1 errors
Field error in object 'content' on field 'stateCollection': rejected value [com.myapp.cmt.model.State[ id=3 ]]; codes [typeMismatch.content.stateCollection,typeMismatch.stateCollection,typeMismatch.java.util.Collection,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [content.stateCollection,stateCollection]; arguments []; default message [stateCollection]]; default message [Failed to convert property value of type 'java.lang.String' to required type 'java.util.Collection' for property 'stateCollection'; nested exception is java.lang.IllegalStateException:
Cannot convert value of type [java.lang.String] to required type [com.myapp.cmt.model.State] for property 'stateCollection[0]': no matching editors or conversion strategy found]
My jsp
<strong>State</strong><br/>
<form:checkboxes path="stateCollection" items="${states}" itemLabel="name"/>
My Content
public class Content implements Serializable {
.......
#JoinTable(name = "content_to_state", joinColumns = {
#JoinColumn(name = "content_id", referencedColumnName = "id")}, inverseJoinColumns = {
#JoinColumn(name = "state_id", referencedColumnName = "id")})
#ManyToMany
private Collection<State> stateCollection;
.....
#XmlTransient
public Collection<State> getStateCollection() {
return stateCollection;
}
public void setStateCollection(Collection<State> stateCollection) {
this.stateCollection = stateCollection;
}
.....
My Controller
...
#RequestMapping(value = "/{guid}/save", method = RequestMethod.POST)
public ModelAndView saveContent(#ModelAttribute("content") Content content, #PathVariable("guid") String guid) {
try {
// Save the modified object
contentService.save(content);
} catch (IllegalOrphanException ex) {
...
My content service
...
#Transactional
public void save(Content content) throws IllegalOrphanException, NonexistentEntityException, RollbackFailureException, Exception {
try {
utx.begin();
em.merge(content);
utx.commit();
} catch (Exception ex) {
} finally {
if (em != null) {
em.close();
}
}
}
...

Your title isn't correct. You have declared a Collection<State> your input is a String. Spring couldn't know how to make a State from a String, you have to tell it. Please see this question: Converting from String to custom Object for Spring MVC form Data binding?

I had the same problem. i'm using Spring, Hibernate.
I have one class with composite primary key and pass two parameters in request, my mistake was:
#Entity
#Table(name = "TAREAS")
public class Tarea implements Serializable {
private static final long serialVersionUID = 1L;
protected TareaPK clave;
private String descripcion;
.....
}
the controller:
#RequestMapping(value = "/tareas", params = {"clave", "tipot"}, method = RequestMethod.GET)
public String formularioTareaEditar(
#RequestParam(value = "clave") String clave,
#RequestParam(value = "tipot") String tipoTrabajo,
Model model) {
Tarea tarea = catalogoService.getTarea(tipoTrabajo, clave);
model.addAttribute(tarea);
return "tarea/editar";
}
#RequestMapping(value = "/tareas", params = {"clave", "tipot"}, method = RequestMethod.POST)
public String tareaEditar(#Valid #ModelAttribute Tarea tarea, BindingResult result) {
if (result.hasErrors()) {
return "tarea/editar";
} else {
catalogoService.edit(tarea);
return "redirect:/tareas";
}
}
So... when the info gets in the controller the parameter clave is considered as if the object TareaPK of the primary key.
i just change the name of the parameter in my controller.
#RequestMapping(value = "/tareas", params = {"txt_clave", "tipot"}, method = RequestMethod.GET)
public String formularioTareaEditar(...){
...
}

Related

Error with JPA PagingAndSorting request parameter

I have a Controller that pages and sorts all the news in my database:
#RequestMapping(value = "/viewstatus", method = RequestMethod.GET)
ModelAndView viewStatus(ModelAndView modelAndView, #RequestParam(name = "p", defaultValue = "1") int pageNumber) {
Page<StatusUpdate> page = statusUpdateService.getPage(pageNumber);
modelAndView.getModel().put("page", page);
modelAndView.setViewName("app.viewStatus");
return modelAndView;
}
With its call to the service that works fine:
public Page<StatusUpdate> getPage(int pageNumber) {
PageRequest request = new PageRequest(pageNumber-1, pageSize, Sort.Direction.DESC, "added");
return statusUpdateDao.findAll(request);
}
But now, I would like to do the same SortingAndPaging BUT with one parameter (SiteUser). Here is my object:
#Entity
#Table(name = "status_update")
public class StatusUpdate {
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Size(min=5, max=255, message="{addstatus.title.size}")
#Column(name = "title")
private String title;
#Size(min=5, max=5000, message="{addstatus.text.size}")
#Column(name = "text")
private String text;
#Column(name = "added")
#Temporal(TemporalType.TIMESTAMP)
#DateTimeFormat(pattern="yyyy/MM/dd hh:mm:ss")
private Date added;
#OneToOne(targetEntity = SiteUser.class)
#JoinColumn(name="user_id")
private SiteUser siteUser;
#PrePersist
protected void onCreate() {
if (added == null) {
added = new Date();
}
}
public StatusUpdate() {
}
But when I do it, it gives me this error:
Exception: org.springframework.dao.InvalidDataAccessApiUsageException: Parameter value [3] did not match expected type [com.caveofprogramming.model.entity.SiteUser (n/a)]; nested exception is java.lang.IllegalArgumentException: Parameter value [3] did not match expected type [com.caveofprogramming.model.entity.SiteUser (n/a)]
Failed URL: http://192.168.160.128:8080/viewmystatus
Exception message: Parameter value [3] did not match expected type [com.caveofprogramming.model.entity.SiteUser (n/a)]; nested exception is java.lang.IllegalArgumentException: Parameter value [3] did not match expected type [com.caveofprogramming.model.entity.SiteUser (n/a)]
I tired to send a String, but it did not work. I had to change it to a NativeQuery but I does not work with PagingAndSorting, it only works as a List (which is a headache to work with). So if you can help me with the ERROR of PagingAndSorting that would be great.
Here is the Controller:
#RequestMapping(value = "/viewmystatus", method = RequestMethod.GET)
ModelAndView viewMyStatus(ModelAndView modelAndView, #RequestParam(name = "p", defaultValue = "1") int pageNumber) {
SiteUser user = getUser();
Long user_id= user.getId();
Page<StatusUpdate> page = statusUpdateService.findMyStatusUpdates(user_id, pageNumber);
for(StatusUpdate statusUpdate: page){
SiteUser siteUser= statusUpdate.getSiteUser();
modelAndView.getModel().put("siteuser", siteUser);
}
modelAndView.getModel().put("page", page);
modelAndView.setViewName("app.viewStatus");
return modelAndView;
}
Here is the service:
public Page<StatusUpdate> findMyStatusUpdates(Long user_id, int pageNumber) {
PageRequest request = new PageRequest(pageNumber-1, pageSize, Sort.Direction.DESC, "added");
return statusUpdateDao.findBySiteUser(user_id, request);
}
And the DAO:
#Repository
public interface StatusUpdateDao extends PagingAndSortingRepository<StatusUpdate, Long> {
StatusUpdate findFirstByOrderByAddedDesc();
Page<StatusUpdate> findBySiteUser(Long user_id, Pageable pageable);
}
Thanks for your help!
Use a SiteUser object:
public Page<StatusUpdate> findMyStatusUpdates(Long user_id, int pageNumber) {
PageRequest request = new PageRequest(pageNumber-1, pageSize, Sort.Direction.DESC, "added");
return statusUpdateDao.findBySiteUser(new SiteUser(user_id), request);
}
You could try query by nested properties as well, but I think you must change user_id by userId, as underscore is a reserved character. Have a look to the documentation:
Spring data JPA Property expressions
Have you changed your findBySiteUser method? The one you posted looks fine but it seems is complaining about the signature. Even when PageRequest implements Pageable the signature has to be declared, explicitly, using Pageable, but the error message you are getting says PageRequest
public abstract org.springframework.data.domain.Page com.caveofprogramming.model.repository.StatusUpdateDao.findB‌​ySiteUser(com.caveof‌​programming.model.en‌​tity.SiteUser,org.sp‌​ringframework.data.d‌​omain.PageRequest)
More info:
PageRequest parameter not recognized as Pageable in Paging query

How to send Java collections containing subclasses to spring controller

I'm trying to send collections to my spring MVC controller:
#RequestMapping("/postUsers.do")
public #ResponseBody ResponseDTO postUsers(#ModelAttribute("mapperList") MapperList mapperList) {
//prints {"users":null}
System.out.println(new ObjectMapper().writeValueAsString(mapperList));
return new ResponseDTO();
}
this is the code posting my users :
public ResponseDTO postUsers(ArrayList<User> users) {
ResponseDTO serverResponse = null;
URL url = new URL(urlString);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoOutput(true);
connection.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
connection.setRequestMethod("POST");
// prints {"users":[{"property1":"x","property1":y}]}
System.out.println(objectMapper.writeValueAsString(new MapperList(users)));
objectMapper.writeValue(connection.getOutputStream(), objectMapper.writeValueAsString(new MapperList(users)));
//blabla ...
}
and this is the object containing my list :
public class MapperList implements Serializable {
private static final long serialVersionUID = 8561295813487706798L;
private ArrayList<User> users;
public MapperList() {}
public MapperList(ArrayList<User> users) {
this.setUsers(users);
}
public ArrayList<User> getUsers() {
return users;
}
public void setUsers(ArrayList<User> users) {
this.users = users;
}
}
and this is the users type to post:
public abstract class User implements Serializable {
private static final long serialVersionUID = -1811485256250922102L;
private String property1;
private String property2;
public User() {}
public User(String prop1, String prop2) {
// set properties
}
// getters and setters
}
the problem is, when I output the value of the users's array before to post it to the controller, I got the following json value :
{"users":[{"property1":"x","property1":y}]}
but in the controller, when I print what I get from the request body, I only get :
{"users":null}
I also tryed with the annotation #RequestBody instead of #ModelAttribute("mapperList") and a JSONException is displayed :
*A JSONObject text must begin with '{' at 1 [character 2 line 1]\r\n*
My array list of users contains only one user that should be displayed. I don't understand why this doesn't work...
Thanks for any help !
You can chnage your MapperList class definition as public class MapperList extends ArrayList<User>{ ..} you dont need to define any instance variable like private ArrayList users inside MapperList class. Use #Requestbody annotation. You will be able to use MapperList as a ArrayList
Try to use:
public class MapperList{
private List<User> users;
//setter and getter
//toString
}
public class User{
private String property1;
private String property2;
//getter + setter
}
json:
{"users":[{"property1":"x", "property2":"y"}]}
in controller use #RequestBody. In that case Jackson will map your json to ArrayList of users.
#ResponseStatus(HttpStatus.OK)
#RequestMapping("/postUsers.do")
public #ResponseBody ResponseDTO postUsers(#RequestBody MapperList users) {
System.out.println(users);
return null;
}
no need to get objectMapper in that case. Don't forget to set content-type in request header to application/json. It required by Spring to handle #RequestBody processing.
If not working try to change MapperList:
List<User> users = new ArrayList<User>();
On the server side keep the #RequestBody annotation:
public #ResponseBody ResponseDTO postUsers(#RequestBody MapperList mapperList)
...
But this line causes problems:
objectMapper.writeValue(
connection.getOutputStream(),
objectMapper.writeValueAsString(new MapperList(users))
);
First it converts the object to JSON and then again uses objectMapper to JSON-encode the string into output stream. Try the following instead:
connection.getOutputStream().write(
objectMapper.writeValueAsString(new MapperList(users))
.getBytes("UTF-8")
);
or directly output to stream:
objectMapper.writeValue(
connection.getOutputStream(),
new MapperList(users))
);
Zbynek gave me part of the answer. Indeed
objectMapper.writeValue(
connection.getOutputStream(),
objectMapper.writeValueAsString(new MapperList(users))
);
doesn't work properly in my case
But moreover, my User class was an abstract class, with many type of User as subclasses. so the #RequestBody annotation couldn't work without specified the object type in the Json.
I used the following annotations on User class to make it working :
#JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type")
#JsonSubTypes({
#JsonSubTypes.Type(value = SubClassA.class, name = "a"),
#JsonSubTypes.Type(value = SubClassB.class, name = "b")
})
Thanks a lot for all your answers.

Java: GroupSequenceProvider for Validation, object is null in getValidationGroups method

This is what I am trying to achieve:
I have an update request object and user is allowed to do Partial Updates. But I want to validate the field only if it is in the request body. Otherwise, it is OK to be null. To achieve this, I am using GroupSequenceProvider to let the Validator know what groups to validate. What am I doing wrong here? If there is a blunder, how do I fix it?
Documentation: https://docs.jboss.org/hibernate/validator/5.1/reference/en-US/html/chapter-groups.html#example-implementing-using-default-group-sequence-provider
#GroupSequenceProvider(UpdateUserRegistrationGroupSequenceProvider.class)
public class UpdateUserRegistrationRequestV1 {
#NotBlank(groups = {EmailExistsInRequest.class})
#Email(groups = {EmailExistsInRequest.class})
#SafeHtml(whitelistType = SafeHtml.WhiteListType.NONE, groups = {EmailExistsInRequest.class})
private String email;
#NotNull(groups = {PasswordExistsInRequest.class})
#Size(min = 8, max = 255, groups = {PasswordExistsInRequest.class})
private String password;
#NotNull(groups = {FirstNameExistsInRequest.class})
#Size(max = 255, groups = {FirstNameExistsInRequest.class})
#SafeHtml(whitelistType = SafeHtml.WhiteListType.NONE, groups = {FirstNameExistsInRequest.class})
private String firstName;
// THERE ARE GETTERS AND SETTERS BELOW
}
Group Sequence Provider Code:
public class UpdateUserRegistrationGroupSequenceProvider implements DefaultGroupSequenceProvider<UpdateUserRegistrationRequestV1> {
public interface EmailExistsInRequest {}
public interface PasswordExistsInRequest {}
public interface FirstNameExistsInRequest {}
#Override
public List<Class<?>> getValidationGroups(UpdateUserRegistrationRequestV1 updateUserRegistrationRequestV1) {
List<Class<?>> defaultGroupSequence = new ArrayList<Class<?>>();
defaultGroupSequence.add(Default.class);
defaultGroupSequence.add(UpdateUserRegistrationRequestV1.class);
if(StringUtils.hasText(updateUserRegistrationRequestV1.getEmail())) {
defaultGroupSequence.add(EmailExistsInRequest.class);
}
if(StringUtils.hasText(updateUserRegistrationRequestV1.getPassword())) {
defaultGroupSequence.add(PasswordExistsInRequest.class);
}
if(StringUtils.hasText(updateUserRegistrationRequestV1.getFirstName())) {
defaultGroupSequence.add(FirstNameExistsInRequest.class);
}
return defaultGroupSequence;
}
}
I am using Spring MVC, so this is how my controller method looks,
#RequestMapping(value = "/{userId}", method = RequestMethod.PUT, consumes = MediaType.APPLICATION_JSON_VALUE)
#ResponseStatus(HttpStatus.NO_CONTENT)
public void updateUser(#PathVariable("userId") Long userId,
#RequestBody #Valid UpdateUserRegistrationRequestV1 request) {
logger.info("Received update request = " + request + " for userId = " + userId);
registrationService.updateUser(userId, conversionService.convert(request, User.class));
}
Now the problem is, the parameter "updateUserRegistrationRequestV1" in the UpdateUserRegistrationGroupSequenceProvider.getValidationGroups method is null. This is the request object that I am sending in the request body and I am sending email field with it.
What am I doing wrong?
I too went through the same issue ,and hopefully solved it
You just have to check the object is null and put all your conditions inside it.
public List<Class<?>> getValidationGroups(Employee object) {
List<Class<?>> sequence = new ArrayList<>();
//first check if the object is null
if(object != null ){
if (!object.isDraft()) {
sequence.add(Second.class);
}
}
// Apply all validation rules from default group
sequence.add(Employee.class);
return sequence;
}

Spring MVC : How to Validate Nested Bean Property with Ajax

Suppose that I have these classes :
class Child {
private int id;
#NotNull
#Size(min = 5)
private String name;
#NotNull
private Parent parent;
//getter and setter methods
}
class Parent {
private int id;
#NotNull
private String name;
//getter and setter methods
}
Here is the handler method:
#RequestMapping(value = "/add", method = RequestMethod.POST)
#ResponseBody
public Map<String, ?> add(#Valid Child child, BindingResult result) {
Map<String, ?> out = new LinkedHashMap<String, ?>();
if(result.hasErrors()){
Map<String, String> errors = new LinkedHashMap<String, String>();
for (FieldError error : result.getFieldErrors()) {
errors.put(error.getField(), error.getDefaultMessage());
}
out.put("success", false);
out.put("errors", errors);
return out;
} else {
out.put("success", true);
}
return out;
}
If I submit this data to add a child via Ajax (POST):
name = testtesttest
parent.id = 3
Everything is OK. The new child is saved successfully.
But If don't include the parent.id (only name is set)
name = testtesttest
The validation result return this:
"errors":{"parent":"may not be null"}
Note the "parent" property in that JSON. It's supposed to return parent.id not parent.
It causes problem as the field on client-side script (HTML) has the name parent.id not parent.
Any suggestion How to solve this??
Thank you.
NOTE:
If I change the submitted data to this:
name = testtesttest
parent = 3
I got the other error:
{"success":false,"errors":{"parent":"Failed to convert property value of type 'java.lang.String' to required type 'com.test.entity.Parent' for property 'parent'; nested exception is java.lang.IllegalStateException: Cannot convert value of type [java.lang.String] to required type [com.test.entity.Parent] for property 'parent': no matching editors or conversion strategy found"}}

JAXB Error while using in SpringREST to return a ArrayList of a domain object

I am trying to use JAXB in Spring RESTful webservice.
My code is as follows:
#RequestMapping(value = "/countries",
method = RequestMethod.GET,
headers="Accept=application/xml, application/json")
public #ResponseBody CountryList getCountry() {
logger.debug("Provider has received request to get all persons");
// Call service here
CountryList result = new CountryList();
result.setData(countryService.getAll());
return result;
}
The CountryList.java class looks like:
#XmlRootElement(name="countries")
public class CountryList {
#XmlElement(required = true)
public List<Country> data;
#XmlElement(required = false)
public List<Country> getData() {
return data;
}
public void setData(List<Country> data) {
this.data = data;
}
}
The Country.java looks like:
#XmlRootElement(name="country")
public class Country {
private Calendar createdDt;
private String updatedBy;
private String createdBy;
private Long id;
private String countryName;
private Calendar updatedDt;
// getters and setters for all attributes goes here
}
Now, when I access the method getCountry(), I am getting the following exception
Caused by: com.sun.xml.bind.v2.runtime.IllegalAnnotationsException: 1 counts of IllegalAnnotationExceptions
Class has two properties of the same name "data"
this problem is related to the following location:
at public java.util.List com.cisco.bic.services.model.CountryList.getData()
at com.cisco.bic.services.model.CountryList
this problem is related to the following location:
at public java.util.List com.cisco.bic.services.model.CountryList.data
at com.cisco.bic.services.model.CountryList
Would anyone has any idea why is this error coming. Am I doing anything wrong in the annotaion part ??
Please help.
Regards
Saroj
You can't annotate both the getter/setter and the field, you need to decide on one of them.

Resources