Permalink
Browse files

HV-878 Integrating Optional and JavaFX types

  • Loading branch information...
1 parent 9b676a6 commit 7d330d514e85044560b517eb92d1076a6b036571 @khalidq khalidq committed with gunnarmorling Jun 14, 2014
@@ -580,3 +580,74 @@ via the configuration property hibernate.validator.validated_value_handlers whic
configuring the default validator factory using the descriptor _META-INF/validation.xml_ (see
<<chapter-xml-configuration>>).
+==== Optional unwrapper
+
+Hibernate Validator provides built-in unwrapping for Java 8 +Optional+. The unwrapper is registered
+automatically for Java 8 environments, and no further configuration is required. An example of unwrapping
+an +Optional+ is shown in <<example-using-unwrapvalidatedvalue-and-optional>>.
+
+[[example-using-unwrapvalidatedvalue-and-optional]]
+.+@UnwrapValidatedValue+ with +Optional+
+====
+[source, JAVA]
+----
+@Size(min = 3)
+@UnwrapValidatedValue
+private Optional<String> name = Optional.of( "Bob" );
+----
+====
+
+[NOTE]
+====
++Optional.empty()+ is treated as +null+ during validation. This means that for constraints where +null+ is considered
+valid, +Optional.empty()+ is similarly valid.
+====
+
+==== JavaFX unwrapper
+
+Additionally, Hibernate Validator provides built-in unwrapping for JavaFX property values. The unwrapper is registered
+automatically for environments where JavaFX is present, and no further configuration is required. An
+example of some of the different ways in which +JavaFX+ property values can be unwrapped is shown
+in <<example-using-unwrapvalidatedvalue-and-javafx>>.
+
+[[example-using-unwrapvalidatedvalue-and-javafx]]
+.+@UnwrapValidatedValue+ with +JavaFX+
+====
+[source, JAVA]
+----
+@Min(value = 3)
+@UnwrapValidatedValue
+IntegerProperty integerProperty1 = new SimpleIntegerProperty( 4 );
+
+@Min(value = 3)
+@UnwrapValidatedValue
+Property<Number> integerProperty2 = new SimpleIntegerProperty( 4 );
+
+@Min(value = 3)
+@UnwrapValidatedValue
+ObservableValue<Number> integerProperty3 = new SimpleIntegerProperty( 4 );
+----
+====
+
+==== Unwrapping object graphs
+
+Unwrapping can also be used with object graphs (cascaded validation) as shown in
+ <<example-using-unwrapvalidatedvalue-and-optional-with-valid>>.
+
+[[example-using-unwrapvalidatedvalue-and-optional-with-valid]]
+.+@UnwrapValidatedValue+ with +Optional+ and +@Valid+
+====
+[source, JAVA]
+----
+@Valid
+@UnwrapValidatedValue
+private Optional<Person> person = Optional.of( new Person() );
+----
+[source, JAVA]
+----
+public class Person {
+ @Size(min =3)
+ private String name = "Bob";
+}
+----
+====
@@ -27,6 +27,7 @@
import javax.validation.MessageInterpolator;
import javax.validation.ParameterNameProvider;
import javax.validation.TraversableResolver;
+import javax.validation.ValidationException;
import javax.validation.ValidationProviderResolver;
import javax.validation.ValidatorFactory;
import javax.validation.spi.BootstrapState;
@@ -40,6 +41,7 @@
import org.hibernate.validator.internal.engine.resolver.DefaultTraversableResolver;
import org.hibernate.validator.internal.util.CollectionHelper;
import org.hibernate.validator.internal.util.Contracts;
+import org.hibernate.validator.internal.util.ReflectionHelper;
import org.hibernate.validator.internal.util.Version;
import org.hibernate.validator.internal.util.logging.Log;
import org.hibernate.validator.internal.util.logging.LoggerFactory;
@@ -49,6 +51,8 @@
import org.hibernate.validator.resourceloading.PlatformResourceBundleLocator;
import org.hibernate.validator.spi.resourceloading.ResourceBundleLocator;
import org.hibernate.validator.spi.valuehandling.ValidatedValueUnwrapper;
+import org.hibernate.validator.spi.valuehandling.wrapper.JavaFXPropertyValueUnwrapper;
+import org.hibernate.validator.spi.valuehandling.wrapper.OptionalValueUnwrapper;
import static org.hibernate.validator.internal.util.logging.Messages.MESSAGES;
@@ -103,6 +107,12 @@ public ConfigurationImpl(ValidationProvider<?> provider) {
private ConfigurationImpl() {
this.validationBootstrapParameters = new ValidationBootstrapParameters();
+ if (isJavaFxInClasspath()) {
+ this.validationBootstrapParameters.addValidatedValueHandler( new JavaFXPropertyValueUnwrapper() );
+ }
+ if (Version.getJavaRelease() >= 8) {
+ this.validationBootstrapParameters.addValidatedValueHandler( new OptionalValueUnwrapper() );
+ }
this.defaultResourceBundleLocator = new PlatformResourceBundleLocator( ResourceBundleMessageInterpolator.USER_VALIDATION_MESSAGES );
this.defaultTraversableResolver = new DefaultTraversableResolver();
this.defaultConstraintValidatorFactory = new ConstraintValidatorFactoryImpl();
@@ -411,4 +421,16 @@ private void applyXmlSettings(ValidationBootstrapParameters xmlParameters) {
}
}
}
+
+ private boolean isJavaFxInClasspath() {
+ boolean isInClasspath;
+ try {
+ ReflectionHelper.loadClass( "javafx.application.Application", this.getClass() );
+ isInClasspath = true;
+ }
+ catch ( ValidationException e ) {
+ isInClasspath = false;
+ }
+ return isInClasspath;
+ }
}
@@ -535,7 +535,7 @@ private boolean validateConstraint(ValidationContext<?> validationContext,
* @param validationContext The execution context
* @param valueContext Collected information for single validation
*/
- private void validateCascadedConstraints(ValidationContext<?> validationContext, ValueContext<?, ?> valueContext) {
+ private void validateCascadedConstraints(ValidationContext<?> validationContext, ValueContext<?, Object> valueContext) {
Validatable validatable = valueContext.getCurrentValidatable();
PathImpl originalPath = valueContext.getPropertyPath();
Class<?> originalGroup = valueContext.getCurrentGroup();
@@ -555,6 +555,15 @@ private void validateCascadedConstraints(ValidationContext<?> validationContext,
Object value = cascadable.getValue(
valueContext.getCurrentBean()
);
+
+ // Value can be wrapped (e.g. Optional<Address>). Try to unwrap it
+ ConstraintMetaData metaData = (ConstraintMetaData) cascadable;
+ if ( metaData.requiresUnwrapping() ) {
+ setValidatedValueHandlerToValueContextIfPresent( validationContext, valueContext, metaData );
+ valueContext.setCurrentValidatedValue( value );
+ value = valueContext.getCurrentValidatedValue();
+ }
+
if ( value != null ) {
Type type = value.getClass();
Iterator<?> iter = createIteratorForCascadedValue( type, value, valueContext );
@@ -938,7 +947,7 @@ private int validatePropertyForNonDefaultGroup(ValueContext<?, Object> valueCont
}
}
- ValueContext<Object[], ?> cascadingValueContext = ValueContext.getLocalExecutionContext(
+ ValueContext<Object[], Object> cascadingValueContext = ValueContext.getLocalExecutionContext(
parameterValues,
executableMetaData.getValidatableParametersMetaData(),
PathImpl.createPathForExecutable( executableMetaData )
@@ -0,0 +1,49 @@
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2014, Red Hat, Inc. and/or its affiliates, and individual contributors
+* by the @authors tag. See the copyright.txt in the distribution for a
+* full listing of individual contributors.
+*
+* 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 org.hibernate.validator.spi.valuehandling.wrapper;
+
+import java.lang.reflect.Type;
+
+import com.fasterxml.classmate.ResolvedType;
+import com.fasterxml.classmate.TypeResolver;
+import javafx.beans.value.ObservableValue;
+
+import org.hibernate.validator.spi.valuehandling.ValidatedValueUnwrapper;
+
+/**
+ * Unwraps a JavaFX {@code ObservableValue} and returns the wrapped value and type.
+ *
+ * @author Khalid Alqinyah
+ */
+public class JavaFXPropertyValueUnwrapper extends ValidatedValueUnwrapper<ObservableValue<?>> {
+
+ private final TypeResolver typeResolver = new TypeResolver();
+
+ @Override
+ public Object handleValidatedValue(ObservableValue<?> value) {
+ if ( value != null ) {
+ return value.getValue();
+ }
+ return value;
+ }
+
+ @Override
+ public Type getValidatedValueType(Type valueType) {
+ ResolvedType resolvedType = typeResolver.resolve( valueType );
+ return resolvedType.typeParametersFor( ObservableValue.class ).get( 0 ).getErasedType();
+ }
+}
@@ -0,0 +1,51 @@
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2014, Red Hat, Inc. and/or its affiliates, and individual contributors
+* by the @authors tag. See the copyright.txt in the distribution for a
+* full listing of individual contributors.
+*
+* 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 org.hibernate.validator.spi.valuehandling.wrapper;
+
+import java.lang.reflect.Type;
+import java.util.Optional;
+
+import com.fasterxml.classmate.ResolvedType;
+import com.fasterxml.classmate.TypeResolver;
+
+import org.hibernate.validator.spi.valuehandling.ValidatedValueUnwrapper;
+
+/**
+ * Unwraps an {@code Optional} and returns the wrapped value and type. Empty {@code Optional} value is returned as
+ * {@code null}.
+ *
+ * @author Khalid Alqinyah
+ */
+public class OptionalValueUnwrapper extends ValidatedValueUnwrapper<Optional<?>> {
+
+ private final TypeResolver typeResolver = new TypeResolver();
+
+ @Override
+ public Object handleValidatedValue(Optional<?> value) {
+ if ( value.isPresent() ) {
+ return value.get();
+ }
+
+ return null;
+ }
+
+ @Override
+ public Type getValidatedValueType(Type valueType) {
+ ResolvedType resolvedType = typeResolver.resolve( valueType );
+ return resolvedType.typeParametersFor( Optional.class ).get( 0 ).getErasedType();
+ }
+}
@@ -0,0 +1,21 @@
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2014, Red Hat, Inc. and/or its affiliates, and individual contributors
+* by the @authors tag. See the copyright.txt in the distribution for a
+* full listing of individual contributors.
+*
+* 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.
+*/
+
+/**
+ * Implementations for {@link org.hibernate.validator.spi.valuehandling.ValidatedValueUnwrapper}
+ */
+package org.hibernate.validator.spi.valuehandling.wrapper;
Oops, something went wrong. Retry.

0 comments on commit 7d330d5

Please sign in to comment.