I have an User
object stored in the session with @SessionAttributes
. And a straight-forward method decorated with @ModelAttribute
in order to initialize it whenever the session's value is null.
User class:
@Entity
@Table( name="USER")
public class User implements java.io.Serializable {
private Long id;
private String username;
private String password;
....
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name ="ID")
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
...
Controller:
@RequestMapping("/item")
@Controller
@SessionAttributes({"user"})
public class MyController {
@ModelAttribute method:
@ModelAttribute("user")
public User createUser(Principal principal) {
return userService.findByUsername(principal.getName());
}
It all seems to work as expected except in this particular method:
@RequestMapping(value = "/{id}", method = RequestMethod.GET)
public String showItem(@PathVariable("id") Long id, @ModelAttribute("user") User user,
Model uiModel) {
...
}
The problem is that User.id
is being set with @PathVariable("id")
. I believe I ran into this with @RequestParam
too. I'm assuming that's because both have the same name and type. After reading Spring's documentation (see below) I'm assuming this is expected behavior:
The next step is data binding. The WebDataBinder class matches request parameter names — including query string parameters and form fields — to model attribute fields by name. Matching fields are populated after type conversion (from String to the target field type) has been applied where necessary.
However, I would think this scenario is fairly common, how are other people handling this? If my findings are correct and this is expected behavior (or bug), this seems to be very error prone.
Possible solutions:
- Change
@PathVariable("id")
to@PathVariable("somethingElse")
. Works but it's not as straightforward with @RequestParam (e.g. I don't know how to change jqgrid's request parameter id to something else but this is another issue). - Change
@PathVariable("id")
type from Long to Int. This will makeUser.id
andid
types differ but the cast to Long looks ugly :) - Don't use
@ModelAttribute
here and query the DB forUser
again. Not consistent with other methods and involves redundant DB calls.
Any suggestions?
How about this approach -
use @SessionAttribute