Create Vaadin form using Binding form to data - forms

I'm trying to create form with Vaadin using "Binding form to data" with this class:
public class Job {
private String nom_projet;
private String svn;
private String planning1;
private String planning2;
private String goals;
}
with getters and setters.
When I try this everything works fine:
final Form form = new Form();
Job bean = new Job();
BeanItem<Job> item = new BeanItem<Job>(bean);
form.setItemDataSource(item);
I tried to add a custom field like its described in "Book of Vaadin" so I created this class:
public class MyFieldFactory implements FormFieldFactory {
private static final long serialVersionUID = 1L;
public Field createField(Item item, Object propertyId, Component uiContext) {
Select select = new Select("goals");
select.addItem("compiler:compile");
select.addItem("clean install");
select.addItem("clean");
select.addItem("package");
select.addItem("test");
select.setNewItemsAllowed(true);
return select;
}
}
But when I wanted to add this statement to MyApplication.java:
form.setFieldFactory(new MyFieldFactory());
I got "setFieldFactory" underlined and 3 choices:
() Cast argument 1 to FieldFactory
Change to setFirldFormFactory(...)
Let 'MyFieldFactory' implements 'FieldFactory'
When I click on:
Let 'MyFieldFactory' implements 'FieldFactory'
custom field does not appear in form.

the setFieldFactory method take a FieldFactory as parameter and your MyFieldFactory class implements FormFieldFactory wich is not the same.
In Vaadin javadoc, the setFieldFactory is mark as deprecated and they hint you to use setFormFieldFactory(FormFieldFactory formFieldFactory) instead.
Using this method will solve your problem.
Regards.

Related

Dynamic injection using #SpringBean in wicket

I have a form that based on collected information generates a report. I have multiple sources from which to generate reports, but the form for them is the same. I tried to implement strategy pattern using an interface implementing report generator services, but that led to wicket complaining about serialization issues of various parts of the report generator. I would like to solve this without duplicating the code contained in the form, but I have not been able to find information on dynamic injection with #SpringBean.
Here is a rough mock up of what I have
public class ReportForm extends Panel {
private IReportGenerator reportGenerator;
public ReportForm(String id, IReportGenerator reportGenerator) {
super(id);
this.reportGenerator = reportGenerator;
final Form<Void> form = new Form<Void>("form");
this.add(form);
...
form.add(new AjaxButton("button1") {
private static final long serialVersionUID = 1L;
#Override
protected void onSubmit(AjaxRequestTarget target)
{
byte[] report = reportGenerator.getReport(...);
...
}
});
}
}
If I do it this way, wicket tries to serialize the concrete instance of reportGenerator. If I annotate the reportGenerator property with #SpringBean I receive Concrete bean could not be received from the application context for class: IReportGenerator
Edit: I have reworked implementations of IRerportGenerator to be able to annotate them with #Component and now I when I use #SpringBean annotation I get More than one bean of type [IReportGenerator] found, you have to specify the name of the bean (#SpringBean(name="foo")) or (#Named("foo") if using #javax.inject classes) in order to resolve this conflict. Which is exactly what I don't want to do.
I think the behavior you're trying to achieve can be done with a slight workaround, by introducing a Spring bean that holds all IReportGenerator instances:
#Component
public class ReportGeneratorHolder {
private final List<IReportGenerator> reportGenerators;
#Autowired
public ReportGeneratorHolder(List<IReportGenerator> reportGenerators) {
this.reportGenerators = reportGenerators;
}
public Optional<IReportGenerator> getReportGenerator(Class<? extends IReportGenerator> reportGeneratorClass) {
return reportGenerators.stream()
.filter(reportGeneratorClass::isAssignableFrom)
.findAny();
}
}
You can then inject this class into your Wicket page, and pass the desired class as a constructor-parameter. Depending on your Spring configuration you might need to introduce an interface for this as well.
public class ReportForm extends Panel {
#SpringBean
private ReportGeneratorHolder reportGeneratorHolder;
public ReportForm(String id, Class<? extends IReportGenerator> reportGeneratorClass) {
super(id);
IReportGenerator reportGenerator = reportGeneratorHolder
.getReportGenerator(reportGeneratorClass)
.orElseThrow(IllegalStateException::new);
// Form logic omitted for brevity
}
}
As far as I am able to find, looking through documentation and even the source for wicket #SpringBean annotation, this isn't possible. The closest I got is with explicitly creating a proxy for a Spring bean based on class passed. As described in 13.2.4 Using proxies from the wicket-spring project chapter in Wicket in Action.
public class ReportForm extends Panel {
private IReportGenerator reportGenerator;
private Class<? extends IReportGenerator> classType;
private static ISpringContextLocator CTX_LOCATOR = new ISpringContextLocator() {
public ApplicationContext getSpringContext() {
return ((MyApplication)MyApplication.get()).getApplicationContext();
}
};
public ReportForm(String id, Class<? extends IReportGenerator> classType) {
super(id);
this.classType = classType;
final Form<Void> form = new Form<Void>("form");
this.add(form);
...
form.add(new AjaxButton("button1") {
private static final long serialVersionUID = 1L;
#Override
protected void onSubmit(AjaxRequestTarget target)
{
byte[] report = getReportGenerator().getReport(...);
...
}
});
}
private <T> T createProxy(Class<T> classType) {
return (T) LazyInitProxyFactory.createProxy(classType, new
SpringBeanLocator(classType, CTX_LOCATOR));
}
private IReportGenerator getReportGenerator() {
if (reportGenerator = null) {
reportGenerator = createProxy(classType);
}
return reportGenerator;
}
}

