summaryrefslogtreecommitdiffstats
path: root/documentation/jpacontainer/jpacontainer-fieldfactory.asciidoc
blob: dd014d746ede89d998bc6222475e8e3e7999d58d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
---
title: Automatic Form Generation
order: 8
layout: page
---

[[jpacontainer.fieldfactory]]
= Automatic Form Generation

The JPAContainer [classname]#FieldFactory# is an implementation of the
[interfacename]#FormFieldFactory# and [interfacename]#TableFieldFactory#
interfaces that can generate fields based on JPA annotations in a POJO. It goes
further than the [classname]#DefaultFieldFactory#, which only creates simple
fields for the basic data types. This way, you can easily create forms to input
entities or enable editing in tables.

The generated defaults are as follows:

[options="header"]
|===============
|Annotation|Class Mapping
|[literal]#++@ManyToOne++#|[classname]#NativeSelect#
|[literal]#++@OneToOne++#, [literal]#++@Embedded++#|Nested [classname]#Form#
|[literal]#++@OneToMany++#, [literal]#++@ElementCollection++#|[classname]#MasterDetailEditor# (see below)
|[literal]#++@ManyToMany++#|Selectable [classname]#Table#

|===============

The field factory is recursive, so that you can edit a complex object tree with one form.

[[jpacontainer.fieldfactory.configuring]]
== Configuring the Field Factory

The [classname]#FieldFactory# is highly configurable with various configuration settings and by extending.
// You need to make the configuration before ...

The [methodname]#setMultiSelectType()# and [methodname]#setSingleSelectType()#
allow you to specify a selection component that is used instead of the default
for a field with [literal]#++@ManyToMany++# and [literal]#++@ManyToOne++#
annotation, respectively. The first parameter is the class type of the field,
and the second parameter is the class type of a selection component. It must be
a sub-class of [classname]#AbstractSelect#.

The [methodname]#setVisibleProperties()# controls which properties (fields) are
visible in generated forms, subforms, and tables. The first paramater is the
class type for which the setting should be made, followed by the IDs of the
visible properties.

The configuration should be done before binding the form to a data source as
that is when the field generation is done.

Further configuration must be done by extending the many protected methods.
Please see the API documentation for the complete list.


[[jpacontainer.fieldfactory.using]]
== Using the Field Factory

The most basic use case for the JPAContainer [classname]#FieldFactory# is with a
[classname]#Form# bound to a container item:


----
// Have a persistent container
final JPAContainer<Country> countries =
    JPAContainerFactory.make(Country.class, "book-examples");

// For selecting an item to edit
final ComboBox countrySelect =
    new ComboBox("Select a Country", countries);
countrySelect.setItemCaptionMode(Select.ITEM_CAPTION_MODE_PROPERTY);
countrySelect.setItemCaptionPropertyId("name");

// Country Editor
final Form  countryForm  = new Form();
countryForm.setCaption("Country Editor");
countryForm.addStyleName("bordered"); // Custom style
countryForm.setWidth("420px");
countryForm.setBuffered(true);
countryForm.setEnabled(false);

// When an item is selected from the list...
countrySelect.addValueChangeListener(new ValueChangeListener(){
    @Override
    public void valueChange(ValueChangeEvent event) {
        // Get the item to edit in the form
        Item countryItem =
            countries.getItem(event.getProperty().getValue());

        // Use a JPAContainer field factory
        //  - no configuration is needed here
        final FieldFactory fieldFactory = new FieldFactory();
        countryForm.setFormFieldFactory(fieldFactory);

        // Edit the item in the form
        countryForm.setItemDataSource(countryItem);
        countryForm.setEnabled(true);

        // Handle saves on the form
        final Button save = new Button("Save");
        countryForm.getFooter().removeAllComponents();
        countryForm.getFooter().addComponent(save);
        save.addClickListener(new ClickListener() {
            @Override
            public void buttonClick(ClickEvent event) {
                try {
                    countryForm.commit();
                    countryForm.setEnabled(false);
                } catch (InvalidValueException e) {
                }
            }
        });
    }
});
countrySelect.setImmediate(true);
countrySelect.setNullSelectionAllowed(false);
----
See the http://demo.vaadin.com/book-examples-vaadin7/book#jpacontainer.fieldfactory.formonetoone[on-line example, window="_blank"].

This would create a form shown in <<figure.jpacontainer.fieldfactory.using>>.

[[figure.jpacontainer.fieldfactory.using]]
.Using FieldFactory with One-to-Many Relationship
image::img/fieldfactory-form.png[]

If you use Hibernate, you also need to pass an
[classname]#EntityManagerPerRequestHelper#, either for the constructor or with
[methodname]#setEntityManagerPerRequestHelper()#
ifdef::web[]
, as described in
<<dummy/../../../framework/jpacontainer/jpacontainer-hibernate#jpacontainer.hibernate.em-per-request,"The
EntityManager-Per-Request
pattern">>
endif::web[]
.


[[jpacontainer.fieldfactory.masterdetaileditor]]
== Master-Detail Editor

The [classname]#MasterDetailEditor# is a field component that allows editing an
item property that has one-to-many relationship. The item can be a row in a
table or bound to a form. It displays the referenced collection as an editable
[classname]#Table# and allows adding and removing items in it.

You can use the [classname]#MasterDetailEditor# manually, or perhaps more
commonly use a JPAContainer [classname]#FieldFactory# to create it
automatically. As shown in the example in
<<figure.jpacontainer.fieldfactory.using>>, the factory creates a
[classname]#MasterDetailEditor# for all properties with a
[literal]#++@OneToMany++# or an [literal]#++@ElementCollection++# annotation.