Fixes #8253tags/8.0.0.beta2
import java.util.stream.Collectors; | import java.util.stream.Collectors; | ||||
import java.util.stream.Stream; | import java.util.stream.Stream; | ||||
import com.vaadin.data.Binder.BindingBuilder; | |||||
import com.vaadin.data.util.BeanUtil; | import com.vaadin.data.util.BeanUtil; | ||||
import com.vaadin.data.validator.BeanValidator; | |||||
import com.vaadin.server.Setter; | import com.vaadin.server.Setter; | ||||
import com.vaadin.util.ReflectTools; | import com.vaadin.util.ReflectTools; | ||||
.convertPrimitiveType(descriptor.getPropertyType()); | .convertPrimitiveType(descriptor.getPropertyType()); | ||||
} | } | ||||
@Override | |||||
public BindingBuilder<T, V> beforeBind( | |||||
BindingBuilder<T, V> originalBuilder) { | |||||
if (BeanUtil.checkBeanValidationAvailable()) { | |||||
return originalBuilder.withValidator(new BeanValidator( | |||||
getPropertySet().beanType, descriptor.getName())); | |||||
} else { | |||||
return originalBuilder; | |||||
} | |||||
} | |||||
@Override | @Override | ||||
public String getName() { | public String getName() { | ||||
return descriptor.getName(); | return descriptor.getName(); |
/* | |||||
* Copyright 2000-2016 Vaadin Ltd. | |||||
* | |||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not | |||||
* use this file except in compliance with the License. You may obtain a copy of | |||||
* the License at | |||||
* | |||||
* http://www.apache.org/licenses/LICENSE-2.0 | |||||
* | |||||
* Unless required by applicable law or agreed to in writing, software | |||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | |||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | |||||
* License for the specific language governing permissions and limitations under | |||||
* the License. | |||||
*/ | |||||
package com.vaadin.data; | |||||
import com.vaadin.data.util.BeanUtil; | |||||
import com.vaadin.data.validator.BeanValidator; | |||||
/** | |||||
* @author Vaadin Ltd | |||||
* @see Binder | |||||
* @see HasValue | |||||
* | |||||
* @since 8.0 | |||||
*/ | |||||
public class BeanValidationBinder<BEAN> extends Binder<BEAN> { | |||||
private final Class<BEAN> beanType; | |||||
/** | |||||
* Creates a new binder that uses reflection based on the provided bean type | |||||
* to resolve bean properties. It assumes that JSR-303 bean validation | |||||
* implementation is present on the classpath. If there is no such | |||||
* implementation available then {@link Binder} class should be used instead | |||||
* (this constructor will throw an exception). Otherwise | |||||
* {@link BeanValidator} is added to each binding that is defined using a | |||||
* property name. | |||||
* | |||||
* @param beanType | |||||
* the bean type to use, not <code>null</code> | |||||
*/ | |||||
public BeanValidationBinder(Class<BEAN> beanType) { | |||||
super(beanType); | |||||
if (!BeanUtil.checkBeanValidationAvailable()) { | |||||
throw new IllegalStateException( | |||||
BeanValidationBinder.class.getSimpleName() | |||||
+ " cannot be used because a JSR-303 Bean Validation " | |||||
+ "implementation not found on the classpath. Use " | |||||
+ Binder.class.getSimpleName() + " instead"); | |||||
} | |||||
this.beanType = beanType; | |||||
} | |||||
@Override | |||||
protected BindingBuilder<BEAN, ?> configureBinding( | |||||
BindingBuilder<BEAN, ?> binding, | |||||
BinderPropertyDefinition<BEAN, ?> definition) { | |||||
return binding.withValidator( | |||||
new BeanValidator(beanType, definition.getName())); | |||||
} | |||||
} |
// Setter ignores value | // Setter ignores value | ||||
}); | }); | ||||
BindingBuilder finalBinding = withConverter( | |||||
BindingBuilder<BEAN, ?> finalBinding = withConverter( | |||||
createConverter(definition.getType()), false); | createConverter(definition.getType()), false); | ||||
finalBinding = definition.beforeBind(finalBinding); | |||||
finalBinding = getBinder().configureBinding(finalBinding, | |||||
definition); | |||||
try { | try { | ||||
return finalBinding.bind(getter, setter); | |||||
return ((BindingBuilder) finalBinding).bind(getter, setter); | |||||
} finally { | } finally { | ||||
getBinder().boundProperties.add(propertyName); | getBinder().boundProperties.add(propertyName); | ||||
getBinder().incompleteMemberFieldBindings.remove(getField()); | getBinder().incompleteMemberFieldBindings.remove(getField()); | ||||
/** | /** | ||||
* Creates a new binder that uses reflection based on the provided bean type | * Creates a new binder that uses reflection based on the provided bean type | ||||
* to resolve bean properties. If a JSR-303 bean validation implementation | |||||
* is present on the classpath, a {@link BeanValidator} is added to each | |||||
* binding that is defined using a property name. | |||||
* to resolve bean properties. | |||||
* | * | ||||
* @param beanType | * @param beanType | ||||
* the bean type to use, not <code>null</code> | * the bean type to use, not <code>null</code> | ||||
return eventRouter; | return eventRouter; | ||||
} | } | ||||
/** | |||||
* Configures the {@code binding} with the property definition | |||||
* {@code definition} before it's being bound. | |||||
* | |||||
* @param binding | |||||
* a binding to configure | |||||
* @param definition | |||||
* a property definition information | |||||
* @return the new configured binding | |||||
*/ | |||||
protected BindingBuilder<BEAN, ?> configureBinding( | |||||
BindingBuilder<BEAN, ?> binding, | |||||
BinderPropertyDefinition<BEAN, ?> definition) { | |||||
return binding; | |||||
} | |||||
private void doRemoveBean(boolean fireStatusEvent) { | private void doRemoveBean(boolean fireStatusEvent) { | ||||
setHasChanges(false); | setHasChanges(false); | ||||
if (bean != null) { | if (bean != null) { |
import java.io.Serializable; | import java.io.Serializable; | ||||
import java.util.Optional; | import java.util.Optional; | ||||
import com.vaadin.data.Binder.BindingBuilder; | |||||
import com.vaadin.server.Setter; | import com.vaadin.server.Setter; | ||||
/** | /** | ||||
*/ | */ | ||||
public Class<V> getType(); | public Class<V> getType(); | ||||
/** | |||||
* Hook for modifying a binding before it is being bound to this property. | |||||
* This method can return the provided {@link BindingBuilder} as-is if no | |||||
* modifications are necessary. | |||||
* | |||||
* @param originalBuilder | |||||
* the original binding builder that is being bound, not | |||||
* <code>null</code> | |||||
* @return the binding builder to use for creating the binding, not | |||||
* <code>null</code> | |||||
*/ | |||||
public BindingBuilder<T, V> beforeBind( | |||||
BindingBuilder<T, V> originalBuilder); | |||||
/** | /** | ||||
* Gets the name of this property. | * Gets the name of this property. | ||||
* | * |
if (!BeanUtil.checkBeanValidationAvailable()) { | if (!BeanUtil.checkBeanValidationAvailable()) { | ||||
throw new IllegalStateException("Cannot create a " | throw new IllegalStateException("Cannot create a " | ||||
+ BeanValidator.class.getSimpleName() | + BeanValidator.class.getSimpleName() | ||||
+ ": a JSR-303 Bean Validation implementation not found on theclasspath"); | |||||
+ ": a JSR-303 Bean Validation implementation not found on the classpath"); | |||||
} | } | ||||
Objects.requireNonNull(beanType, "bean class cannot be null"); | Objects.requireNonNull(beanType, "bean class cannot be null"); | ||||
Objects.requireNonNull(propertyName, "property name cannot be null"); | Objects.requireNonNull(propertyName, "property name cannot be null"); |
@Before | @Before | ||||
public void setUp() { | public void setUp() { | ||||
binder = new Binder<>(BeanToValidate.class); | |||||
binder = new BeanValidationBinder<>(BeanToValidate.class); | |||||
item = new BeanToValidate(); | item = new BeanToValidate(); | ||||
item.setFirstname("Johannes"); | item.setFirstname("Johannes"); | ||||
item.setAge(32); | item.setAge(32); |
import org.junit.Assert; | import org.junit.Assert; | ||||
import org.junit.Test; | import org.junit.Test; | ||||
import com.vaadin.data.Binder.BindingBuilder; | |||||
import com.vaadin.server.Setter; | import com.vaadin.server.Setter; | ||||
import com.vaadin.ui.TextField; | import com.vaadin.ui.TextField; | ||||
return String.class; | return String.class; | ||||
} | } | ||||
@Override | |||||
public BindingBuilder<Map<String, String>, String> beforeBind( | |||||
BindingBuilder<Map<String, String>, String> originalBuilder) { | |||||
return originalBuilder; | |||||
} | |||||
@Override | @Override | ||||
public String getName() { | public String getName() { | ||||
return name; | return name; |
// BeanToValidate : @Size(min = 3, max = 16) for the firstName | // BeanToValidate : @Size(min = 3, max = 16) for the firstName | ||||
nameField.setValue("a"); | nameField.setValue("a"); | ||||
assertEquals(nameField.getValue(), item.getFirstname()); | assertEquals(nameField.getValue(), item.getFirstname()); | ||||
try { | |||||
BeanValidationBinder<BeanToValidate> beanValidationBinder = new BeanValidationBinder<>( | |||||
BeanToValidate.class); | |||||
Assert.fail(); | |||||
} catch (IllegalStateException ignore) { | |||||
// an exception has to be thrown | |||||
} | |||||
} | } | ||||
} | } |