Wicket 7 - Select, SelectOptions and pre-set

Im using Select instead of DropDownChoice to use OPTGROUP.
Select<Role> roleInput = new Select<Role>("role", new PropertyModel<Role>(this,"selectedRole"));
The two list of Role are:
SelectOptions<Role> fedOptions = new SelectOptions<Role>("federazione",federationRoleList,new RoleRenderer());
SelectOptions<Role> eOptions = new SelectOptions<Role>("enti",eRoleList,new RoleRenderer());
Its working well when submitting and also applying a AjaxFormComponentUpdatingBehavior on roleInput, I have my PropertyModel dynamically modified.
Unfortunally I have a problem with pre-set.
I tried to set selectedRole with a specific Role but the Select always start with the first element of the first list.
DropDownChoice works perfectly pre-setting the model but not Select.
I've tried with
roleInput.setModelObject(selectedRole);
but its not working.
I thinks the problem is with this component that has to manage two or more Repeaters instead of a single list.
Any clue?
Thanks
EDIT:
Implementation of RoleRenderer
public class RoleRenderer implements IChoiceRenderer<Role>,Serializable{
private static final long serialVersionUID = 1L;
#Override
public Object getDisplayValue(Role object) {
return object.getName();
}
#Override
public String getIdValue(Role object, int index) {
return object.getId().toString();
}
#Override
public Role getObject(String id, IModel<? extends List<? extends Role>> choices) {
return getObjectFromId(id);
}
public Role getObjectFromId(String id){
return null;
};
}
NOTE: getObjectFromId require access to Manager so will be overrided outside.
Put a breakpoint at org.apache.wicket.extensions.markup.html.form.select.SelectOption#onComponentTag() and see what is returned by select.isSelected(this) for the SelectionOption that matches the default model (object).
It might be that your #equals() implementation is not correct.

GWT editor frame work is not working

I have a bean named SignUpBean and it's editor is SignUpBeanEditor and following is its Driver interface.
public interface SignUpDriver extends SimpleBeanEditorDriver<SignUpBean, SignUpEditor>{
}
Following is entry point class
public class Signup implements EntryPoint {
private SignUpDriver signUpDriver;
private SignUpEditor signUpEditor;
private SignUpBean signUpBean;
private VerticalPanel verticalPanel;
private Label signUpLbl;
private Button submitButton;
private Button cancelButton;
private RequestBuilder requestBuilder;
final SignUpConverter signUpConverter=GWT.create(SignUpConverter.class);
public void onModuleLoad() {
signUpLbl = new Label("Sign Up");
signUpDriver = GWT.create(SignUpDriver.class);
signUpBean = new SignUpBean();
signUpEditor = new SignUpEditor();
submitButton = new Button("Submit");
cancelButton = new Button("Cancel");
signUpDriver.initialize(signUpEditor);
signUpDriver.edit(signUpBean);
System.out.println(signUpBean.getUserName());
submitButton.addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
SignUpBean signUpBeanEdited=signUpDriver.flush();
}
}
}
}
I am getting only null value from signUpBeanEdited after giving value in UI. If i am initializing SignUpBean with constructor then also data is not binding to UI. My problem is I cant bind data in GWT UI using editor framework.
The fields( sub editors ) declared in SignUpEditor should be of at least DEFAULT scope. I guess you declared them as private. If so, the Editor Impl classes generated cannot access the fields to bind the data.
Changing scope to at least DEFAULT might solve your problem.

