Skip to content

Commit

Permalink
Integrate BeanBinder functionality into Binder (#8096)
Browse files Browse the repository at this point in the history
* Integrate BeanBinder functionality into Binder
  • Loading branch information
Legioth authored and pleku committed Jan 12, 2017
1 parent c2ad28c commit 2fd7e13
Show file tree
Hide file tree
Showing 17 changed files with 1,088 additions and 780 deletions.
2 changes: 1 addition & 1 deletion all/src/main/templates/release-notes.html
Expand Up @@ -120,7 +120,7 @@ <h2 id="incompatible">Incompatible or Behavior-altering Changes in @version@</h2
<ul><h4>New Data Binding API related changes</h4>
<li>Components using <tt>Property</tt>, <tt>Item</tt> or <tt>Container</tt> API have been reimplemented for the new API, except <tt>Tree</tt>, <tt>Table</tt>, <tt>TreeTable</tt> and <tt>Calendar</tt></li>
<li>Framework 7 versions of the components available in the v7 compatibility package for easier migration, <a href="#legacycomponents">see list of legacy components</a></li>
<li><tt>Binder</tt> is the replacement of <tt>FieldGroup</tt>, and similarly <tt>BeanBinder</tt> is the replacement of <tt>BeanFieldGroup</tt></li>
<li><tt>Binder</tt> is the replacement of <tt>FieldGroup</tt> and <tt>BeanFieldGroup</tt></li>
<li>Converters and Validators have been moved from Components to <tt>Binder</tt></li>
<li><tt>DataProvider</tt> is the replacement of <tt>Container</tt></li>
<ul>
Expand Down
1 change: 0 additions & 1 deletion documentation/components/components-grid.asciidoc
Expand Up @@ -765,7 +765,6 @@ grid.getEditor().setSaveCaption("Tallenna");
grid.getEditor().setCancelCaption("Peruuta"));
----


[[components.grid.editing.validation]]
=== Handling Validation Errors

Expand Down
21 changes: 11 additions & 10 deletions documentation/datamodel/datamodel-forms.asciidoc
Expand Up @@ -417,12 +417,13 @@ If some other part of the application is also using the same instance, then that
== Binding Beans to Forms

The business objects used in an application are in most cases implemented as Java beans or POJOs.
There is special support for that kind of business object in [classname]#BeanBinder#.
It can use reflection based on bean property names to bind values. This reduces the amount of code you have to write when binding to fields in the bean.
There is special support for that kind of business object in [classname]#Binder#.
It can use reflection based on bean property names to bind values.
This reduces the amount of code you have to write when binding to fields in the bean.

[source, java]
----
BeanBinder<Person> binder = new BeanBinder<>(Person.class);
Binder<Person> binder = new Binder<>(Person.class);
// Bind based on property name
binder.bind(nameField, "name");
Expand All @@ -436,9 +437,9 @@ binder.forField(yearOfBirthField)
----

[NOTE]
[classname]#BeanBinder# uses strings to identify the properties so it is not refactor safe.
Code using strings to identify properties will cause exceptions during runtime if the string contains a typo or if the name of the setter and getter methods have been changed without also updating the string.

[classname]#BeanBinder# will automatically use JSR 303 Bean Validation annotations from the bean class if a Bean Validation implementation is available.
Bindings created based on a property name will automatically use JSR 303 Bean Validation annotations from the bean class if a Bean Validation implementation is available.
Constraints defined for properties in the bean will work in the same way as if configured when the binding is created.

[source, java]
Expand All @@ -461,15 +462,15 @@ Constraint annotations can also be defined on the bean level instead of being de
[NOTE]
Bean level validation can only be performed once the bean has been updated. This means that this functionality can only be used together with `setBean`. You need to trigger validation manually if using `readBean` and `writeBean`.

Validation errors caused by that bean level validation might not be directly associated with any field component shown in the user interface, so [classname]#BeanBinder# cannot know where such messages should be displayed.
Validation errors caused by that bean level validation might not be directly associated with any field component shown in the user interface, so [classname]#Binder# cannot know where such messages should be displayed.

Similarly to how the [methodname]#withStatusLabel# method can be used for defining where messages for a specific binding should be showed, we can also define a [classname]#Label# that is used for showing status messages that are not related to any specific field.

[source, java]
----
Label formStatusLabel = new Label();
BeanBinder<Person> binder = new BeanBinder<>(Person.class);
Binder<Person> binder = new Binder<>(Person.class);
binder.setStatusLabel(formStatusLabel);
Expand Down Expand Up @@ -541,14 +542,14 @@ public class PersonFormDesign extends FormLayout {
}
----

Based on those files, we can create a subclass of the design that uses a [classname]#BeanBinder# to automatically connect bean properties to field instances.
Based on those files, we can create a subclass of the design that uses a [classname]#Binder# to automatically connect bean properties to field instances.
This will look at all instance fields that are of a Field type in the class and try to find a bean property with the same name.

[source, java]
----
public class PersonForm extends PersonFormDesign {
private BeanBinder<Person> binder
= new BeanBinder<>(Person.class);
private Binder<Person> binder
= new Binder<>(Person.class);
public PersonForm(Person person) {
binder.bindInstanceFields(this);
Expand Down
18 changes: 8 additions & 10 deletions server/src/main/java/com/vaadin/annotations/PropertyId.java
Expand Up @@ -20,20 +20,18 @@
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import com.vaadin.data.BeanBinder;
import com.vaadin.data.Binder;
import com.vaadin.data.HasValue;

/**
* Defines the custom property name to be bound to a {@link Field} using
* {@link Binder} or {@link BeanBinder}.
* Defines the custom property name to be bound to a {@link HasValue field
* component} using {@link Binder}.
* <p>
* The automatic data binding in Binder and BeanBinder relies on a naming
* convention by default: properties of an item are bound to similarly named
* field components in given a editor object. If you want to map a property with
* a different name (ID) to a {@link HasValue}, you can use this annotation for
* the member fields, with the name (ID) of the desired property as the
* parameter.
* The automatic data binding in Binder relies on a naming convention by
* default: properties of an item are bound to similarly named field components
* in given a editor object. If you want to map a property with a different name
* (ID) to a {@link HasValue}, you can use this annotation for the member
* fields, with the name (ID) of the desired property as the parameter.
* <p>
* In following usage example, the text field would be bound to property "foo"
* in the Entity class. <code>
Expand All @@ -49,7 +47,7 @@ class Entity {
{
Editor editor = new Editor();
BeanBinder<Entity> binder = new BeanBinder(Entity.class);
Binder&lt;Entity&gt; binder = new Binder(Entity.class);
binder.bindInstanceFields(editor);
}
</pre>
Expand Down

0 comments on commit 2fd7e13

Please sign in to comment.