aboutsummaryrefslogtreecommitdiffstats
path: root/server/src/main/java/com
diff options
context:
space:
mode:
authorLeif Åstrand <legioth@gmail.com>2017-02-01 15:30:57 +0200
committerPekka Hyvönen <pekka@vaadin.com>2017-02-01 15:30:57 +0200
commit953e7212d84619332cba22888aa653462f9c1706 (patch)
tree08ff65e0d812dc507dcf816c5c49743256eeff23 /server/src/main/java/com
parent38b475330868d2d7b0d0b2da0a14be4040ca89ae (diff)
downloadvaadin-framework-953e7212d84619332cba22888aa653462f9c1706.tar.gz
vaadin-framework-953e7212d84619332cba22888aa653462f9c1706.zip
Make Grid add columns based on bean properties (#8392)
* Make Grid add columns based on bean properties The property set concept used for Binder is slightly generalized and used by Grid as well to support similar functionality. Fixes vaadin/framework8-issues#250
Diffstat (limited to 'server/src/main/java/com')
-rw-r--r--server/src/main/java/com/vaadin/data/BeanPropertySet.java (renamed from server/src/main/java/com/vaadin/data/BeanBinderPropertySet.java)51
-rw-r--r--server/src/main/java/com/vaadin/data/BeanValidationBinder.java2
-rw-r--r--server/src/main/java/com/vaadin/data/Binder.java77
-rw-r--r--server/src/main/java/com/vaadin/data/PropertyDefinition.java (renamed from server/src/main/java/com/vaadin/data/BinderPropertyDefinition.java)19
-rw-r--r--server/src/main/java/com/vaadin/data/PropertySet.java (renamed from server/src/main/java/com/vaadin/data/BinderPropertySet.java)9
-rw-r--r--server/src/main/java/com/vaadin/ui/Grid.java165
-rw-r--r--server/src/main/java/com/vaadin/ui/components/grid/EditorImpl.java8
7 files changed, 260 insertions, 71 deletions
diff --git a/server/src/main/java/com/vaadin/data/BeanBinderPropertySet.java b/server/src/main/java/com/vaadin/data/BeanPropertySet.java
index d5fb2b4f5d..d6ab364aff 100644
--- a/server/src/main/java/com/vaadin/data/BeanBinderPropertySet.java
+++ b/server/src/main/java/com/vaadin/data/BeanPropertySet.java
@@ -32,10 +32,11 @@ import java.util.stream.Stream;
import com.vaadin.data.util.BeanUtil;
import com.vaadin.server.Setter;
+import com.vaadin.shared.util.SharedUtil;
import com.vaadin.util.ReflectTools;
/**
- * A {@link BinderPropertySet} that uses reflection to find bean properties.
+ * A {@link PropertySet} that uses reflection to find bean properties.
*
* @author Vaadin Ltd
*
@@ -44,7 +45,7 @@ import com.vaadin.util.ReflectTools;
* @param <T>
* the type of the bean
*/
-public class BeanBinderPropertySet<T> implements BinderPropertySet<T> {
+public class BeanPropertySet<T> implements PropertySet<T> {
/**
* Serialized form of a property set. When deserialized, the property set
@@ -52,7 +53,7 @@ public class BeanBinderPropertySet<T> implements BinderPropertySet<T> {
* existing cached instance or creates a new one.
*
* @see #readResolve()
- * @see BeanBinderPropertyDefinition#writeReplace()
+ * @see BeanPropertyDefinition#writeReplace()
*/
private static class SerializedPropertySet implements Serializable {
private final Class<?> beanType;
@@ -77,7 +78,7 @@ public class BeanBinderPropertySet<T> implements BinderPropertySet<T> {
* definition is then fetched from the property set.
*
* @see #readResolve()
- * @see BeanBinderPropertySet#writeReplace()
+ * @see BeanPropertySet#writeReplace()
*/
private static class SerializedPropertyDefinition implements Serializable {
private final Class<?> beanType;
@@ -102,14 +103,13 @@ public class BeanBinderPropertySet<T> implements BinderPropertySet<T> {
}
}
- private static class BeanBinderPropertyDefinition<T, V>
- implements BinderPropertyDefinition<T, V> {
+ private static class BeanPropertyDefinition<T, V>
+ implements PropertyDefinition<T, V> {
private final PropertyDescriptor descriptor;
- private final BeanBinderPropertySet<T> propertySet;
+ private final BeanPropertySet<T> propertySet;
- public BeanBinderPropertyDefinition(
- BeanBinderPropertySet<T> propertySet,
+ public BeanPropertyDefinition(BeanPropertySet<T> propertySet,
PropertyDescriptor descriptor) {
this.propertySet = propertySet;
this.descriptor = descriptor;
@@ -156,7 +156,12 @@ public class BeanBinderPropertySet<T> implements BinderPropertySet<T> {
}
@Override
- public BeanBinderPropertySet<T> getPropertySet() {
+ public String getCaption() {
+ return SharedUtil.propertyIdToHumanFriendly(getName());
+ }
+
+ @Override
+ public BeanPropertySet<T> getPropertySet() {
return propertySet;
}
@@ -171,21 +176,21 @@ public class BeanBinderPropertySet<T> implements BinderPropertySet<T> {
}
}
- private static final ConcurrentMap<Class<?>, BeanBinderPropertySet<?>> instances = new ConcurrentHashMap<>();
+ private static final ConcurrentMap<Class<?>, BeanPropertySet<?>> instances = new ConcurrentHashMap<>();
private final Class<T> beanType;
- private final Map<String, BinderPropertyDefinition<T, ?>> definitions;
+ private final Map<String, PropertyDefinition<T, ?>> definitions;
- private BeanBinderPropertySet(Class<T> beanType) {
+ private BeanPropertySet(Class<T> beanType) {
this.beanType = beanType;
try {
definitions = BeanUtil.getBeanPropertyDescriptors(beanType).stream()
- .filter(BeanBinderPropertySet::hasNonObjectReadMethod)
- .map(descriptor -> new BeanBinderPropertyDefinition<>(this,
+ .filter(BeanPropertySet::hasNonObjectReadMethod)
+ .map(descriptor -> new BeanPropertyDefinition<>(this,
descriptor))
- .collect(Collectors.toMap(BinderPropertyDefinition::getName,
+ .collect(Collectors.toMap(PropertyDefinition::getName,
Function.identity()));
} catch (IntrospectionException e) {
throw new IllegalArgumentException(
@@ -196,28 +201,28 @@ public class BeanBinderPropertySet<T> implements BinderPropertySet<T> {
}
/**
- * Gets a {@link BeanBinderPropertySet} for the given bean type.
+ * Gets a {@link BeanPropertySet} for the given bean type.
*
* @param beanType
* the bean type to get a property set for, not <code>null</code>
- * @return the bean binder property set, not <code>null</code>
+ * @return the bean property set, not <code>null</code>
*/
@SuppressWarnings("unchecked")
- public static <T> BinderPropertySet<T> get(Class<? extends T> beanType) {
+ public static <T> PropertySet<T> get(Class<? extends T> beanType) {
Objects.requireNonNull(beanType, "Bean type cannot be null");
// Cache the reflection results
- return (BinderPropertySet<T>) instances.computeIfAbsent(beanType,
- BeanBinderPropertySet::new);
+ return (PropertySet<T>) instances.computeIfAbsent(beanType,
+ BeanPropertySet::new);
}
@Override
- public Stream<BinderPropertyDefinition<T, ?>> getProperties() {
+ public Stream<PropertyDefinition<T, ?>> getProperties() {
return definitions.values().stream();
}
@Override
- public Optional<BinderPropertyDefinition<T, ?>> getProperty(String name) {
+ public Optional<PropertyDefinition<T, ?>> getProperty(String name) {
return Optional.ofNullable(definitions.get(name));
}
diff --git a/server/src/main/java/com/vaadin/data/BeanValidationBinder.java b/server/src/main/java/com/vaadin/data/BeanValidationBinder.java
index 5e3b220ffd..34af4156a4 100644
--- a/server/src/main/java/com/vaadin/data/BeanValidationBinder.java
+++ b/server/src/main/java/com/vaadin/data/BeanValidationBinder.java
@@ -56,7 +56,7 @@ public class BeanValidationBinder<BEAN> extends Binder<BEAN> {
@Override
protected BindingBuilder<BEAN, ?> configureBinding(
BindingBuilder<BEAN, ?> binding,
- BinderPropertyDefinition<BEAN, ?> definition) {
+ PropertyDefinition<BEAN, ?> definition) {
return binding.withValidator(
new BeanValidator(beanType, definition.getName()));
}
diff --git a/server/src/main/java/com/vaadin/data/Binder.java b/server/src/main/java/com/vaadin/data/Binder.java
index f291c791b7..d36c9996fd 100644
--- a/server/src/main/java/com/vaadin/data/Binder.java
+++ b/server/src/main/java/com/vaadin/data/Binder.java
@@ -23,7 +23,6 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.LinkedHashSet;
import java.util.List;
@@ -195,7 +194,7 @@ public class Binder<BEAN> implements Serializable {
/**
* Completes this binding by connecting the field to the property with
* the given name. The getter and setter of the property are looked up
- * using a {@link BinderPropertySet}.
+ * using a {@link PropertySet}.
* <p>
* For a <code>Binder</code> created using the
* {@link Binder#Binder(Class)} constructor, introspection will be used
@@ -217,7 +216,7 @@ public class Binder<BEAN> implements Serializable {
* if the property has no accessible getter
* @throws IllegalStateException
* if the binder is not configured with an appropriate
- * {@link BinderPropertySet}
+ * {@link PropertySet}
*
* @see Binder.BindingBuilder#bind(ValueProvider, Setter)
*/
@@ -608,7 +607,7 @@ public class Binder<BEAN> implements Serializable {
"Property name cannot be null");
checkUnbound();
- BinderPropertyDefinition<BEAN, ?> definition = getBinder().propertySet
+ PropertyDefinition<BEAN, ?> definition = getBinder().propertySet
.getProperty(propertyName)
.orElseThrow(() -> new IllegalArgumentException(
"Could not resolve property name " + propertyName
@@ -627,9 +626,11 @@ public class Binder<BEAN> implements Serializable {
definition);
try {
- return ((BindingBuilder) finalBinding).bind(getter, setter);
+ Binding binding = ((BindingBuilder) finalBinding).bind(getter,
+ setter);
+ getBinder().boundProperties.put(propertyName, binding);
+ return binding;
} finally {
- getBinder().boundProperties.add(propertyName);
getBinder().incompleteMemberFieldBindings.remove(getField());
}
}
@@ -1044,12 +1045,12 @@ public class Binder<BEAN> implements Serializable {
}
}
- private final BinderPropertySet<BEAN> propertySet;
+ private final PropertySet<BEAN> propertySet;
/**
* Property names that have been used for creating a binding.
*/
- private final Set<String> boundProperties = new HashSet<>();
+ private final Map<String, Binding<BEAN, ?>> boundProperties = new HashMap<>();
private final Map<HasValue<?>, BindingBuilder<BEAN, ?>> incompleteMemberFieldBindings = new IdentityHashMap<>();
@@ -1072,16 +1073,15 @@ public class Binder<BEAN> implements Serializable {
private boolean hasChanges = false;
/**
- * Creates a binder using a custom {@link BinderPropertySet} implementation
- * for finding and resolving property names for
+ * Creates a binder using a custom {@link PropertySet} implementation for
+ * finding and resolving property names for
* {@link #bindInstanceFields(Object)}, {@link #bind(HasValue, String)} and
* {@link BindingBuilder#bind(String)}.
*
* @param propertySet
- * the binder property set implementation to use, not
- * <code>null</code>.
+ * the property set implementation to use, not <code>null</code>.
*/
- protected Binder(BinderPropertySet<BEAN> propertySet) {
+ protected Binder(PropertySet<BEAN> propertySet) {
Objects.requireNonNull(propertySet, "propertySet cannot be null");
this.propertySet = propertySet;
}
@@ -1094,7 +1094,7 @@ public class Binder<BEAN> implements Serializable {
* the bean type to use, not <code>null</code>
*/
public Binder(Class<BEAN> beanType) {
- this(BeanBinderPropertySet.get(beanType));
+ this(BeanPropertySet.get(beanType));
}
/**
@@ -1106,15 +1106,15 @@ public class Binder<BEAN> implements Serializable {
* {@link #bind(HasValue, String)} or {@link BindingBuilder#bind(String)}.
*/
public Binder() {
- this(new BinderPropertySet<BEAN>() {
+ this(new PropertySet<BEAN>() {
@Override
- public Stream<BinderPropertyDefinition<BEAN, ?>> getProperties() {
+ public Stream<PropertyDefinition<BEAN, ?>> getProperties() {
throw new IllegalStateException(
"A Binder created with the default constructor doesn't support listing properties.");
}
@Override
- public Optional<BinderPropertyDefinition<BEAN, ?>> getProperty(
+ public Optional<PropertyDefinition<BEAN, ?>> getProperty(
String name) {
throw new IllegalStateException(
"A Binder created with the default constructor doesn't support finding properties by name.");
@@ -1123,8 +1123,8 @@ public class Binder<BEAN> implements Serializable {
}
/**
- * Creates a binder using a custom {@link BinderPropertySet} implementation
- * for finding and resolving property names for
+ * Creates a binder using a custom {@link PropertySet} implementation for
+ * finding and resolving property names for
* {@link #bindInstanceFields(Object)}, {@link #bind(HasValue, String)} and
* {@link BindingBuilder#bind(String)}.
* <p>
@@ -1137,13 +1137,12 @@ public class Binder<BEAN> implements Serializable {
* @see Binder#Binder(Class)
*
* @param propertySet
- * the binder property set implementation to use, not
- * <code>null</code>.
+ * the property set implementation to use, not <code>null</code>.
* @return a new binder using the provided property set, not
* <code>null</code>
*/
public static <BEAN> Binder<BEAN> withPropertySet(
- BinderPropertySet<BEAN> propertySet) {
+ PropertySet<BEAN> propertySet) {
return new Binder<>(propertySet);
}
@@ -1272,7 +1271,7 @@ public class Binder<BEAN> implements Serializable {
/**
* Binds the given field to the property with the given name. The getter and
- * setter of the property are looked up using a {@link BinderPropertySet}.
+ * setter of the property are looked up using a {@link PropertySet}.
* <p>
* For a <code>Binder</code> created using the {@link Binder#Binder(Class)}
* constructor, introspection will be used to find a Java Bean property. If
@@ -1297,7 +1296,7 @@ public class Binder<BEAN> implements Serializable {
* if the property has no accessible getter
* @throws IllegalStateException
* if the binder is not configured with an appropriate
- * {@link BinderPropertySet}
+ * {@link PropertySet}
*
* @see #bind(HasValue, ValueProvider, Setter)
*/
@@ -1964,7 +1963,7 @@ public class Binder<BEAN> implements Serializable {
/**
* Configures the {@code binding} with the property definition
* {@code definition} before it's being bound.
- *
+ *
* @param binding
* a binding to configure
* @param definition
@@ -1973,7 +1972,7 @@ public class Binder<BEAN> implements Serializable {
*/
protected BindingBuilder<BEAN, ?> configureBinding(
BindingBuilder<BEAN, ?> binding,
- BinderPropertyDefinition<BEAN, ?> definition) {
+ PropertyDefinition<BEAN, ?> definition) {
return binding;
}
@@ -2217,7 +2216,7 @@ public class Binder<BEAN> implements Serializable {
private void handleProperty(Field field, Object objectWithMemberFields,
BiConsumer<String, Class<?>> propertyHandler) {
- Optional<BinderPropertyDefinition<BEAN, ?>> descriptor = getPropertyDescriptor(
+ Optional<PropertyDefinition<BEAN, ?>> descriptor = getPropertyDescriptor(
field);
if (!descriptor.isPresent()) {
@@ -2225,7 +2224,7 @@ public class Binder<BEAN> implements Serializable {
}
String propertyName = descriptor.get().getName();
- if (boundProperties.contains(propertyName)) {
+ if (boundProperties.containsKey(propertyName)) {
return;
}
@@ -2237,10 +2236,25 @@ public class Binder<BEAN> implements Serializable {
}
propertyHandler.accept(propertyName, descriptor.get().getType());
- boundProperties.add(propertyName);
+ assert boundProperties.containsKey(propertyName);
+ }
+
+ /**
+ * Gets the binding for a property name. Bindings are available by property
+ * name if bound using {@link #bind(HasValue, String)},
+ * {@link BindingBuilder#bind(String)} or indirectly using
+ * {@link #bindInstanceFields(Object)}.
+ *
+ * @param propertyName
+ * the property name of the binding to get
+ * @return the binding corresponding to the property name, or an empty
+ * optional if there is no binding with that property name
+ */
+ public Optional<Binding<BEAN, ?>> getBinding(String propertyName) {
+ return Optional.ofNullable(boundProperties.get(propertyName));
}
- private Optional<BinderPropertyDefinition<BEAN, ?>> getPropertyDescriptor(
+ private Optional<PropertyDefinition<BEAN, ?>> getPropertyDescriptor(
Field field) {
PropertyId propertyIdAnnotation = field.getAnnotation(PropertyId.class);
@@ -2254,8 +2268,7 @@ public class Binder<BEAN> implements Serializable {
String minifiedFieldName = minifyFieldName(propertyId);
- return propertySet.getProperties()
- .map(BinderPropertyDefinition::getName)
+ return propertySet.getProperties().map(PropertyDefinition::getName)
.filter(name -> minifyFieldName(name).equals(minifiedFieldName))
.findFirst().flatMap(propertySet::getProperty);
}
diff --git a/server/src/main/java/com/vaadin/data/BinderPropertyDefinition.java b/server/src/main/java/com/vaadin/data/PropertyDefinition.java
index b4145a8c4f..79bb2159b4 100644
--- a/server/src/main/java/com/vaadin/data/BinderPropertyDefinition.java
+++ b/server/src/main/java/com/vaadin/data/PropertyDefinition.java
@@ -21,17 +21,17 @@ import java.util.Optional;
import com.vaadin.server.Setter;
/**
- * A property from a {@link BinderPropertySet}.
+ * A property from a {@link PropertySet}.
*
* @author Vaadin Ltd
* @since
*
* @param <T>
- * the type of the binder property set
+ * the type of the property set
* @param <V>
* the property type
*/
-public interface BinderPropertyDefinition<T, V> extends Serializable {
+public interface PropertyDefinition<T, V> extends Serializable {
/**
* Gets the value provider that is used for finding the value of this
* property for a bean.
@@ -62,9 +62,16 @@ public interface BinderPropertyDefinition<T, V> extends Serializable {
public String getName();
/**
- * Gets the {@link BinderPropertySet} that this property belongs to.
+ * Gets the human readable caption to show for this property.
*
- * @return the binder property set, not <code>null</code>
+ * @return the caption to show, not <code>null</code>
*/
- public BinderPropertySet<T> getPropertySet();
+ public String getCaption();
+
+ /**
+ * Gets the {@link PropertySet} that this property belongs to.
+ *
+ * @return the property set, not <code>null</code>
+ */
+ public PropertySet<T> getPropertySet();
}
diff --git a/server/src/main/java/com/vaadin/data/BinderPropertySet.java b/server/src/main/java/com/vaadin/data/PropertySet.java
index 6252a228aa..7b557dc293 100644
--- a/server/src/main/java/com/vaadin/data/BinderPropertySet.java
+++ b/server/src/main/java/com/vaadin/data/PropertySet.java
@@ -20,7 +20,8 @@ import java.util.Optional;
import java.util.stream.Stream;
/**
- * Describes a set of properties that can be used with a {@link Binder}.
+ * Describes a set of properties that can be used for configuration based on
+ * property names instead of setter and getter callbacks.
*
* @author Vaadin Ltd
*
@@ -29,13 +30,13 @@ import java.util.stream.Stream;
* @param <T>
* the type for which the properties are defined
*/
-public interface BinderPropertySet<T> extends Serializable {
+public interface PropertySet<T> extends Serializable {
/**
* Gets all known properties as a stream.
*
* @return a stream of property names, not <code>null</code>
*/
- public Stream<BinderPropertyDefinition<T, ?>> getProperties();
+ public Stream<PropertyDefinition<T, ?>> getProperties();
/**
* Gets the definition for the named property, or an empty optional if there
@@ -46,5 +47,5 @@ public interface BinderPropertySet<T> extends Serializable {
* @return the property definition, or empty optional if property doesn't
* exist
*/
- public Optional<BinderPropertyDefinition<T, ?>> getProperty(String name);
+ public Optional<PropertyDefinition<T, ?>> getProperty(String name);
}
diff --git a/server/src/main/java/com/vaadin/ui/Grid.java b/server/src/main/java/com/vaadin/ui/Grid.java
index 4052282fdc..daf1cd1c69 100644
--- a/server/src/main/java/com/vaadin/ui/Grid.java
+++ b/server/src/main/java/com/vaadin/ui/Grid.java
@@ -41,10 +41,13 @@ import org.jsoup.nodes.Attributes;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
+import com.vaadin.data.BeanPropertySet;
import com.vaadin.data.Binder;
import com.vaadin.data.Binder.Binding;
import com.vaadin.data.HasDataProvider;
import com.vaadin.data.HasValue;
+import com.vaadin.data.PropertyDefinition;
+import com.vaadin.data.PropertySet;
import com.vaadin.data.ValueProvider;
import com.vaadin.data.provider.DataCommunicator;
import com.vaadin.data.provider.DataProvider;
@@ -1609,7 +1612,9 @@ public class Grid<T> extends AbstractListing<T> implements HasComponents,
* a setter that stores the component value in the row item
* @return this column
*
+ * @see #setEditorBinding(Binding)
* @see Grid#getEditor()
+ * @see Binder#bind(HasValue, ValueProvider, Setter)
*/
public <C extends HasValue<V> & Component> Column<T, V> setEditorComponent(
C editorComponent, Setter<T, V> setter) {
@@ -1624,6 +1629,47 @@ public class Grid<T> extends AbstractListing<T> implements HasComponents,
}
/**
+ * Sets a component to use for editing values of this columns in the
+ * editor row. This method can only be used if the column has an
+ * {@link #setId(String) id} and the {@link Grid} has been created using
+ * {@link Grid#Grid(Class)} or some other way that allows finding
+ * properties based on property names.
+ * <p>
+ * This is a shorthand for use in simple cases where no validator or
+ * converter is needed. Use {@link #setEditorBinding(Binding)} to
+ * support more complex cases.
+ * <p>
+ * <strong>Note:</strong> The same component cannot be used for multiple
+ * columns.
+ *
+ * @param editorComponent
+ * the editor component
+ * @return this column
+ *
+ * @see #setEditorBinding(Binding)
+ * @see Grid#getEditor()
+ * @see Binder#bind(HasValue, String)
+ * @see Grid#Grid(Class)
+ */
+ public <F, C extends HasValue<F> & Component> Column<T, V> setEditorComponent(
+ C editorComponent) {
+ Objects.requireNonNull(editorComponent,
+ "Editor component cannot be null");
+
+ String propertyName = getId();
+ if (propertyName == null) {
+ throw new IllegalStateException(
+ "setEditorComponent without a setter can only be used if the column has an id. "
+ + "Use another setEditorComponent(Component, Setter) or setEditorBinding(Binding) instead.");
+ }
+
+ Binding<T, F> binding = getGrid().getEditor().getBinder()
+ .bind(editorComponent, propertyName);
+
+ return setEditorBinding(binding);
+ }
+
+ /**
* Gets the grid that this column belongs to.
*
* @return the grid that this column belongs to, or <code>null</code> if
@@ -1851,10 +1897,64 @@ public class Grid<T> extends AbstractListing<T> implements HasComponents,
private Editor<T> editor;
+ private final PropertySet<T> propertySet;
+
/**
- * Constructor for the {@link Grid} component.
+ * Creates a new grid without support for creating columns based on property
+ * names. Use an alternative constructor, such as {@link Grid#Grid(Class)},
+ * to create a grid that automatically sets up columns based on the type of
+ * presented data.
+ *
+ * @see #Grid(Class)
+ * @see #withPropertySet(PropertySet)
*/
public Grid() {
+ this(new PropertySet<T>() {
+ @Override
+ public Stream<PropertyDefinition<T, ?>> getProperties() {
+ // No columns configured by default
+ return Stream.empty();
+ }
+
+ @Override
+ public Optional<PropertyDefinition<T, ?>> getProperty(String name) {
+ throw new IllegalStateException(
+ "A Grid created without a bean type class literal or a custom property set"
+ + " doesn't support finding properties by name.");
+ }
+ });
+ }
+
+ /**
+ * Creates a new grid that uses reflection based on the provided bean type
+ * to automatically set up an initial set of columns. All columns will be
+ * configured using the same {@link Object#toString()} renderer that is used
+ * by {@link #addColumn(ValueProvider)}.
+ *
+ * @param beanType
+ * the bean type to use, not <code>null</code>
+ * @see #Grid()
+ * @see #withPropertySet(PropertySet)
+ */
+ public Grid(Class<T> beanType) {
+ this(BeanPropertySet.get(beanType));
+ }
+
+ /**
+ * Creates a grid using a custom {@link PropertySet} implementation for
+ * configuring the initial columns and resolving property names for
+ * {@link #addColumn(String)} and
+ * {@link Column#setEditorComponent(HasValue)}.
+ *
+ * @see #withPropertySet(PropertySet)
+ *
+ * @param propertySet
+ * the property set implementation to use, not <code>null</code>.
+ */
+ protected Grid(PropertySet<T> propertySet) {
+ Objects.requireNonNull(propertySet, "propertySet cannot be null");
+ this.propertySet = propertySet;
+
registerRpc(new GridServerRpcImpl());
setDefaultHeaderRow(appendHeaderRow());
@@ -1882,6 +1982,33 @@ public class Grid<T> extends AbstractListing<T> implements HasComponents,
}
}
});
+
+ // Automatically add columns for all available properties
+ propertySet.getProperties().map(PropertyDefinition::getName)
+ .forEach(this::addColumn);
+ }
+
+ /**
+ * Creates a grid using a custom {@link PropertySet} implementation for
+ * creating a default set of columns and for resolving property names with
+ * {@link #addColumn(String)} and
+ * {@link Column#setEditorComponent(HasValue)}.
+ * <p>
+ * This functionality is provided as static method instead of as a public
+ * constructor in order to make it possible to use a custom property set
+ * without creating a subclass while still leaving the public constructors
+ * focused on the common use cases.
+ *
+ * @see Grid#Grid()
+ * @see Grid#Grid(Class)
+ *
+ * @param propertySet
+ * the property set implementation to use, not <code>null</code>.
+ * @return a new grid using the provided property set, not <code>null</code>
+ */
+ public static <BEAN> Grid<BEAN> withPropertySet(
+ PropertySet<BEAN> propertySet) {
+ return new Grid<>(propertySet);
}
/**
@@ -1940,6 +2067,37 @@ public class Grid<T> extends AbstractListing<T> implements HasComponents,
}
/**
+ * Adds a new column with the given property name. The property name will be
+ * used as the {@link Column#getId() column id} and the
+ * {@link Column#getCaption() column caption} will be set based on the
+ * property definition.
+ * <p>
+ * This method can only be used for a <code>Grid</code> created using
+ * {@link Grid#Grid(Class)} or {@link #withPropertySet(PropertySet)}.
+ *
+ * @param propertyName
+ * the property name of the new column, not <code>null</code>
+ * @return the newly added column, not <code>null</code>
+ */
+ public Column<T, ?> addColumn(String propertyName) {
+ Objects.requireNonNull(propertyName, "Property name cannot be null");
+
+ if (getColumn(propertyName) != null) {
+ throw new IllegalStateException(
+ "There is already a column for " + propertyName);
+ }
+
+ PropertyDefinition<T, ?> definition = propertySet
+ .getProperty(propertyName)
+ .orElseThrow(() -> new IllegalArgumentException(
+ "Could not resolve property name " + propertyName
+ + " from " + propertySet));
+
+ return addColumn(definition.getGetter()).setId(definition.getName())
+ .setCaption(definition.getCaption());
+ }
+
+ /**
* Adds a new text column to this {@link Grid} with a value provider. The
* column will use a {@link TextRenderer}. The value is converted to a
* String using {@link Object#toString()}. Sorting in memory is executed by
@@ -2070,7 +2228,8 @@ public class Grid<T> extends AbstractListing<T> implements HasComponents,
*
* @param columnId
* the identifier of the column to get
- * @return the column corresponding to the given column identifier
+ * @return the column corresponding to the given column identifier, or
+ * <code>null</code> if there is no such column
*/
public Column<T, ?> getColumn(String columnId) {
return columnIds.get(columnId);
@@ -2983,7 +3142,7 @@ public class Grid<T> extends AbstractListing<T> implements HasComponents,
* @return editor
*/
protected Editor<T> createEditor() {
- return new EditorImpl<>();
+ return new EditorImpl<>(propertySet);
}
private void addExtensionComponent(Component c) {
diff --git a/server/src/main/java/com/vaadin/ui/components/grid/EditorImpl.java b/server/src/main/java/com/vaadin/ui/components/grid/EditorImpl.java
index a001a5026a..dae7c61ee7 100644
--- a/server/src/main/java/com/vaadin/ui/components/grid/EditorImpl.java
+++ b/server/src/main/java/com/vaadin/ui/components/grid/EditorImpl.java
@@ -27,6 +27,7 @@ import com.vaadin.data.Binder;
import com.vaadin.data.Binder.Binding;
import com.vaadin.data.BinderValidationStatus;
import com.vaadin.data.BinderValidationStatusHandler;
+import com.vaadin.data.PropertySet;
import com.vaadin.shared.ui.grid.editor.EditorClientRpc;
import com.vaadin.shared.ui.grid.editor.EditorServerRpc;
import com.vaadin.shared.ui.grid.editor.EditorState;
@@ -112,8 +113,11 @@ public class EditorImpl<T> extends AbstractGridExtension<T>
/**
* Constructor for internal implementation of the Editor.
+ *
+ * @param propertySet
+ * the property set to use for configuring the default binder
*/
- public EditorImpl() {
+ public EditorImpl(PropertySet<T> propertySet) {
rpc = getRpcProxy(EditorClientRpc.class);
registerRpc(new EditorServerRpc() {
@@ -142,7 +146,7 @@ public class EditorImpl<T> extends AbstractGridExtension<T>
}
});
- setBinder(new Binder<>());
+ setBinder(Binder.withPropertySet(propertySet));
}
@Override