How to edit a Set<? extends EntityProxy> with GWT Editor framework?

for sake of simplicity:
public class Person
{
String name;
Set<Address> addresses;
}
public class Address
{
String city;
String street;
}
with and matching
public interface PersonProxy extends EntityProxy
{
public String getName();
public Set<AdressProxy> getAddresses();
}
and
public interface AdressProxy extends EntityProxy
{
public String getCity();
public String getStreet();
}
I got UiBuinder classes to edit AddressProxy
and it clear to me how to use ListEditor in case if I got List but data is Set in the Person class
how do I use Editor Framework to edit them?
Or may be how do I convert Set to List when it becomes PersonProxy?
I did an attempt to put a kind of adapter Editor class that would implement
LeafValueEditor<Set<AddressProxy>>
and then inside of the LeafValueEditor.setValue() move to a List and start a new driver.edit() on a separate Editor hierarchy that takes care of List editing but with now luck.
You should create a CompositeEditor<Set<AddressProxy>, AddressProxy, AddressEditor>, similar to a ListEditor but handling a Set instead of a List.
I suppose you could somehow delegate to a ListEditor though I'm really not sure.
I've done it with Points and Routes (one Route contains N Points):
Route (Composite):
#UiField
TextBox name;
#Ignore
#UiField
FlexTable listPoints;
PointsEditor pointsEditor = new PointsEditor();
....
pointsEditor.add(String id);
PointsEditor:
public class PointsEditor implements HasRequestContext<List<PointProxy>>, ValueAwareEditor<List<PointProxy>> {
List<PointProxy> points = new ArrayList<PointProxy>();
public void add(String id) {
PointProxy point = ctx.create(PointProxy.class);
point.setId(id);
points.add(point);
}
Route (server side):
#Embedded
private List<Point> points = new ArrayList<Point>();
RouteProxy
public interface RouteProxy extends EntityProxy {
abstract List<PointProxy> getPoints();
abstract void setPoints(List<PointProxy> points);
PointProxy
public interface PointProxy extends ValueProxy {
...
}

How to get access to underlying POJO from GWT Editor class

I have a HashMap inside my POJO that I am using the Editor framework in GWT to edit. While I have access to the standard member variables bound through thier getters/setters, I don't know how to access the values inside the HashMap. How do I get access to the underlying POJO that is being edited through my editor that is using the SimpleBeanEditorDriver?
My POJO:
#Entity(noClassnameStored=true)
public class ProfileConfig extends BaseEntity {
#Indexed(unique=true)
private String name;
private boolean isDefault;
private HashMap<ProfileID, ProfileInfo> profiles= new HashMap<ProfileID, ProfileInfo>();
public ProfileInfo getProfile(ProfileID id) {
return profiles.get(id);
}
public void setProfile(ProfileID id, ProfileInfo p) {
profiles.put(id, p);
}
My Editor:
public class ProfileConfigEditor extends Composite implements ManagedObjectEditor<ProfileConfig> {
private static ProfileConfigEditorUiBinder uiBinder = GWT.create(ProfileConfigEditorUiBinder.class);
interface ProfileConfigEditorUiBinder extends UiBinder<Widget, ProfileConfigEditor> {
}
private UserManager userManager;
#UiField
CellList Profiles;
#UiField
TextBox name;
#UiField
CheckBox isDefault;
So given that I have a list of valid Profile ids from the userManager, how do I go about calling the getProfile method from my POJO from within my Editor?
What you need is a ValueAwareEditor.
public class ProfileConfigEditor extends Composite implements ManagedObjectEditor<ProfileConfig>, ValueAwareEditor<ProfileConfig> {
void setValue(ProfileConfig value){
// TODO: Call ProfileConfig.getProfile()
}
void flush(){
// TODO: Call ProfileConfig.setProfile()
}
// ... Other methods here
Alternatively, if you want more of a challenge, you can look at rolling your own CompositeEditor, for example see the source code for ListEditor. In your case, you would implement a CompositeEditor<ProfileConfig, ProfileInfo, MyNewProfileInfoEditor>. You can this of this as "This editor will take a ProfileConfig object, extract one or more ProfileInfo objects and edit it with one or more MyNewProfileInfoEditor editors"