| /* |
| * 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 org.apache.bval.util; |
| |
| import java.util.List; |
| import java.util.Map; |
| import org.apache.bval.DynamicMetaBean; |
| import org.apache.bval.model.MetaBean; |
| import org.apache.bval.model.MetaProperty; |
| import org.apache.bval.model.Validation; |
| import org.apache.bval.model.ValidationContext; |
| import org.apache.bval.model.ValidationListener; |
| |
| |
| /** |
| * Stateless helper methods used by the validators. |
| * |
| * @author Carlos Vara |
| */ |
| public class ValidationHelper { |
| |
| /** |
| * Interface implemented by the call-back object passed to |
| * {@link ValidationHelper#validateContext(ValidationContext, ValidateCallback, boolean)} |
| * . Its {@link #validate()} method will be called accordingly for every |
| * dispatch. |
| */ |
| public static interface ValidateCallback { |
| void validate(); |
| } |
| |
| /** |
| * validate a complex 'bean' with related beans according to |
| * validation rules in 'metaBean' |
| * |
| * @param context |
| * - the context is initialized with: <br> |
| * bean - the root object start validation at |
| * or a collection of root objects <br> |
| * metaBean - the meta information for the root |
| * object(s) |
| * @param context |
| * The current validation context. |
| */ |
| static public void validateContext(ValidationContext<?> context, ValidateCallback s, boolean treatMapsLikeBeans) { |
| if (context.getBean() != null) { |
| if (!treatMapsLikeBeans && context.getBean() instanceof Map<?, ?>) { |
| validateMapInContext(context, s); |
| } else if (context.getBean() instanceof Iterable<?>) { |
| validateIterableInContext(context, s); |
| } else if (context.getBean() instanceof Object[]) { |
| validateArrayInContext(context, s); |
| } else { // to One Bean (or Map like Bean) |
| validateBeanInContext(context, s); |
| } |
| } |
| } |
| |
| /** |
| * Validates a single object. |
| * |
| * @param <VL> |
| * @param context |
| * The validation context, its current bean must be a single |
| * object. |
| * @param s |
| */ |
| static protected <VL extends ValidationListener> void validateBeanInContext(ValidationContext<VL> context, ValidateCallback s) { |
| if (getDynamicMetaBean(context) != null) { |
| context.setMetaBean(getDynamicMetaBean(context).resolveMetaBean(context.getBean())); |
| } |
| s.validate(); |
| } |
| |
| /** |
| * Iterates the values of an array, setting the current context |
| * appropriately and validating each value. |
| * |
| * @param <VL> |
| * @param context |
| * The validation context, its current bean must be an array. |
| */ |
| static protected <VL extends ValidationListener> void validateArrayInContext(ValidationContext<VL> context, ValidateCallback s) { |
| int index = 0; |
| DynamicMetaBean dyn = getDynamicMetaBean(context); |
| Object[] array = (Object[]) context.getBean(); |
| MetaBean metaBean = context.getMetaBean(); |
| context.setCurrentIndex(null); |
| try { |
| for (Object each : array) { |
| context.setCurrentIndex(index++); |
| if (each == null) { |
| continue; // Null values are not validated |
| } |
| if (dyn != null) { |
| context.setBean(each, dyn.resolveMetaBean(each)); |
| } else { |
| context.setBean(each); |
| } |
| s.validate(); |
| } |
| } finally { |
| context.moveUp(array, metaBean); |
| } |
| } |
| |
| /** |
| * Iterates the values of an {@link Iterable} object, setting the current |
| * context appropriately and validating each value. |
| * |
| * @param <VL> |
| * @param context |
| * The validation context, its current bean must implement |
| * {@link Iterable}. |
| */ |
| static protected <VL extends ValidationListener> void validateIterableInContext(ValidationContext<VL> context, ValidateCallback s) { |
| |
| final boolean positional = context.getBean() instanceof List<?>; |
| int index = 0; |
| Iterable<?> iterable = (Iterable<?>) context.getBean(); |
| MetaBean metaBean = context.getMetaBean(); |
| context.setCurrentIndex(null); |
| |
| try { |
| // jsr303 spec: Each object provided by the iterator is validated. |
| final DynamicMetaBean dyn = getDynamicMetaBean(context); |
| for (Object each : iterable) { |
| if (positional) { |
| context.setCurrentIndex(index++); |
| } |
| if (each == null) { |
| continue; // Null values are not validated |
| } |
| if (dyn != null) { |
| context.setBean(each, dyn.resolveMetaBean(each)); |
| } else { |
| context.setBean(each); |
| } |
| s.validate(); |
| } |
| } finally { |
| context.moveUp(iterable, metaBean); |
| } |
| } |
| |
| /** |
| * Iterates the values of a {@link Map}, setting the current context |
| * appropriately and validating each value. |
| * |
| * @param <VL> |
| * @param context |
| * The validation context, its current bean must implement |
| * {@link Map}. |
| */ |
| static protected <VL extends ValidationListener> void validateMapInContext(ValidationContext<VL> context, ValidateCallback s) { |
| // jsr303 spec: For Map, the value of each Map.Entry is validated (key |
| // is not validated). |
| Map<?, ?> currentBean = (Map<?, ?>) context.getBean(); |
| MetaBean metaBean = context.getMetaBean(); |
| final DynamicMetaBean dyn = getDynamicMetaBean(context); |
| context.setCurrentKey(null); |
| try { |
| for (Map.Entry<?, ?> entry : currentBean.entrySet()) { |
| Object value = entry.getValue(); |
| if (value == null) { |
| continue; |
| } |
| context.setCurrentKey(entry.getKey()); |
| if (dyn == null) { |
| context.setBean(value); |
| } else { |
| context.setBean(value, dyn.resolveMetaBean(value)); |
| } |
| s.validate(); |
| } |
| } finally { |
| context.moveUp(currentBean, metaBean); |
| } |
| } |
| |
| /** |
| * @param <VL> |
| * @param context |
| * The current validation context. |
| * @return the current {@link DynamicMetaBean} in context, or |
| * <code>null</code> if the current meta bean is not dynamic. |
| */ |
| static private <VL extends ValidationListener> DynamicMetaBean getDynamicMetaBean(ValidationContext<VL> context) { |
| return context.getMetaBean() instanceof DynamicMetaBean ? (DynamicMetaBean) context.getMetaBean() : null; |
| } |
| |
| |
| /** |
| * Validate a single bean only, no related beans will be validated. |
| */ |
| static public <VL extends ValidationListener> void validateBean(ValidationContext<VL> context) { |
| // execute all property level validations |
| for (MetaProperty prop : context.getMetaBean().getProperties()) { |
| context.setMetaProperty(prop); |
| validateProperty(context); |
| } |
| |
| // execute all bean level validations |
| context.setMetaProperty(null); |
| for (Validation validation : context.getMetaBean().getValidations()) { |
| validation.validate(context); |
| } |
| } |
| |
| |
| /** |
| * Validate a single property only. Performs all validations |
| * for this property. |
| */ |
| static public <VL extends ValidationListener> void validateProperty(ValidationContext<VL> context) { |
| for (Validation validation : context.getMetaProperty().getValidations()) { |
| validation.validate(context); |
| } |
| } |
| } |