Himanshu Mishra Himanshu Mishra - 1 month ago 7
Java Question

Not able to persist the role mapped to the user

I am creating an application with Spring 4, Hibernate 4 having Spring security

Users have roles assigned to them, but when I tried to create the user, it not able to save the user it is giving me exception on Browser below the field of role

Failed to convert property value of type [java.lang.String[]] to required type [java.util.Set] for property userRoles; nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type


[@org.hibernate.validator.constraints.NotEmpty @javax.persistence.ManyToMany @javax.persistence.JoinTable com.himanshu.blogger.model.Role] for value 2; nested exception is java.lang.StackOverflowError

My User model class

@Entity
@Table(name = "BLOG_USER")
public class User {

@Id
@Column(name = "USER_ID")
private String userId;

@NotEmpty
@Column(name = "PASSWORD")
private String password;

@NotEmpty
@Column(name = "FIRST_NAME")
private String firstName;

@NotEmpty
@Column(name = "MIDDLE_NAME")
private String middleName;

@NotEmpty
@Column(name = "LAST_NAME")
private String lastName;

@Column(name = "EMAIL")
private String email;

@Column(name = "PHONE")
private String phone;

@NotNull
@Column(name = "STATE")
private Integer state = State.ACTIVE.getState();

@Transient
private String stateName;

@NotEmpty
@ManyToMany(fetch = FetchType.LAZY)
@JoinTable(name = "USER_ROLE_MAP", joinColumns = { @JoinColumn(name = "USER_ID") }, inverseJoinColumns = {
@JoinColumn(name = "ROLE_ID") })
private Set<Role> userRoles = new HashSet<>();

/*skipped getter, setters and some utility methods*/


Role model class

@Id
@GeneratedValue(strategy=GenerationType.AUTO)
@Column(name="ROLE_ID")
private Integer roleId;

@Column(name="ROLE_TYPE", length=20, nullable=false, unique=true)
private String roleType=RoleType.USER.getRoleType();
/*skipped getters and setters*/


My controller methods for registering new user here I have added a model attribute also to load the roles in registration form

/**
* This method will provide the medium to add a new user.
* By GET method it will identify that it has to load registration page
*/
@RequestMapping(value = { "/newuser" }, method = RequestMethod.GET)
public String newUser(ModelMap model) {
User user = new User();
model.addAttribute("user", user);
model.addAttribute("edit", false);
return "registration";
}

/**
* This method will be called on form submission, handling POST request for
* saving user in database. It also validates the user input
*/
@RequestMapping(value = { "/newuser" }, method = RequestMethod.POST)
public String saveUser(@Valid User user, BindingResult result, ModelMap model) {

System.out.println("save user : "+user);
if (result.hasErrors()) {
return "registration";
}

if(!userService.isUniqueUser(user.getUserId())){
FieldError userIdError =new FieldError("user","userId",messageSource.getMessage("non.unique.ssoId", new String[]{user.getUserId()}, Locale.getDefault()));
result.addError(userIdError);
return "registration";
}

userService.saveUser(user);

model.addAttribute("success", "User " + user.getFirstName() + " "+ user.getLastName() + " registered successfully");

//return "success";
return "registrationsuccess";
}

@ModelAttribute("blogRoleList")
public List<Role> initializeProfiles() {
return roleService.findAll();
}


I have registered a convertor to convert role id to Role object

@Component
public class RoleIdtoRoleConverter implements Converter<Object, Role> {

@Autowired
RoleService roleService;

public Role convert(Object roleIdObj) {

System.out.println("covertor called with id " + roleIdObj.toString());
Integer roleId = -1;
try {
roleId = Integer.parseInt((String) roleIdObj);
} catch (NumberFormatException e) {
throw new ConversionFailedException(TypeDescriptor.valueOf(String.class),
TypeDescriptor.valueOf(Role.class), roleIdObj, null);
}

System.out.println("covertor called with id " + roleIdObj.toString());

Role role = roleService.findRoleById(roleId);
System.out.println("Role = " + role);

return role;
}


Registered this convertor in my config class

@Autowired
RoleIdtoRoleConverter roleIdToRoleConverter;

public void addFormatters(FormatterRegistry registry) {
registry.addConverter(roleIdToRoleConverter);
}


Registration JSP file registration.jsp

<form:form method="POST" modelAttribute="user" class="form-horizontal">
<%-- <form:input type="hidden" path="userId" id="useId"/> --%>

<div class="row">
<div class="form-group col-md-12">
<label class="col-md-3 control-lable" for="firstName">First Name</label>
<div class="col-md-7">
<form:input type="text" path="firstName" id="firstName" class="form-control input-sm"/>
<div class="has-error">
<form:errors path="firstName" class="help-inline"/>
</div>
</div>
</div>
</div>

<div class="row">
<div class="form-group col-md-12">
<label class="col-md-3 control-lable" for="lastName">Last Name</label>
<div class="col-md-7">
<form:input type="text" path="lastName" id="lastName" class="form-control input-sm" />
<div class="has-error">
<form:errors path="lastName" class="help-inline"/>
</div>
</div>
</div>
</div>

<div class="row">
<div class="form-group col-md-12">
<label class="col-md-3 control-lable" for="userId">User ID</label>
<div class="col-md-7">
<c:choose>
<c:when test="${edit}">
<form:input type="text" path="userId" id="userId" class="form-control input-sm" disabled="true"/>
</c:when>
<c:otherwise>
<form:input type="text" path="userId" id="userId" class="form-control input-sm" />
<div class="has-error">
<form:errors path="userId" class="help-inline"/>
</div>
</c:otherwise>
</c:choose>
</div>
</div>
</div>
<c:if test="${!edit}">
<div class="row">
<div class="form-group col-md-12">
<label class="col-md-3 control-lable" for="password">Password</label>
<div class="col-md-7">
<form:input type="password" path="password" id="password" class="form-control input-sm" />
<div class="has-error">
<form:errors path="password" class="help-inline"/>
</div>
</div>
</div>
</div>
</c:if>


<div class="row">
<div class="form-group col-md-12">
<label class="col-md-3 control-lable" for="email">Email</label>
<div class="col-md-7">
<form:input type="text" path="email" id="email" class="form-control input-sm" />
<div class="has-error">
<form:errors path="email" class="help-inline"/>
</div>
</div>
</div>
</div>

<div class="row">
<div class="form-group col-md-12">
<label class="col-md-3 control-lable" for="userRoles">Roles</label>
<div class="col-md-7">
<form:select path="userRoles" items="${blogRoleList}" multiple="true" itemValue="roleId" itemLabel="roleType" class="form-control input-sm" />
<div class="has-error">
<form:errors path="userRoles" class="help-inline"/>
</div>
</div>
</div>
</div>

<div class="row">
<div class="form-actions floatRight" style="margin-left: 25px">
<c:choose>
<c:when test="${edit}">
<input type="submit" value="Update" class="btn btn-primary btn-sm"/> or <a href="<c:url value='/listUser' />">Cancel</a>
</c:when>
<c:otherwise>
<input type="submit" value="Register" class="btn btn-primary btn-sm"/> or <a href="<c:url value='/listUser' />">Cancel</a>
</c:otherwise>
</c:choose>
</div>
</div>
</form:form>


But am not able to figure out it is not able to save the data, I have printed the user object in controller it is showing Roles as blank array, did I am missing some things here, not able to get, any help and suggestions will be got.

Adding Code for saving user

Abstract dao class

public class AbstractDao <PK extends Serializable, T>{

private final Class<T> persistantClass;

@Autowired
SessionFactory sessionFactory;

@SuppressWarnings("unchecked")
public AbstractDao() {
this.persistantClass=(Class<T>)((ParameterizedType)this.getClass().getGenericSuperclass()).getActualTypeArguments()[1];
}

public void persistEntity(T entity) {
this.getSession().persist(entity);
}
/* mor emethods to load data on based on object type */
}


User Dao implimentation calss

@Repository("userDao")
public class UserDaoImpl extends AbstractDao<String, User> implements UserDao{
@Override
public void saveUser(User user) {
persistEntity(user);

}
/* more methods for fetching data from db*/
}


Thanks.

Answer

I got the problem with my application. The problem was with the dao method which was there to get role object from DB, by mistake while writing the code I did made the call to same method, which executing recursively, so convertor was not able to get the role object from DB.