You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by ja...@apache.org on 2010/03/24 20:37:30 UTC
svn commit: r927162 - in
/myfaces/core/trunk/api/src/main/java/javax/faces/validator:
BeanValidator.java _BeanValidatorUELUtils.java
Author: jakobk
Date: Wed Mar 24 19:37:30 2010
New Revision: 927162
URL: http://svn.apache.org/viewvc?rev=927162&view=rev
Log:
MYFACES-2621 BeanValidation does not work with Unified EL 2.2
Modified:
myfaces/core/trunk/api/src/main/java/javax/faces/validator/BeanValidator.java (contents, props changed)
myfaces/core/trunk/api/src/main/java/javax/faces/validator/_BeanValidatorUELUtils.java (contents, props changed)
Modified: myfaces/core/trunk/api/src/main/java/javax/faces/validator/BeanValidator.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/api/src/main/java/javax/faces/validator/BeanValidator.java?rev=927162&r1=927161&r2=927162&view=diff
==============================================================================
--- myfaces/core/trunk/api/src/main/java/javax/faces/validator/BeanValidator.java (original)
+++ myfaces/core/trunk/api/src/main/java/javax/faces/validator/BeanValidator.java Wed Mar 24 19:37:30 2010
@@ -1,573 +1,585 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you 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 javax.faces.validator;
-
-import java.beans.FeatureDescriptor;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Locale;
-import java.util.Set;
-
-import javax.el.ELContext;
-import javax.el.ELResolver;
-import javax.el.FunctionMapper;
-import javax.el.ValueExpression;
-import javax.el.VariableMapper;
-import javax.faces.FacesException;
-import javax.faces.application.FacesMessage;
-import javax.faces.component.PartialStateHolder;
-import javax.faces.component.UIComponent;
-import javax.faces.context.FacesContext;
-import javax.servlet.ServletContext;
-import javax.validation.ConstraintViolation;
-import javax.validation.MessageInterpolator;
-import javax.validation.Validation;
-import javax.validation.ValidatorFactory;
-import javax.validation.groups.Default;
-import javax.validation.metadata.BeanDescriptor;
-
-import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFJspProperty;
-import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFProperty;
-import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFValidator;
-import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFWebConfigParam;
-
-/**
- * <p>
- * <strong>BeanValidator</strong> is a {@link javax.faces.validator.Validator}
- * that doesn't do any validation itself, but delegates validation logic to
- * Bean Validation.
- * </p>
- *
- * @author Jan-Kees van Andel
- * @since 2.0
- */
-@JSFValidator(
- name="f:validateBean",
- bodyContent="empty")
-@JSFJspProperty(
- name = "binding",
- returnType = "javax.faces.validator.BeanValidator",
- longDesc = "A ValueExpression that evaluates to a BeanValidator.")
-@FacesValidator(value = BeanValidator.VALIDATOR_ID, isDefault = true)
-public class BeanValidator implements Validator, PartialStateHolder
-{
-
-// private static final Logger log = Logger.getLogger(BeanValidator.class.getName());
-
- /**
- * Converter ID, as defined by the JSF 2.0 specification.
- */
- public static final String VALIDATOR_ID = "javax.faces.Bean";
-
- /**
- * The message ID for this Validator in the message bundles.
- */
- public static final String MESSAGE_ID = "javax.faces.validator.BeanValidator.MESSAGE";
-
- /**
- * If this init parameter is present, no Bean Validators should be added to an UIInput by default.
- * Explicitly adding a BeanValidator to an UIInput is possible though.
- */
- @JSFWebConfigParam(defaultValue="true", expectedValues="true, false", since="2.0")
- public static final String DISABLE_DEFAULT_BEAN_VALIDATOR_PARAM_NAME = "javax.faces.validator.DISABLE_DEFAULT_BEAN_VALIDATOR";
-
- /**
- * The key in the ServletContext where the Bean Validation Factory can be found.
- * In a managed Java EE 6 environment, the container initializes the ValidatorFactory
- * and stores it in the ServletContext under this key.
- * If not present, the manually instantiated ValidatorFactory is stored in the ServletContext
- * under this key for caching purposes.
- */
- public static final String VALIDATOR_FACTORY_KEY = "javax.faces.validator.beanValidator.ValidatorFactory";
-
- /**
- * This is used as a separator so multiple validation groups can be specified in one String.
- */
- public static final String VALIDATION_GROUPS_DELIMITER = ",";
-
- /**
- * This regular expression is used to match for empty validation groups.
- * Currently, a string containing only whitespace is classified as empty.
- */
- public static final String EMPTY_VALIDATION_GROUPS_PATTERN = "^[\\W,]*$";
-
- private String validationGroups;
-
- private Class<?>[] validationGroupsArray;
-
- private boolean isTransient = false;
-
- private boolean _initialStateMarked = false;
-
- /**
- * {@inheritDoc}
- */
- public void validate(final FacesContext context, final UIComponent component, final Object value) throws ValidatorException
- {
- if (context == null) throw new NullPointerException("context");
- if (component == null) throw new NullPointerException("component");
-
- // Obtain a reference to the to-be-validated object and the property name.
- final ValueReferenceWrapper reference = getValueReference(component, context);
- if (reference == null)
- {
- return;
- }
- final Object base = reference.getBase();
- if (base == null)
- {
- return;
- }
- final Class<?> valueBaseClass = base.getClass();
- final String valueProperty = (String) reference.getProperty();
- if (valueBaseClass == null || valueProperty == null)
- {
- return;
- }
-
- // Initialize Bean Validation.
- final ValidatorFactory validatorFactory = createValidatorFactory(context);
- final javax.validation.Validator validator = createValidator(validatorFactory);
- final BeanDescriptor beanDescriptor = validator.getConstraintsForClass(valueBaseClass);
- if (!beanDescriptor.isBeanConstrained())
- {
- return;
- }
-
- // Note that validationGroupsArray was initialized when createValidator was called
- final Class[] validationGroupsArray = this.validationGroupsArray;
-
- // Delegate to Bean Validation.
- final Set constraintViolations = validator.validateValue(valueBaseClass, valueProperty, value, validationGroupsArray);
- if (!constraintViolations.isEmpty())
- {
- final Set<FacesMessage> messages = new LinkedHashSet<FacesMessage>(constraintViolations.size());
- for (Object violation: constraintViolations)
- {
- final ConstraintViolation constraintViolation = (ConstraintViolation) violation;
- final String message = constraintViolation.getMessage();
- final String[] args = new String[]{ message, _MessageUtils.getLabel(context, component) };
- final FacesMessage msg = _MessageUtils.getErrorMessage(context, MESSAGE_ID, args);
- messages.add(msg);
- }
- throw new ValidatorException(messages);
- }
- }
-
- private javax.validation.Validator createValidator(final ValidatorFactory validatorFactory)
- {
- // Set default validation group when setValidationGroups has not been called.
- // The null check is there to prevent it from happening twice.
- if (validationGroupsArray == null)
- {
- postSetValidationGroups();
- }
-
- return validatorFactory //
- .usingContext() //
- .messageInterpolator(FacesMessageInterpolatorHolder.get(validatorFactory)) //
- .getValidator();
-
- }
-
- /**
- * Get the ValueReference from the ValueExpression.
- *
- * @param component The component.
- * @param context The FacesContext.
- * @return A ValueReferenceWrapper with the necessary information about the ValueReference.
- */
-
- private ValueReferenceWrapper getValueReference(final UIComponent component, final FacesContext context)
- {
- final ValueExpression valueExpression = component.getValueExpression("value");
- final ELContext elCtx = context.getELContext();
- if (_ExternalSpecifications.isUnifiedELAvailable())
- {
- return _BeanValidatorUELUtils.getUELValueReferenceWrapper(valueExpression, elCtx);
- }
- else
- {
- return ValueReferenceResolver.resolve(valueExpression, elCtx);
- }
- }
-
- /**
- * This method creates ValidatorFactory instances or retrieves them from the container.
- *
- * Once created, ValidatorFactory instances are stored in the container under the key
- * VALIDATOR_FACTORY_KEY for performance.
- *
- * @param context The FacesContext.
- * @return The ValidatorFactory instance.
- * @throws FacesException if no ValidatorFactory can be obtained because: a) the
- * container is not a Servlet container or b) because Bean Validation is not available.
- */
- private synchronized ValidatorFactory createValidatorFactory(FacesContext context)
- {
- final Object ctx = context.getExternalContext().getContext();
- if (ctx instanceof ServletContext)
- {
- final ServletContext servletCtx = (ServletContext) ctx;
- final Object attr = servletCtx.getAttribute(VALIDATOR_FACTORY_KEY);
- if (attr != null)
- {
- return (ValidatorFactory) attr;
- }
- else
- {
- if (_ExternalSpecifications.isBeanValidationAvailable())
- {
- final ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
- servletCtx.setAttribute(VALIDATOR_FACTORY_KEY, attr);
- return factory;
- }
- else
- {
- throw new FacesException("Bean Validation is not present");
- }
- }
- }
- else
- {
- throw new FacesException("Only Servlet environments are supported for Bean Validation");
- }
- }
-
- /**
- * Fully initialize the validation groups if needed.
- * If no validation groups are specified, the Default validation group is used.
- */
- private void postSetValidationGroups()
- {
- if (this.validationGroups == null || this.validationGroups.matches(EMPTY_VALIDATION_GROUPS_PATTERN))
- {
- this.validationGroupsArray = new Class<?>[] { Default.class };
- }
- else
- {
- final String[] classes = this.validationGroups.split(VALIDATION_GROUPS_DELIMITER);
- final List<Class<?>> validationGroupsList = new ArrayList<Class<?>>(classes.length);
-
- for (String clazz : classes)
- {
- clazz = clazz.trim();
- if (!clazz.equals(""))
- {
- try
- {
- final Class<?> theClass = Class.forName(clazz);
- validationGroupsList.add(theClass);
- }
- catch (ClassNotFoundException e)
- {
- throw new RuntimeException("Could not load validation group", e);
- }
- }
- }
- this.validationGroupsArray = validationGroupsList.toArray(new Class[validationGroupsList.size()]);
- }
- }
-
- /** {@inheritDoc} */
- public Object saveState(final FacesContext context)
- {
- return this.validationGroups;
- }
-
- /** {@inheritDoc} */
- public void restoreState(final FacesContext context, final Object state)
- {
- this.validationGroups = (String) state;
-
- // Only the String is saved, recalculate the Class[] on state restoration.
- //postSetValidationGroups();
- }
-
- /**
- * Get the Bean Validation validation groups.
- * @return The validation groups String.
- */
- @JSFProperty
- public String getValidationGroups()
- {
- return validationGroups;
- }
-
- /**
- * Set the Bean Validation validation groups.
- * @param validationGroups The validation groups String, separated by
- * {@link BeanValidator#VALIDATION_GROUPS_DELIMITER}.
- */
- public void setValidationGroups(final String validationGroups)
- {
- this.validationGroups = validationGroups;
- //postSetValidationGroups();
- }
-
- @JSFProperty
- private Boolean isDisabled()
- {
- return null;
- }
-
- @JSFProperty
- private String getFor()
- {
- return null;
- }
-
- /** {@inheritDoc} */
- public boolean isTransient()
- {
- return isTransient;
- }
-
- /** {@inheritDoc} */
- public void setTransient(final boolean isTransient)
- {
- this.isTransient = isTransient;
- }
-
- /** {@inheritDoc} */
- public void clearInitialState()
- {
- _initialStateMarked = false;
- }
-
- /** {@inheritDoc} */
- public boolean initialStateMarked()
- {
- return _initialStateMarked;
- }
-
- /** {@inheritDoc} */
- public void markInitialState()
- {
- _initialStateMarked = true;
- }
-}
-
-/**
- * Holder class to prevent NoClassDefFoundError in environments without Bean Validation.
- *
- * This is needed, because holder classes are loaded lazily. This means that when it's not
- * used, it will not be loaded, parsed and initialized. The BeanValidator class is used always,
- * so the MessageInterpolator references need to be in this separate class.
- */
-final class FacesMessageInterpolatorHolder
-{
- // Needs to be volatile.
- private static volatile FacesMessageInterpolator instance;
-
- /**
- * Helper method for initializing the FacesMessageInterpolator.
- *
- * It uses the "Single Check Idiom" as described in Joshua Bloch's Effective Java 2nd Edition.
- *
- * @param validatorFactory Used to obtain the MessageInterpolator.
- * @return The instantiated MessageInterpolator for BeanValidator.
- */
- static MessageInterpolator get(final ValidatorFactory validatorFactory)
- {
- FacesMessageInterpolatorHolder.FacesMessageInterpolator ret = instance;
- if (ret == null)
- {
- final MessageInterpolator interpolator = validatorFactory.getMessageInterpolator();
- instance = ret = new FacesMessageInterpolator(interpolator);
- }
- return ret;
- }
-
- /**
- * Standard MessageInterpolator, as described in the JSR-314 spec.
- */
- private static class FacesMessageInterpolator implements MessageInterpolator
- {
- private final MessageInterpolator interpolator;
-
- FacesMessageInterpolator(final MessageInterpolator interpolator)
- {
- this.interpolator = interpolator;
- }
-
- public String interpolate(final String s, final Context context)
- {
- final Locale locale = FacesContext.getCurrentInstance().getViewRoot().getLocale();
- return interpolator.interpolate(s, context, locale);
- }
-
- public String interpolate(final String s, final Context context, final Locale locale)
- {
- return interpolator.interpolate(s, context, locale);
- }
- }
-}
-
-/**
- * This class provides access to the object pointed to by the EL expression.
- *
- * It makes the BeanValidator work when Unified EL is not available.
- */
-final class ValueReferenceWrapper
-{
- private final Object base, property;
-
- /**
- * Full constructor.
- *
- * @param base The object the reference points to.
- * @param property The property the reference points to.
- */
- public ValueReferenceWrapper(final Object base, final Object property)
- {
- this.base = base;
- this.property = property;
- }
-
- /**
- * The object the reference points to.
- * @return base.
- */
- public final Object getBase()
- {
- return base;
- }
-
- /**
- * The property the reference points to.
- * @return property.
- */
- public final Object getProperty()
- {
- return property;
- }
-}
-
-/**
- * This class inspects the EL expression and returns a ValueReferenceWrapper
- * when Unified EL is not available.
- */
-final class ValueReferenceResolver extends ELResolver
-{
- private final ELResolver resolver;
-
- /**
- * This is a simple solution to keep track of the resolved objects,
- * since ELResolver provides no way to know if the current ELResolver
- * is the last one in the chain. By assigning (and effectively overwriting)
- * this field, we know that the value after invoking the chain is always
- * the last one.
- *
- * This solution also deals with nested objects (like: #{myBean.prop.prop.prop}.
- */
- private ValueReferenceWrapper lastObject;
-
- /**
- * Constructor is only used internally.
- * @param elResolver An ELResolver from the current ELContext.
- */
- ValueReferenceResolver(final ELResolver elResolver)
- {
- this.resolver = elResolver;
- }
-
- /**
- * This method can be used to extract the ValueReferenceWrapper from the given ValueExpression.
- *
- * @param valueExpression The ValueExpression to resolve.
- * @param elCtx The ELContext, needed to parse and execute the expression.
- * @return The ValueReferenceWrapper.
- */
- public static ValueReferenceWrapper resolve(final ValueExpression valueExpression, final ELContext elCtx)
- {
- final ValueReferenceResolver resolver = new ValueReferenceResolver(elCtx.getELResolver());
- valueExpression.getValue(new ELContextDecorator(elCtx, resolver));
- return resolver.lastObject;
- }
-
- /**
- * This method is the only one that matters. It keeps track of the objects in the EL expression.
- *
- * It creates a new ValueReferenceWrapper and assigns it to lastObject.
- *
- * @param context The ELContext.
- * @param base The base object, may be null.
- * @param property The property, may be null.
- * @return The resolved value
- */
- @Override
- public Object getValue(final ELContext context, final Object base, final Object property)
- {
- lastObject = new ValueReferenceWrapper(base, property);
- return resolver.getValue(context, base, property);
- }
-
- // ############################ Standard delegating implementations ############################
- public final Class<?> getType(final ELContext ctx, final Object base, final Object property){return resolver.getType(ctx, base, property);}
- public final void setValue(final ELContext ctx, final Object base, final Object property, final Object value){resolver.setValue(ctx, base, property, value);}
- public final boolean isReadOnly(final ELContext ctx, final Object base, final Object property){return resolver.isReadOnly(ctx, base, property);}
- public final Iterator<FeatureDescriptor> getFeatureDescriptors(final ELContext ctx, final Object base){return resolver.getFeatureDescriptors(ctx, base);}
- public final Class<?> getCommonPropertyType(final ELContext ctx, final Object base){return resolver.getCommonPropertyType(ctx, base);}
-
-}
-
-/**
- * This ELContext is used to hook into the EL handling, by decorating the
- * ELResolver chain with a custom ELResolver.
- */
-final class ELContextDecorator extends ELContext
-{
- private final ELContext ctx;
- private final ELResolver interceptingResolver;
-
- /**
- * Only used by ValueExpressionResolver.
- *
- * @param elContext The standard ELContext. All method calls, except getELResolver, are delegated to it.
- * @param interceptingResolver The ELResolver to be returned by getELResolver.
- */
- ELContextDecorator(final ELContext elContext, final ELResolver interceptingResolver)
- {
- this.ctx = elContext;
- this.interceptingResolver = interceptingResolver;
- }
-
- /**
- * This is the important one, it returns the passed ELResolver.
- * @return The ELResolver passed into the constructor.
- */
- @Override
- public final ELResolver getELResolver()
- {
- return interceptingResolver;
- }
-
- // ############################ Standard delegating implementations ############################
- public final FunctionMapper getFunctionMapper(){return ctx.getFunctionMapper();}
- public final VariableMapper getVariableMapper(){return ctx.getVariableMapper();}
- public final void setPropertyResolved(final boolean resolved){ctx.setPropertyResolved(resolved);}
- public final boolean isPropertyResolved(){return ctx.isPropertyResolved();}
- public final void putContext(final Class key, Object contextObject){ctx.putContext(key, contextObject);}
- public final Object getContext(final Class key){return ctx.getContext(key);}
- public final Locale getLocale(){return ctx.getLocale();}
- public final void setLocale(final Locale locale){ctx.setLocale(locale);}
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 javax.faces.validator;
+
+import java.beans.FeatureDescriptor;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Set;
+
+import javax.el.ELContext;
+import javax.el.ELResolver;
+import javax.el.FunctionMapper;
+import javax.el.ValueExpression;
+import javax.el.VariableMapper;
+import javax.faces.FacesException;
+import javax.faces.application.FacesMessage;
+import javax.faces.component.PartialStateHolder;
+import javax.faces.component.UIComponent;
+import javax.faces.context.FacesContext;
+import javax.servlet.ServletContext;
+import javax.validation.ConstraintViolation;
+import javax.validation.MessageInterpolator;
+import javax.validation.Validation;
+import javax.validation.ValidatorFactory;
+import javax.validation.groups.Default;
+import javax.validation.metadata.BeanDescriptor;
+
+import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFJspProperty;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFProperty;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFValidator;
+import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFWebConfigParam;
+
+/**
+ * <p>
+ * <strong>BeanValidator</strong> is a {@link javax.faces.validator.Validator}
+ * that doesn't do any validation itself, but delegates validation logic to
+ * Bean Validation.
+ * </p>
+ *
+ * @author Jan-Kees van Andel (latest modification by $Author$)
+ * @version $Revision$ $Date$
+ *
+ * @since 2.0
+ */
+@JSFValidator(
+ name="f:validateBean",
+ bodyContent="empty")
+@JSFJspProperty(
+ name = "binding",
+ returnType = "javax.faces.validator.BeanValidator",
+ longDesc = "A ValueExpression that evaluates to a BeanValidator.")
+@FacesValidator(value = BeanValidator.VALIDATOR_ID, isDefault = true)
+public class BeanValidator implements Validator, PartialStateHolder
+{
+
+// private static final Logger log = Logger.getLogger(BeanValidator.class.getName());
+
+ /**
+ * Converter ID, as defined by the JSF 2.0 specification.
+ */
+ public static final String VALIDATOR_ID = "javax.faces.Bean";
+
+ /**
+ * The message ID for this Validator in the message bundles.
+ */
+ public static final String MESSAGE_ID = "javax.faces.validator.BeanValidator.MESSAGE";
+
+ /**
+ * If this init parameter is present, no Bean Validators should be added to an UIInput by default.
+ * Explicitly adding a BeanValidator to an UIInput is possible though.
+ */
+ @JSFWebConfigParam(defaultValue="true", expectedValues="true, false", since="2.0")
+ public static final String DISABLE_DEFAULT_BEAN_VALIDATOR_PARAM_NAME = "javax.faces.validator.DISABLE_DEFAULT_BEAN_VALIDATOR";
+
+ /**
+ * The key in the ServletContext where the Bean Validation Factory can be found.
+ * In a managed Java EE 6 environment, the container initializes the ValidatorFactory
+ * and stores it in the ServletContext under this key.
+ * If not present, the manually instantiated ValidatorFactory is stored in the ServletContext
+ * under this key for caching purposes.
+ */
+ public static final String VALIDATOR_FACTORY_KEY = "javax.faces.validator.beanValidator.ValidatorFactory";
+
+ /**
+ * This is used as a separator so multiple validation groups can be specified in one String.
+ */
+ public static final String VALIDATION_GROUPS_DELIMITER = ",";
+
+ /**
+ * This regular expression is used to match for empty validation groups.
+ * Currently, a string containing only whitespace is classified as empty.
+ */
+ public static final String EMPTY_VALIDATION_GROUPS_PATTERN = "^[\\W,]*$";
+
+ private String validationGroups;
+
+ private Class<?>[] validationGroupsArray;
+
+ private boolean isTransient = false;
+
+ private boolean _initialStateMarked = false;
+
+ /**
+ * {@inheritDoc}
+ */
+ public void validate(final FacesContext context, final UIComponent component, final Object value) throws ValidatorException
+ {
+ if (context == null) throw new NullPointerException("context");
+ if (component == null) throw new NullPointerException("component");
+
+ // Obtain a reference to the to-be-validated object and the property name.
+ final ValueReferenceWrapper reference = getValueReference(component, context);
+ if (reference == null)
+ {
+ return;
+ }
+ final Object base = reference.getBase();
+ if (base == null)
+ {
+ return;
+ }
+ final Class<?> valueBaseClass = base.getClass();
+ final String valueProperty = (String) reference.getProperty();
+ if (valueBaseClass == null || valueProperty == null)
+ {
+ return;
+ }
+
+ // Initialize Bean Validation.
+ final ValidatorFactory validatorFactory = createValidatorFactory(context);
+ final javax.validation.Validator validator = createValidator(validatorFactory);
+ final BeanDescriptor beanDescriptor = validator.getConstraintsForClass(valueBaseClass);
+ if (!beanDescriptor.isBeanConstrained())
+ {
+ return;
+ }
+
+ // Note that validationGroupsArray was initialized when createValidator was called
+ final Class[] validationGroupsArray = this.validationGroupsArray;
+
+ // Delegate to Bean Validation.
+ final Set constraintViolations = validator.validateValue(valueBaseClass, valueProperty, value, validationGroupsArray);
+ if (!constraintViolations.isEmpty())
+ {
+ final Set<FacesMessage> messages = new LinkedHashSet<FacesMessage>(constraintViolations.size());
+ for (Object violation: constraintViolations)
+ {
+ final ConstraintViolation constraintViolation = (ConstraintViolation) violation;
+ final String message = constraintViolation.getMessage();
+ final String[] args = new String[]{ message, _MessageUtils.getLabel(context, component) };
+ final FacesMessage msg = _MessageUtils.getErrorMessage(context, MESSAGE_ID, args);
+ messages.add(msg);
+ }
+ throw new ValidatorException(messages);
+ }
+ }
+
+ private javax.validation.Validator createValidator(final ValidatorFactory validatorFactory)
+ {
+ // Set default validation group when setValidationGroups has not been called.
+ // The null check is there to prevent it from happening twice.
+ if (validationGroupsArray == null)
+ {
+ postSetValidationGroups();
+ }
+
+ return validatorFactory //
+ .usingContext() //
+ .messageInterpolator(FacesMessageInterpolatorHolder.get(validatorFactory)) //
+ .getValidator();
+
+ }
+
+ /**
+ * Get the ValueReference from the ValueExpression.
+ *
+ * @param component The component.
+ * @param context The FacesContext.
+ * @return A ValueReferenceWrapper with the necessary information about the ValueReference.
+ */
+
+ private ValueReferenceWrapper getValueReference(final UIComponent component, final FacesContext context)
+ {
+ final ValueExpression valueExpression = component.getValueExpression("value");
+ final ELContext elCtx = context.getELContext();
+ if (_ExternalSpecifications.isUnifiedELAvailable())
+ {
+ // unified el 2.2 is available --> we can use ValueExpression.getValueReference()
+
+ // TODO handle wrapped ValueExpressions
+
+ // we can't access ValueExpression.getValueReference() directly here, because
+ // Class loading would fail in applications with el-api versions prior to 2.2
+ ValueReferenceWrapper valueReference
+ = _BeanValidatorUELUtils.getUELValueReferenceWrapper(valueExpression, elCtx);
+ if (valueReference != null)
+ {
+ return valueReference;
+ }
+ }
+
+ // get base object and property name the "old-fashioned" way
+ return ValueReferenceResolver.resolve(valueExpression, elCtx);
+ }
+
+ /**
+ * This method creates ValidatorFactory instances or retrieves them from the container.
+ *
+ * Once created, ValidatorFactory instances are stored in the container under the key
+ * VALIDATOR_FACTORY_KEY for performance.
+ *
+ * @param context The FacesContext.
+ * @return The ValidatorFactory instance.
+ * @throws FacesException if no ValidatorFactory can be obtained because: a) the
+ * container is not a Servlet container or b) because Bean Validation is not available.
+ */
+ private synchronized ValidatorFactory createValidatorFactory(FacesContext context)
+ {
+ final Object ctx = context.getExternalContext().getContext();
+ if (ctx instanceof ServletContext)
+ {
+ final ServletContext servletCtx = (ServletContext) ctx;
+ final Object attr = servletCtx.getAttribute(VALIDATOR_FACTORY_KEY);
+ if (attr != null)
+ {
+ return (ValidatorFactory) attr;
+ }
+ else
+ {
+ if (_ExternalSpecifications.isBeanValidationAvailable())
+ {
+ final ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
+ servletCtx.setAttribute(VALIDATOR_FACTORY_KEY, attr);
+ return factory;
+ }
+ else
+ {
+ throw new FacesException("Bean Validation is not present");
+ }
+ }
+ }
+ else
+ {
+ throw new FacesException("Only Servlet environments are supported for Bean Validation");
+ }
+ }
+
+ /**
+ * Fully initialize the validation groups if needed.
+ * If no validation groups are specified, the Default validation group is used.
+ */
+ private void postSetValidationGroups()
+ {
+ if (this.validationGroups == null || this.validationGroups.matches(EMPTY_VALIDATION_GROUPS_PATTERN))
+ {
+ this.validationGroupsArray = new Class<?>[] { Default.class };
+ }
+ else
+ {
+ final String[] classes = this.validationGroups.split(VALIDATION_GROUPS_DELIMITER);
+ final List<Class<?>> validationGroupsList = new ArrayList<Class<?>>(classes.length);
+
+ for (String clazz : classes)
+ {
+ clazz = clazz.trim();
+ if (!clazz.equals(""))
+ {
+ try
+ {
+ final Class<?> theClass = Class.forName(clazz);
+ validationGroupsList.add(theClass);
+ }
+ catch (ClassNotFoundException e)
+ {
+ throw new RuntimeException("Could not load validation group", e);
+ }
+ }
+ }
+ this.validationGroupsArray = validationGroupsList.toArray(new Class[validationGroupsList.size()]);
+ }
+ }
+
+ /** {@inheritDoc} */
+ public Object saveState(final FacesContext context)
+ {
+ return this.validationGroups;
+ }
+
+ /** {@inheritDoc} */
+ public void restoreState(final FacesContext context, final Object state)
+ {
+ this.validationGroups = (String) state;
+
+ // Only the String is saved, recalculate the Class[] on state restoration.
+ //postSetValidationGroups();
+ }
+
+ /**
+ * Get the Bean Validation validation groups.
+ * @return The validation groups String.
+ */
+ @JSFProperty
+ public String getValidationGroups()
+ {
+ return validationGroups;
+ }
+
+ /**
+ * Set the Bean Validation validation groups.
+ * @param validationGroups The validation groups String, separated by
+ * {@link BeanValidator#VALIDATION_GROUPS_DELIMITER}.
+ */
+ public void setValidationGroups(final String validationGroups)
+ {
+ this.validationGroups = validationGroups;
+ //postSetValidationGroups();
+ }
+
+ @JSFProperty
+ private Boolean isDisabled()
+ {
+ return null;
+ }
+
+ @JSFProperty
+ private String getFor()
+ {
+ return null;
+ }
+
+ /** {@inheritDoc} */
+ public boolean isTransient()
+ {
+ return isTransient;
+ }
+
+ /** {@inheritDoc} */
+ public void setTransient(final boolean isTransient)
+ {
+ this.isTransient = isTransient;
+ }
+
+ /** {@inheritDoc} */
+ public void clearInitialState()
+ {
+ _initialStateMarked = false;
+ }
+
+ /** {@inheritDoc} */
+ public boolean initialStateMarked()
+ {
+ return _initialStateMarked;
+ }
+
+ /** {@inheritDoc} */
+ public void markInitialState()
+ {
+ _initialStateMarked = true;
+ }
+}
+
+/**
+ * Holder class to prevent NoClassDefFoundError in environments without Bean Validation.
+ *
+ * This is needed, because holder classes are loaded lazily. This means that when it's not
+ * used, it will not be loaded, parsed and initialized. The BeanValidator class is used always,
+ * so the MessageInterpolator references need to be in this separate class.
+ */
+final class FacesMessageInterpolatorHolder
+{
+ // Needs to be volatile.
+ private static volatile FacesMessageInterpolator instance;
+
+ /**
+ * Helper method for initializing the FacesMessageInterpolator.
+ *
+ * It uses the "Single Check Idiom" as described in Joshua Bloch's Effective Java 2nd Edition.
+ *
+ * @param validatorFactory Used to obtain the MessageInterpolator.
+ * @return The instantiated MessageInterpolator for BeanValidator.
+ */
+ static MessageInterpolator get(final ValidatorFactory validatorFactory)
+ {
+ FacesMessageInterpolatorHolder.FacesMessageInterpolator ret = instance;
+ if (ret == null)
+ {
+ final MessageInterpolator interpolator = validatorFactory.getMessageInterpolator();
+ instance = ret = new FacesMessageInterpolator(interpolator);
+ }
+ return ret;
+ }
+
+ /**
+ * Standard MessageInterpolator, as described in the JSR-314 spec.
+ */
+ private static class FacesMessageInterpolator implements MessageInterpolator
+ {
+ private final MessageInterpolator interpolator;
+
+ FacesMessageInterpolator(final MessageInterpolator interpolator)
+ {
+ this.interpolator = interpolator;
+ }
+
+ public String interpolate(final String s, final Context context)
+ {
+ final Locale locale = FacesContext.getCurrentInstance().getViewRoot().getLocale();
+ return interpolator.interpolate(s, context, locale);
+ }
+
+ public String interpolate(final String s, final Context context, final Locale locale)
+ {
+ return interpolator.interpolate(s, context, locale);
+ }
+ }
+}
+
+/**
+ * This class provides access to the object pointed to by the EL expression.
+ *
+ * It makes the BeanValidator work when Unified EL is not available.
+ */
+final class ValueReferenceWrapper
+{
+ private final Object base, property;
+
+ /**
+ * Full constructor.
+ *
+ * @param base The object the reference points to.
+ * @param property The property the reference points to.
+ */
+ public ValueReferenceWrapper(final Object base, final Object property)
+ {
+ this.base = base;
+ this.property = property;
+ }
+
+ /**
+ * The object the reference points to.
+ * @return base.
+ */
+ public final Object getBase()
+ {
+ return base;
+ }
+
+ /**
+ * The property the reference points to.
+ * @return property.
+ */
+ public final Object getProperty()
+ {
+ return property;
+ }
+}
+
+/**
+ * This class inspects the EL expression and returns a ValueReferenceWrapper
+ * when Unified EL is not available.
+ */
+final class ValueReferenceResolver extends ELResolver
+{
+ private final ELResolver resolver;
+
+ /**
+ * This is a simple solution to keep track of the resolved objects,
+ * since ELResolver provides no way to know if the current ELResolver
+ * is the last one in the chain. By assigning (and effectively overwriting)
+ * this field, we know that the value after invoking the chain is always
+ * the last one.
+ *
+ * This solution also deals with nested objects (like: #{myBean.prop.prop.prop}.
+ */
+ private ValueReferenceWrapper lastObject;
+
+ /**
+ * Constructor is only used internally.
+ * @param elResolver An ELResolver from the current ELContext.
+ */
+ ValueReferenceResolver(final ELResolver elResolver)
+ {
+ this.resolver = elResolver;
+ }
+
+ /**
+ * This method can be used to extract the ValueReferenceWrapper from the given ValueExpression.
+ *
+ * @param valueExpression The ValueExpression to resolve.
+ * @param elCtx The ELContext, needed to parse and execute the expression.
+ * @return The ValueReferenceWrapper.
+ */
+ public static ValueReferenceWrapper resolve(final ValueExpression valueExpression, final ELContext elCtx)
+ {
+ final ValueReferenceResolver resolver = new ValueReferenceResolver(elCtx.getELResolver());
+ valueExpression.getValue(new ELContextDecorator(elCtx, resolver));
+ return resolver.lastObject;
+ }
+
+ /**
+ * This method is the only one that matters. It keeps track of the objects in the EL expression.
+ *
+ * It creates a new ValueReferenceWrapper and assigns it to lastObject.
+ *
+ * @param context The ELContext.
+ * @param base The base object, may be null.
+ * @param property The property, may be null.
+ * @return The resolved value
+ */
+ @Override
+ public Object getValue(final ELContext context, final Object base, final Object property)
+ {
+ lastObject = new ValueReferenceWrapper(base, property);
+ return resolver.getValue(context, base, property);
+ }
+
+ // ############################ Standard delegating implementations ############################
+ public final Class<?> getType(final ELContext ctx, final Object base, final Object property){return resolver.getType(ctx, base, property);}
+ public final void setValue(final ELContext ctx, final Object base, final Object property, final Object value){resolver.setValue(ctx, base, property, value);}
+ public final boolean isReadOnly(final ELContext ctx, final Object base, final Object property){return resolver.isReadOnly(ctx, base, property);}
+ public final Iterator<FeatureDescriptor> getFeatureDescriptors(final ELContext ctx, final Object base){return resolver.getFeatureDescriptors(ctx, base);}
+ public final Class<?> getCommonPropertyType(final ELContext ctx, final Object base){return resolver.getCommonPropertyType(ctx, base);}
+
+}
+
+/**
+ * This ELContext is used to hook into the EL handling, by decorating the
+ * ELResolver chain with a custom ELResolver.
+ */
+final class ELContextDecorator extends ELContext
+{
+ private final ELContext ctx;
+ private final ELResolver interceptingResolver;
+
+ /**
+ * Only used by ValueExpressionResolver.
+ *
+ * @param elContext The standard ELContext. All method calls, except getELResolver, are delegated to it.
+ * @param interceptingResolver The ELResolver to be returned by getELResolver.
+ */
+ ELContextDecorator(final ELContext elContext, final ELResolver interceptingResolver)
+ {
+ this.ctx = elContext;
+ this.interceptingResolver = interceptingResolver;
+ }
+
+ /**
+ * This is the important one, it returns the passed ELResolver.
+ * @return The ELResolver passed into the constructor.
+ */
+ @Override
+ public final ELResolver getELResolver()
+ {
+ return interceptingResolver;
+ }
+
+ // ############################ Standard delegating implementations ############################
+ public final FunctionMapper getFunctionMapper(){return ctx.getFunctionMapper();}
+ public final VariableMapper getVariableMapper(){return ctx.getVariableMapper();}
+ public final void setPropertyResolved(final boolean resolved){ctx.setPropertyResolved(resolved);}
+ public final boolean isPropertyResolved(){return ctx.isPropertyResolved();}
+ public final void putContext(final Class key, Object contextObject){ctx.putContext(key, contextObject);}
+ public final Object getContext(final Class key){return ctx.getContext(key);}
+ public final Locale getLocale(){return ctx.getLocale();}
+ public final void setLocale(final Locale locale){ctx.setLocale(locale);}
+}
Propchange: myfaces/core/trunk/api/src/main/java/javax/faces/validator/BeanValidator.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: myfaces/core/trunk/api/src/main/java/javax/faces/validator/BeanValidator.java
------------------------------------------------------------------------------
svn:keywords = Date Author Id Revision HeadURL
Modified: myfaces/core/trunk/api/src/main/java/javax/faces/validator/_BeanValidatorUELUtils.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/api/src/main/java/javax/faces/validator/_BeanValidatorUELUtils.java?rev=927162&r1=927161&r2=927162&view=diff
==============================================================================
--- myfaces/core/trunk/api/src/main/java/javax/faces/validator/_BeanValidatorUELUtils.java (original)
+++ myfaces/core/trunk/api/src/main/java/javax/faces/validator/_BeanValidatorUELUtils.java Wed Mar 24 19:37:30 2010
@@ -1,93 +1,54 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you 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 javax.faces.validator;
-
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-
-import javax.el.ELContext;
-import javax.el.ValueExpression;
-import javax.el.ValueReference;
-import javax.faces.FacesException;
-
-/**
- * Utility class that isolates UEL calls, to prevent ClassNotFoundException
- * when bean validation is used without it. It is a similar hack to the one
- * used in portlet case.
- *
- * @since 2.0
- * @author Leonardo Uribe (latest modification by $Author: slessard $)
- * @version $Revision: 696523 $ $Date: 2008-09-24 18:31:37 -0400 (mer., 17 sept. 2008) $
- */
-final class _BeanValidatorUELUtils
-{
-
- /**
- * Get the ValueReference from the ValueExpression.
- *
- * @param component The component.
- * @param context The FacesContext.
- * @return A ValueReferenceWrapper with the necessary information about the ValueReference.
- */
- public static ValueReferenceWrapper getUELValueReferenceWrapper(final ValueExpression valueExpression, final ELContext elCtx)
- {
- final ValueReference valueReference = getUELValueReference(valueExpression, elCtx);
- if (valueReference == null)
- {
- return null;
- }
- return new ValueReferenceWrapper(valueReference.getBase(), valueReference.getProperty());
- }
-
- private static ValueReference getUELValueReference(final ValueExpression valueExpression, final ELContext elCtx)
- {
- final String methodName = "getValueReference";
- final String methodSignature = valueExpression.getClass().getName() +
- "." + methodName +
- "(" + ELContext.class + ")";
- try
- {
- final Method method = valueExpression.getClass().getMethod(methodName, ELContext.class);
- if (!ValueReference.class.equals(method.getReturnType())
- && !ValueReference.class.isAssignableFrom(method.getReturnType()))
- {
- throw new NoSuchMethodException(
- methodSignature +
- "doesn't return " + ValueReference.class +
- ", but " + method.getReturnType());
- }
- return (ValueReference) method.invoke(valueExpression, elCtx);
- }
- catch (NoSuchMethodException e)
- {
- throw new FacesException(
- "MyFaces indicates Unified EL is available, but method: " +
- methodSignature +
- " is not available", e);
- }
- catch (InvocationTargetException e)
- {
- throw new FacesException("Exception invoking " + methodSignature, e);
- }
- catch (IllegalAccessException e)
- {
- throw new FacesException("Exception invoking " + methodSignature, e);
- }
- }
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 javax.faces.validator;
+
+import javax.el.ELContext;
+import javax.el.ValueExpression;
+import javax.el.ValueReference;
+
+/**
+ * Utility class that isolates UEL calls, to prevent ClassNotFoundException
+ * when bean validation is used without it. It is a similar hack to the one
+ * used in portlet case.
+ *
+ * @since 2.0
+ * @author Leonardo Uribe (latest modification by $Author$)
+ * @version $Revision$ $Date$
+ */
+final class _BeanValidatorUELUtils
+{
+
+ /**
+ * Get the ValueReference from the ValueExpression.
+ *
+ * @param component The component.
+ * @param context The FacesContext.
+ * @return A ValueReferenceWrapper with the necessary information about the ValueReference.
+ */
+ public static ValueReferenceWrapper getUELValueReferenceWrapper(final ValueExpression valueExpression, final ELContext elCtx)
+ {
+ final ValueReference valueReference = valueExpression.getValueReference(elCtx);
+ if (valueReference == null)
+ {
+ return null;
+ }
+ return new ValueReferenceWrapper(valueReference.getBase(), valueReference.getProperty());
+ }
+
+}
Propchange: myfaces/core/trunk/api/src/main/java/javax/faces/validator/_BeanValidatorUELUtils.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: myfaces/core/trunk/api/src/main/java/javax/faces/validator/_BeanValidatorUELUtils.java
------------------------------------------------------------------------------
svn:keywords = Date Author Id Revision HeadURL