Struts2 Map Form to Collection of Objects

The Struts2 documentation contains examples that are often basic at best which can make it challenging to figure out how to do things sometimes. I was working on creating a form that would allow me to select values from a list to connect 2 objects in a One-to-Many relationship. This is a common relationship for many things. In this example, I’ll use a User and Role class to demonstrate the concept.

For background, here’s a JPA mapped User and Role class.

import java.util.List;
import javax.persistence.*;

@Entity
public class User {

private Long id;
// ... other member variables
private List roles;

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

@OneToMany
@JoinTable(name = "UserRoles",
joinColumns = @JoinColumn(name = "user_Id"),
inverseJoinColumns = @JoinColumn(name = "role_Id"),
uniqueConstraints = @UniqueConstraint(columnNames = {"user_Id", "role_Id"})
)
public List getRoles() {
return roles;
}

public void setRoles(List roles) {
this.roles = roles;
}

// ... other properties
}

@Entity
public class Role {

private Long id;

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

// ... other properties
}

A list of Roles exists in the database. When a User is created, they are assigned one or more Roles. The User and Roles are connected in the Database through a join table as defined in the mapping. At this point I created some DAO Repository classes to manage the persistence and an Action to handle the form values. (The details of JPA, setting up Persistence and Actions are beyond the scope of this post.)

The part that caused me the most grief ended up being the form. I wanted to add a checkbox list that contained all of the Roles. The example on the Struts site for checkboxlist, a control with 43 documented properties is:



Needless to say, there was some ‘figuring out’ to be done.

The form itself is pretty vanilla for the most part. The checkboxlist is the interesting part because it’s what allows us to map the User to the Roles. I knew that I was looking for something to put into the value property of the control that would tell it to pre-select the Role values that were already associated with the User.

I started out with something like:

list="roles"
listKey="id"
listValue="name"
label="%{getText('label.roles')}"
value="user.roles"/>

That didn’t work. When you think about it, that makes sense because the keys in the list are ids and the values supplied are Role objects. So I needed to figure out how to get the Ids from the Roles. I could have done that in the Action class, but it seemed like there should be a better way. A way that would allow me to continue in more of a Domain fashion.

Doing some research into OGNL, I came upon the list projections section which was the key…

The OGNL projection syntax gives us user.roles.{id}. Basically that is a list comprehension that takes of list of Role objects and turns it into a list of Role Ids. That list of Ids becomes the list of values that will be preselected.

Knowing that I can now create a select box that will include the pre-selected values on an edit form:

list="roles"
listKey="id"
listValue="name"
label="%{getText('label.roles')}"
value="user.roles.{id}"/>

Enjoy.

7 thoughts on “Struts2 Map Form to Collection of Objects”

  1. hi buddy this is exactly what i was looking for..thanx for this wonderful informative post..
    i have an issue something related to this..
    i am using struts2 framework and Hibernate annotations..

    i have a Product.java model and Inventory.java model..One Product can be in many inventories..

    i am displaying the product list in a table. i have given in front of every row which contains product information.

    now when user checks 3 or 4 (or whatever he likes) checkboxes and clicks on ‘add to inventory’ button, those products should be updated with inventory objects…m currently using @ManytoOne in Inventory.java
    do u have any idea how should i do this task..

    waiting for ur reply

  2. @correction –

    i have given s:checkbox in front of every row which contains product information

  3. @DreamCoder,
    You can’t bind directly to the Hibernate objects in that case because you’ll just end up binding to something like Inventory.id which will eventually cause you trouble.

    The best way to do that is to have something like public void setInventoryIds(Integer[] inventoryIds) in your Action and handle loading the instances through Hibernate yourself.

  4. Hi Geoff,

    Might be a bit irrelevant but I am trying to access a form bean like name=”user.roles.id” in my form. Can access the bean but when I press submit the user.roles is null in Action class. I have a private property user in Action class which is a DTO (i.e. all properties are public). Any help would be appreciated.

    Thanks.

  5. Thanks for this, Geoff! I found myself in the same exact predicament, having everything but the checkbox pre-selection figured out.

  6. OMG! Thank you so much for this!!!
    I was breaking my head exactly for this very same issue. I even added a method to preselect in the action but nothing would work.

    You can’t imagine how happy you’ve made me! I really appreciate it.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>