Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Values of @PathVariable and @ModelAttribute overlapping

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:

  1. 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).
  2. Change @PathVariable("id") type from Long to Int. This will make User.id and id types differ but the cast to Long looks ugly :)
  3. Don't use @ModelAttribute here and query the DB for User again. Not consistent with other methods and involves redundant DB calls.

Any suggestions?

like image 828
Ulises Avatar asked Jul 23 '12 19:07

Ulises


1 Answers

How about this approach -

@RequestMapping(value = "/{id}", method = RequestMethod.GET)
public String showItem(@PathVariable("id") Long id,
            Model uiModel) {
       User user = (User)uiModel.asMap().get("user");
   ...    
}
like image 114
Biju Kunjummen Avatar answered Oct 20 '22 14:10

Biju Kunjummen