Search code examples
javawicketdropdownchoice

overwrite selection of DropDownChoice in Wicket


I have an issue with the way Wicket searches for the selection for a DropDownChoice in a Model.

Example

//User Bean
public class Users {
  private Long language_id;
  public Long getLanguage_id() {
    return language_id;
  }
  public void setLanguage_id(Long language_id) {
    this.language_id = language_id;
  }
}

//Language Bean
public class Language {
  private Long language_id;
  private String name;
  public Long getLanguage_id() {
    return language_id;
  }
  public void setLanguage_id(Long language_id) {
    this.language_id = language_id;
  }
  public String getName() {
    return name;
  }
  public void setName(String name) {
    this.name = name;
  }
}

Wicket HTML

<form wicket:id="form">
  <select wicket:id="language_id"/>
</form>

Jave Code that renders/compiles the Wicket Form:

public class UserForm extends Form<Users> {
  public UserForm(String id, Users user) {
    add(new DropDownChoice<Language>("language_id", Application
      .getBean(LanguageDaoImpl.class).getLanguages(),
      new ChoiceRenderer<Language>("name", "language_id")));
  }
}

The issue is that the rendering works fine, all languages are in the dropdown selection. However as soon as any User is loaded into the form, Wicket will search for a property "language" in the Long value "language_id" and throw some exception like "No get method defined for class: java.lang.Long ..." Wickets expects me to put the full Bean "Language" in the Users object. However I just have the ID in the Users Object and not the full Bean.

How can I make Wicket use simply the ID and not expect the whole object to be available? I guess I need to overwrite some method in the DropDownChoice, but I could not find any suitable.

Thanks! Sebastian


Solution

  • The problem is that you are trying to set a Language in the field language_id. You need to use an IModel to map the Language to the id. Here's some working sample code:

    public class UserForm extends Form<Users> {
        public UserForm(String id, final Users user) {
            super(id);
            final List<Language> l = new ArrayList<HomePage.Language>();
            l.add(new Language(1L, "English"));
            l.add(new Language(2L, "German"));
            add(new DropDownChoice<Language>("language_id", new IModel<Language>() {
                public Language getObject() {
                    for (Language lang : l) {
                        if (lang.getLanguage_id().equals(user.getLanguage_id())) {
                            return lang;
                        }
                    }
                    return null;
                }
    
                public void setObject(Language object) {
                    user.setLanguage_id(object.getLanguage_id());
                }
    
                public void detach() {
                }
            }, l, new ChoiceRenderer<Language>("name", "language_id")));
        }
    }
    

    I don't think it's possible to just override a method in DropDownChoice because the generic type of it is always the same as the choices list and model type. This means you can't pass a List<Language> to a DropDownChoice and expect to get a Long back without some model that knows how to convert the values.

    Edit: Another option is to use a DropDownChoice<Long> and implement a custom ChoiceRenderer which knows how to convert the Long to the name of the language. I think that's the easiest solution in this case.