Package org.apache.bval.jsr

Source Code of org.apache.bval.jsr.ConstraintValidationListener

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


import org.apache.bval.jsr.util.PathImpl;
import org.apache.bval.model.ValidationContext;
import org.apache.bval.model.ValidationListener;

import javax.validation.ConstraintViolation;
import javax.validation.ElementKind;
import javax.validation.MessageInterpolator;
import javax.validation.Path;
import javax.validation.metadata.ConstraintDescriptor;
import java.lang.annotation.ElementType;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

/**
* Description: JSR-303 {@link ValidationListener} implementation; provides {@link ConstraintViolation}s.<br/>
*
* @version $Rev: 1503686 $ $Date: 2013-07-16 14:38:56 +0200 (mar., 16 juil. 2013) $
*/
public final class ConstraintValidationListener<T> implements ValidationListener {
    private final Set<ConstraintViolation<T>> constraintViolations = new HashSet<ConstraintViolation<T>>();
    private final T rootBean;
    private final Class<T> rootBeanType;
    // the validation process is single-threaded and it's unlikely to change in the near future (otherwise use AtomicInteger).
    private int compositeDepth = 0;
    private boolean hasCompositeError;

    /**
     * Create a new ConstraintValidationListener instance.
     * @param aRootBean
     * @param rootBeanType
     */
    public ConstraintValidationListener(T aRootBean, Class<T> rootBeanType) {
        this.rootBean = aRootBean;
        this.rootBeanType = rootBeanType;
    }

    /**
     * {@inheritDoc}
     */
    public <VL extends ValidationListener> void addError(String reason, ValidationContext<VL> context) {
        addError(reason, null, context);
    }

    /**
     * {@inheritDoc}
     */
    public <VL extends ValidationListener> void addError(Error error, ValidationContext<VL> context) {
        if (error.getOwner() instanceof Path) {
            addError(error.getReason(), (Path) error.getOwner(), context);
        } else {
            addError(error.getReason(), null, context);
        }
    }

    private void addError(String messageTemplate, Path propPath,
                          ValidationContext<?> context) {
        if (compositeDepth > 0) {
            hasCompositeError |= true;
            return;
        }
        final Object value;

        final ConstraintDescriptor<?> descriptor;
        final String message;
        if (context instanceof GroupValidationContext<?>) {
            GroupValidationContext<?> gcontext = (GroupValidationContext<?>) context;
            value = gcontext.getValidatedValue();
            if (gcontext instanceof MessageInterpolator.Context) {
                message = gcontext.getMessageResolver()
                      .interpolate(messageTemplate,
                            (MessageInterpolator.Context) gcontext);
            } else {
                message =
                      gcontext.getMessageResolver().interpolate(messageTemplate, null);
            }
            descriptor = gcontext.getConstraintValidation().asSerializableDescriptor();
            if (propPath == null) propPath = gcontext.getPropertyPath();
        } else {
            if (context.getMetaProperty() == null) value = context.getBean();
            else value = context.getPropertyValue();
            message = messageTemplate;
            if (propPath == null)
                propPath = PathImpl.createPathFromString(context.getPropertyName());
            descriptor = null;
        }
        ElementType elementType = (context.getAccess() != null) ? context.getAccess().getElementType() : null;

        final Object[] parameters;
        Object leaf;
        Object returnValue;
        T rootBean;
        if (GroupValidationContext.class.isInstance(context)) { // TODO: clean up it but it would need to rework completely our context - get rid of it would be the best
            final GroupValidationContext<T> ctx = GroupValidationContext.class.cast(context);
            final ElementKind elementKind = ctx.getElementKind();
            final Iterator<Path.Node> it = propPath.iterator();
            final ElementKind kind = propPath.iterator().next().getKind();

            returnValue = ctx.getReturnValue();

            if (ElementKind.CONSTRUCTOR.equals(kind)) {
                rootBean = null;
                leaf = context.getBean();
                returnValue = this.rootBean; // switch back return value and rootBean
            } else if (ElementKind.METHOD.equals(kind)) {
                if (ElementKind.RETURN_VALUE.equals(elementKind)) { // switch back return value and rootBean
                    rootBean = (T) returnValue;
                    if (kindOf(propPath, ElementKind.RETURN_VALUE)) {
                        leaf = returnValue;
                        returnValue = this.rootBean;
                    } else {
                        leaf = this.rootBean;
                        returnValue = this.rootBean;
                    }
                } else {
                    rootBean = this.rootBean;
                    if (kindOf(propPath, ElementKind.PARAMETER, ElementKind.CROSS_PARAMETER)) {
                        leaf = rootBean;
                    } else {
                        leaf = context.getBean();
                    }
                }
            } else {
                rootBean = this.rootBean;
                leaf = context.getBean();
            }

            if (ElementKind.CONSTRUCTOR.equals(kind)
                    && (ElementKind.CROSS_PARAMETER.equals(elementKind)
                        || ElementKind.PARAMETER.equals(elementKind))
                    && (it.hasNext() && it.next() != null && it.hasNext() && it.next() != null && !it.hasNext())) { // means inherited validation use real value
                leaf = null;
            }

            parameters = ctx.getParameters();
        } else {
            leaf = context.getBean();
            returnValue = null;
            parameters = null;
            rootBean = this.rootBean;
        }

        constraintViolations.add(new ConstraintViolationImpl<T>(
                messageTemplate, message,
                rootBean, leaf,
                propPath, value, descriptor,
                rootBeanType,
                elementType, returnValue, parameters));
    }

