com.vaadin.v7.data.fieldgroup.BeanFieldGroup Maven / Gradle / Ivy
Show all versions of vaadin-compatibility-server Show documentation
/*
* Copyright (C) 2000-2024 Vaadin Ltd
*
* This program is available under Vaadin Commercial License and Service Terms.
*
* See for the full
* license.
*/
package com.vaadin.v7.data.fieldgroup;
import java.beans.IntrospectionException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import com.vaadin.data.BeanValidationBinder;
import com.vaadin.data.Binder;
import com.vaadin.data.util.BeanUtil;
import com.vaadin.v7.data.Item;
import com.vaadin.v7.data.util.BeanItem;
import com.vaadin.v7.data.validator.BeanValidator;
import com.vaadin.v7.ui.Field;
/**
*
* @deprecated As of 8.0, replaced by {@link Binder} and
* {@link BeanValidationBinder}
*/
@Deprecated
public class BeanFieldGroup extends FieldGroup {
private final Class beanType;
private static Boolean beanValidationImplementationAvailable = null;
private final Map, BeanValidator> defaultValidators;
public BeanFieldGroup(Class beanType) {
this.beanType = beanType;
this.defaultValidators = new HashMap, BeanValidator>();
}
@Override
protected Class> getPropertyType(Object propertyId) {
if (getItemDataSource() != null) {
return super.getPropertyType(propertyId);
} else {
// Data source not set so we need to figure out the type manually
/*
* toString should never really be needed as propertyId should be of
* form "fieldName" or "fieldName.subField[.subField2]" but the
* method declaration comes from parent.
*/
try {
Class> type = BeanUtil.getPropertyType(beanType,
propertyId.toString());
if (type == null) {
throw new BindException(
"Cannot determine type of propertyId '" + propertyId
+ "'. The propertyId was not found in "
+ beanType.getName());
}
return type;
} catch (IntrospectionException e) {
throw new BindException("Cannot determine type of propertyId '"
+ propertyId + "'. Unable to introspect " + beanType,
e);
}
}
}
@Override
protected Object findPropertyId(java.lang.reflect.Field memberField) {
String fieldName = memberField.getName();
Item dataSource = getItemDataSource();
if (dataSource != null
&& dataSource.getItemProperty(fieldName) != null) {
return fieldName;
} else {
String minifiedFieldName = minifyFieldName(fieldName);
try {
return getFieldName(beanType, minifiedFieldName);
} catch (SecurityException e) {
} catch (NoSuchFieldException e) {
}
}
return null;
}
private static String getFieldName(Class> cls, String propertyId)
throws SecurityException, NoSuchFieldException {
for (java.lang.reflect.Field field1 : cls.getDeclaredFields()) {
if (propertyId.equals(minifyFieldName(field1.getName()))) {
return field1.getName();
}
}
// Try super classes until we reach Object
Class> superClass = cls.getSuperclass();
if (superClass != null && superClass != Object.class) {
return getFieldName(superClass, propertyId);
} else {
throw new NoSuchFieldException();
}
}
/**
* Helper method for setting the data source directly using a bean. This
* method wraps the bean in a {@link BeanItem} and calls
* {@link #setItemDataSource(Item)}.
*
* For null values, a null item is passed to
* {@link #setItemDataSource(Item)} to be properly clear fields.
*
* @param bean
* The bean to use as data source.
*/
public void setItemDataSource(T bean) {
if (bean == null) {
setItemDataSource((Item) null);
} else {
setItemDataSource(new BeanItem(bean, beanType));
}
}
@Override
public void setItemDataSource(Item item) {
if (item == null || (item instanceof BeanItem)) {
super.setItemDataSource(item);
} else {
throw new RuntimeException(getClass().getSimpleName()
+ " only supports BeanItems as item data source");
}
}
@Override
public BeanItem getItemDataSource() {
return (BeanItem) super.getItemDataSource();
}
private void ensureNestedPropertyAdded(Object propertyId) {
if (getItemDataSource() != null) {
// The data source is set so the property must be found in the item.
// If it is not we try to add it.
try {
getItemProperty(propertyId);
} catch (BindException e) {
// Not found, try to add a nested property;
// BeanItem property ids are always strings so this is safe
getItemDataSource().addNestedProperty((String) propertyId);
}
}
}
@Override
public void bind(Field field, Object propertyId) {
ensureNestedPropertyAdded(propertyId);
super.bind(field, propertyId);
}
@Override
public T buildAndBind(String caption, Object propertyId,
Class fieldType) throws BindException {
ensureNestedPropertyAdded(propertyId);
return super.buildAndBind(caption, propertyId, fieldType);
}
@Override
public void unbind(Field> field) throws BindException {
super.unbind(field);
BeanValidator removed = defaultValidators.remove(field);
if (removed != null) {
field.removeValidator(removed);
}
}
@Override
protected void configureField(Field> field) {
super.configureField(field);
// Add Bean validators if there are annotations
if (isBeanValidationImplementationAvailable()
&& !defaultValidators.containsKey(field)) {
BeanValidator validator = new BeanValidator(beanType,
getPropertyId(field).toString());
field.addValidator(validator);
if (field.getLocale() != null) {
validator.setLocale(field.getLocale());
}
defaultValidators.put(field, validator);
}
}
/**
* Checks whether a bean validation implementation (e.g. Hibernate Validator
* or Apache Bean Validation) is available.
*
* TODO move this method to some more generic location
*
* @return true if a JSR-303 bean validation implementation is available
*/
protected static boolean isBeanValidationImplementationAvailable() {
if (beanValidationImplementationAvailable != null) {
return beanValidationImplementationAvailable;
}
try {
Class> validationClass = Class
.forName("javax.validation.Validation");
Method buildFactoryMethod = validationClass
.getMethod("buildDefaultValidatorFactory");
Object factory = buildFactoryMethod.invoke(null);
beanValidationImplementationAvailable = (factory != null);
} catch (Exception e) {
// no bean validation implementation available
beanValidationImplementationAvailable = false;
}
return beanValidationImplementationAvailable;
}
/**
* Convenience method to bind Fields from a given "field container" to a
* given bean with buffering disabled.
*
* The returned {@link BeanFieldGroup} can be used for further
* configuration.
*
* @see #bindFieldsBuffered(Object, Object)
* @see #bindMemberFields(Object)
* @since 7.2
* @param bean
* the bean to be bound
* @param objectWithMemberFields
* the class that contains {@link Field}s for bean properties
* @return the bean field group used to make binding
*/
public static BeanFieldGroup bindFieldsUnbuffered(T bean,
Object objectWithMemberFields) {
return createAndBindFields(bean, objectWithMemberFields, false);
}
/**
* Convenience method to bind Fields from a given "field container" to a
* given bean with buffering enabled.
*
* The returned {@link BeanFieldGroup} can be used for further
* configuration.
*
* @see #bindFieldsUnbuffered(Object, Object)
* @see #bindMemberFields(Object)
* @since 7.2
* @param bean
* the bean to be bound
* @param objectWithMemberFields
* the class that contains {@link Field}s for bean properties
* @return the bean field group used to make binding
*/
public static BeanFieldGroup bindFieldsBuffered(T bean,
Object objectWithMemberFields) {
return createAndBindFields(bean, objectWithMemberFields, true);
}
private static BeanFieldGroup createAndBindFields(T bean,
Object objectWithMemberFields, boolean buffered) {
@SuppressWarnings("unchecked")
BeanFieldGroup beanFieldGroup = new BeanFieldGroup(
(Class) bean.getClass());
beanFieldGroup.setItemDataSource(bean);
beanFieldGroup.setBuffered(buffered);
beanFieldGroup.bindMemberFields(objectWithMemberFields);
return beanFieldGroup;
}
}