Luuk D. Jansen
Luuk D. Jansen

Reputation: 4508

Saving a list of enums in an EBean and a Form

I have a field 'roles' which contains items of an enum. I am trying to edit this list with a Form, but get:

[InvalidPropertyException: Invalid property 'roles[0]' of bean class [models.Device]: Property referenced in indexed property path 'roles[0]' is neither an array nor a List nor a Map; returned value was [SERVER]]

This is my entity:

@Entity
public class Device extends Model {

    @Id
    @Constraints.Min(1)
    public Long id;

    @Constraints.Required
    public String name;

    @Constraints.Required
    public String ipAddress;

    @Constraints.Required
    @ElementCollection(fetch = FetchType.EAGER)
    public Set<DeviceRole> roles = new HashSet<DeviceRole>(Arrays.asList(DeviceRole.OTHER));

    @Version
    public Timestamp lastUpdate;

    public static Finder<Long,Device> find = new Finder<Long,Device>(
      Long.class, Device.class
    );

    public List<ValidationError> validate() {
        /*
        List<ValidationError> errors = new ArrayList<ValidationError>();
        if (User.byEmail(email) != null) {
            errors.add(new ValidationError("email", "This e-mail is already registered."));
        }
        return errors.isEmpty() ? null : errors;
        */
        return null;
    }
}

The edit and update functions in the controller:

public static Result edit(Long id) {
    Device device = Device.find.byId(id);
    Form<Device> myForm = Form.form(Device.class);
    myForm = myForm.fill(device);

    return ok(views.html.Devices.edit.render(myForm, listOfRoles()));
}

public static Result update() {
    Form<Device> deviceForm = Form.form(Device.class).bindFromRequest();

    if (deviceForm.hasErrors()) {
        return badRequest(views.html.Devices.edit.render(deviceForm, listOfRoles()));
    }

    // Form is OK, has no errors, we can proceed
    Device device = deviceForm.get();
    device.update(device.id);
    return redirect(routes.Devices.index());
}

private static List<String> listOfRoles() {
    List<String> list = new ArrayList<String>();
    for(DeviceRole role : DeviceRole.values()) {
        list.add(role.toString());
    }
    return list;
}

And the template:

@main("Edit a device") {

  @helper.form(action = routes.Devices.update()) {
      @helper.inputText(myForm("name"))
      @helper.inputText(myForm("ipAddress"))

      @helper.select(myForm("roles"), options(deviceRoles), 'multiple->"multiple")

      <input type="hidden" name="id" value="@myForm("id").value">
      <input type="submit" value="Submit">
  }

  <a href="@routes.Devices.index()">Cancel</a>
}

Upvotes: 1

Views: 1305

Answers (2)

Adrian Escutia
Adrian Escutia

Reputation: 1079

For Enum you can use @EnumValue, this is an Ebean specific annotation for mapping Enum's to database values.

public static enum RoleName {
  @EnumValue("SERVER") SERVER,
  @EnumValue("TEMPERATURE") TEMPERATURE,
  @EnumValue("HUMIDITY") HUMIDITY,
  @EnumValue("SWITCH") SWITCH,
  @EnumValue("OTHER") OTHER
}

Reference: http://ebean-orm.github.io/docs/mapping/#enummapping

Upvotes: 1

biesior
biesior

Reputation: 55798

Actually probably for doing it like this you would need to save them as a comma separated list of values in String field, to make it clearer I'd suggest to change DeviceRole to the Ebean model and handle it as common ManyToMany relation.

It gives you more flexibility IMHO and also allows to create more dynamic roles in the future,

Just forked your sample and modified it to show how I'd do it myself (some details in readme file):

https://github.com/biesior/temperature-control

P.S.: Take a look at the Ebean's ticket if nothing changed till now just saving list of enums is not supprted yet (I don't know the current state) http://avaje.org/topic-149.html

Upvotes: 2

Related Questions