    private static boolean kindOf(final Path propPath, final ElementKind... kinds) {
        final Iterator<Path.Node> node = propPath.iterator();
        boolean isParam = false;
        while (node.hasNext()) {
            final ElementKind current = node.next().getKind();
            isParam = false;
            for (final ElementKind k : kinds) {
                if (k.equals(current)) {
                    isParam = true;
                    break;
                }
            }
        }
        return isParam;
    }

    /**
     * Get the {@link ConstraintViolation}s accumulated by this {@link ConstraintValidationListener}.
     * @return {@link Set} of {@link ConstraintViolation}
     */
    public Set<ConstraintViolation<T>> getConstraintViolations() {
        return constraintViolations;
    }

    /**
     * Learn whether no violations were found.
     * @return boolean
     */
    public boolean isEmpty() {
        return constraintViolations.isEmpty();
    }

    /**
     * Get the root bean.
     * @return T
     */
    public T getRootBean() {
        return rootBean;
    }

    /**
     * Get the root bean type of this {@link ConstraintValidationListener}.
     * @return Class<T>
     */
    public Class<T> getRootBeanType() {
        return rootBeanType;
    }
   
    /**
     * Get the count of encountered violations.
     * @return int
     */
    public int violationsSize() {
        return constraintViolations.size();
    }

    /**
     * Learn whether there are violations available.
     * If in report-as-single-violation mode, the result is scoped accordingly.
     * Note that this means you must check before exiting report-as-single-violation mode
     * @return boolean
     */
    public boolean hasViolations() {
        return compositeDepth == 0 ? !constraintViolations.isEmpty() : hasCompositeError;
    }

    /**
     * Signify the beginning of a report-as-single-violation composite validation.
     * @return <code>true</code> as this call caused the listener to enter report-as-single-violation mode
     */
    public boolean beginReportAsSingle() {
        return ++compositeDepth == 1;
    }

    /**
     * Signify the end of a report-as-single-violation composite validation.
     * @return <code>true</code> as this call caused the listener to exit report-as-single-violation mode
     */
    public boolean endReportAsSingle() {
        boolean endOutMostReportAsSingle = (--compositeDepth == 0);
        if( endOutMostReportAsSingle ) {
            hasCompositeError = false;
        }
        return endOutMostReportAsSingle;
    }
}
TOP

Related Classes of org.apache.bval.jsr.ConstraintValidationListener

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.