Package org.apache.bval.jsr303.util

Source Code of org.apache.bval.jsr303.util.ValidationContextTraversal$NullSafePropertyAccess

/*
* 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.jsr303.util;

import java.lang.reflect.Type;

import org.apache.bval.DynamicMetaBean;
import org.apache.bval.jsr303.Jsr303MetaBeanFactory;
import org.apache.bval.jsr303.UnknownPropertyException;
import org.apache.bval.jsr303.util.PathNavigation.CallbackProcedure;
import org.apache.bval.model.MetaBean;
import org.apache.bval.model.MetaProperty;
import org.apache.bval.model.ValidationContext;
import org.apache.bval.util.AccessStrategy;
import org.apache.bval.util.IndexedAccess;
import org.apache.bval.util.KeyedAccess;
import org.apache.bval.util.PropertyAccess;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.reflect.TypeUtils;

/**
* {@link ValidationContext} traversal {@link CallbackProcedure}.
*
* @version $Rev: 1137074 $ $Date: 2011-06-17 18:20:30 -0500 (Fri, 17 Jun 2011) $
*/
public class ValidationContextTraversal extends CallbackProcedure {
    private static class NullSafePropertyAccess extends PropertyAccess {

        /**
         * Create a new NullSafePropertyAccess instance.
         *
         * @param clazz
         * @param propertyName
         */
        public NullSafePropertyAccess(Class<?> clazz, String propertyName) {
            super(clazz, propertyName);
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public Object get(Object bean) {
            return bean == null ? null : super.get(bean);
        }
    }

    private final ValidationContext<?> validationContext;
    private Type type;
    private Class<?> rawType;

    /**
     * Create a new {@link ValidationContextTraversal} instance.
     *
     * @param validationContext
     */
    public ValidationContextTraversal(ValidationContext<?> validationContext) {
        this.validationContext = validationContext;
        init();
    }

    /**
     * Initialize from {@link ValidationContext}.
     */
    public void init() {
        this.rawType = validationContext.getMetaBean().getBeanClass();
        this.type = this.rawType;
    }

    /**
     * {@inheritDoc}
     */
    public void handleIndexOrKey(String token) {
        moveDownIfNecessary();

        AccessStrategy access;
        if (IndexedAccess.getJavaElementType(type) != null) {
            try {
                Integer index = token == null ? null : Integer.valueOf(token);
                access = new IndexedAccess(type, index);
                validationContext.setCurrentIndex(index);
            } catch (NumberFormatException e) {
                throw new UnknownPropertyException(String.format("Cannot parse %s as an array/iterable index", token),
                    e);
            }
        } else if (KeyedAccess.getJavaElementType(type) != null) {
            access = new KeyedAccess(type, token);
            validationContext.setCurrentKey(token);
        } else {
            throw new UnknownPropertyException(String.format("Cannot determine index/key type for %s", type));
        }
        Object value = validationContext.getBean();
        Object child = value == null ? null : access.get(value);
        setType(child == null ? access.getJavaType() : child.getClass());
        validationContext.setBean(child,
            validationContext.getMetaBean().resolveMetaBean(child == null ? rawType : child));
    }

    /**
     * {@inheritDoc}
     */
    public void handleProperty(String token) {
        moveDownIfNecessary();

        MetaBean metaBean = validationContext.getMetaBean();

        if (metaBean instanceof DynamicMetaBean) {
            metaBean = metaBean.resolveMetaBean(ObjectUtils.defaultIfNull(validationContext.getBean(), rawType));
            validationContext.setMetaBean(metaBean);
        }
        MetaProperty mp = metaBean.getProperty(token);
        if (mp == null) {
            // TODO this could indicate a property hosted on a superclass; should we shunt the context traversal down a path based on that type?

            PropertyAccess access = new PropertyAccess(rawType, token);
            if (access.isKnown()) {
                // add heretofore unknown, but valid, property on the fly:
                mp = Jsr303MetaBeanFactory.addMetaProperty(metaBean, access);
            } else {
                throw new UnknownPropertyException("unknown property '" + token + "' in " + metaBean.getId());
            }
        }
        validationContext.setMetaProperty(mp);
        setType(mp.getType());
    }

    /**
     * If we currently have a property, navigate the context such that the property becomes the bean, in preparation for
     * another property.
     *
     * @param validationContext
     */
    public void moveDownIfNecessary() {
        MetaProperty mp = validationContext.getMetaProperty();
        if (mp != null) {
            if (mp.getMetaBean() == null) {
                throw new UnknownPropertyException(String.format("Property %s.%s is not cascaded", mp
                    .getParentMetaBean().getId(), mp.getName()));
            }
            validationContext.moveDown(mp, new NullSafePropertyAccess(validationContext.getMetaBean().getBeanClass(),
                mp.getName()));
        }
    }

    /**
     * Set the type of the expression processed thus far.
     *
     * @param type
     */
    protected void setType(Type type) {
        this.rawType = TypeUtils.getRawType(type, this.type);
        this.type = type;
    }

    /**
     * {@inheritDoc}
     */
    public void handleGenericInIterable() {
        throw new UnsupportedOperationException("Cannot navigate a ValidationContext to []");
    }

    /**
     * @return the type
     */
    public Type getType() {
        return type;
    }

    /**
     * @return the rawType
     */
    public Class<?> getRawType() {
        return rawType;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected void complete() {
        super.complete();
        if (validationContext.getMetaProperty() != null) {
            return;
        }
        if (validationContext.getMetaBean() instanceof DynamicMetaBean) {
            validationContext.setMetaBean(validationContext.getMetaBean().resolveMetaBean(
                ObjectUtils.defaultIfNull(validationContext.getBean(), rawType)));
        }
    }
}
TOP

Related Classes of org.apache.bval.jsr303.util.ValidationContextTraversal$NullSafePropertyAccess

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.