You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@bval.apache.org by rm...@apache.org on 2013/08/26 15:59:20 UTC

svn commit: r1517540 [9/15] - in /bval/branches/bval-11/bval-jsr: ./ src/ src/main/ src/main/appended-resources/ src/main/appended-resources/META-INF/ src/main/java/ src/main/java/org/ src/main/java/org/apache/ src/main/java/org/apache/bval/ src/main/j...

Added: bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/util/NodeImpl.java
URL: http://svn.apache.org/viewvc/bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/util/NodeImpl.java?rev=1517540&view=auto
==============================================================================
--- bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/util/NodeImpl.java (added)
+++ bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/util/NodeImpl.java Mon Aug 26 13:59:15 2013
@@ -0,0 +1,369 @@
+/*
+ * 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.util;
+
+import javax.validation.ElementKind;
+import javax.validation.Path;
+import javax.validation.Path.Node;
+import java.io.Serializable;
+import java.util.List;
+import java.util.Map;
+
+public class NodeImpl implements Path.Node, Serializable {
+
+    private static final long serialVersionUID = 1L;
+    private static final String INDEX_OPEN = "[";
+    private static final String INDEX_CLOSE = "]";
+    private List<Class<?>> parameterTypes;
+
+    /**
+     * Append a Node to the specified StringBuilder.
+     * @param node
+     * @param to
+     * @return to
+     */
+    public static StringBuilder appendNode(Node node, StringBuilder to) {
+        if (node.isInIterable()) {
+            to.append(INDEX_OPEN);
+            if (node.getIndex() != null) {
+                to.append(node.getIndex());
+            } else if (node.getKey() != null) {
+                to.append(node.getKey());
+            }
+            to.append(INDEX_CLOSE);
+        }
+        if (node.getName() != null) {
+            if (to.length() > 0) {
+                to.append(PathImpl.PROPERTY_PATH_SEPARATOR);
+            }
+            to.append(node.getName());
+        }
+        return to;
+    }
+
+    /**
+     * Get a NodeImpl indexed from the preceding node (or root).
+     * @param index
+     * @return NodeImpl
+     */
+    public static NodeImpl atIndex(Integer index) {
+        NodeImpl result = new NodeImpl();
+        result.setIndex(index);
+        return result;
+    }
+
+    /**
+     * Get a NodeImpl keyed from the preceding node (or root).
+     * @param key
+     * @return NodeImpl
+     */
+    public static NodeImpl atKey(Object key) {
+        NodeImpl result = new NodeImpl();
+        result.setKey(key);
+        return result;
+    }
+
+    private String name;
+    private boolean inIterable;
+    private Integer index;
+    private int parameterIndex;
+    private Object key;
+    private ElementKind kind;
+
+    /**
+     * Create a new NodeImpl instance.
+     * @param name
+     */
+    public  NodeImpl(String name) {
+        this.name = name;
+    }
+
+    /**
+     * Create a new NodeImpl instance.
+     * @param node
+     */
+    NodeImpl(Path.Node node) {
+        this.name = node.getName();
+        this.inIterable = node.isInIterable();
+        this.index = node.getIndex();
+        this.key = node.getKey();
+        this.kind = node.getKind();
+    }
+
+    private NodeImpl() {
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * @param name the name to set
+     */
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isInIterable() {
+        return inIterable;
+    }
+
+    /**
+     * Set whether this node represents a contained value of an {@link Iterable} or {@link Map}.
+     * @param inIterable
+     */
+    public void setInIterable(boolean inIterable) {
+        this.inIterable = inIterable;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Integer getIndex() {
+        return index;
+    }
+
+    /**
+     * Set the index of this node, implying <code>inIterable</code>.
+     * @param index
+     */
+    public void setIndex(Integer index) {
+        inIterable = true;
+        this.index = index;
+        this.key = null;
+    }
+
+    public void setParameterIndex(final Integer parameterIndex) {
+        this.parameterIndex = parameterIndex;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Object getKey() {
+        return key;
+    }
+
+    /**
+     * Set the map key of this node, implying <code>inIterable</code>.
+     * @param key
+     */
+    public void setKey(Object key) {
+        inIterable = true;
+        this.key = key;
+        this.index = null;
+    }
+
+    public ElementKind getKind() {
+        return kind;
+    }
+
+    public void setKind(ElementKind kind) {
+        this.kind = kind;
+    }
+
+    public <T extends Node> T as(final Class<T> nodeType) {
+        if (nodeType.isInstance(this)) {
+            return nodeType.cast(this);
+        }
+        throw new ClassCastException("Type " + nodeType + " not supported");
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String toString() {
+        return appendNode(this, new StringBuilder()).toString();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+
+        NodeImpl node = (NodeImpl) o;
+
+        if (inIterable != node.inIterable) {
+            return false;
+        }
+        if (index != null ? !index.equals(node.index) : node.index != null) {
+            return false;
+        }
+        if (key != null ? !key.equals(node.key) : node.key != null) {
+            return false;
+        }
+        if (name != null ? !name.equals(node.name) : node.name != null) {
+            return false;
+        }
+        if (kind != null ? !kind.equals(node.kind) : node.kind != null) {
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode() {
+        int result = name != null ? name.hashCode() : 0;
+        result = 31 * result + (inIterable ? 1 : 0);
+        result = 31 * result + (index != null ? index.hashCode() : 0);
+        result = 31 * result + (key != null ? key.hashCode() : 0);
+        result = 31 * result + (kind != null ? kind.hashCode() : 0);
+        return result;
+    }
+
+    public int getParameterIndex() {
+        return parameterIndex;
+    }
+
+    public List<Class<?>> getParameterTypes() {
+        return parameterTypes;
+    }
+
+    public void setParameterTypes(final List<Class<?>> parameterTypes) {
+        this.parameterTypes = parameterTypes;
+    }
+
+    public static class ParameterNodeImpl extends NodeImpl implements Path.ParameterNode {
+        public ParameterNodeImpl(final Node cast) {
+            super(cast);
+            if (ParameterNodeImpl.class.isInstance(cast)) {
+                setParameterIndex(ParameterNodeImpl.class.cast(cast).getParameterIndex());
+            }
+        }
+
+        public ParameterNodeImpl(final String name, final int idx) {
+            super(name);
+            setParameterIndex(idx);
+        }
+
+        public ElementKind getKind() {
+            return ElementKind.PARAMETER;
+        }
+    }
+
+    public static class ConstructorNodeImpl extends NodeImpl implements Path.ConstructorNode {
+        public ConstructorNodeImpl(final Node cast) {
+            super(cast);
+            if (NodeImpl.class.isInstance(cast)) {
+                setParameterTypes(NodeImpl.class.cast(cast).parameterTypes);
+            }
+        }
+
+        public ConstructorNodeImpl(final String simpleName, List<Class<?>> paramTypes) {
+            super(simpleName);
+            setParameterTypes(paramTypes);
+        }
+
+        public ElementKind getKind() {
+            return ElementKind.CONSTRUCTOR;
+        }
+    }
+
+    public static class CrossParameterNodeImpl extends NodeImpl implements Path.CrossParameterNode {
+        public CrossParameterNodeImpl() {
+            super("<cross-parameter>");
+        }
+
+        public CrossParameterNodeImpl(final Node cast) {
+            super(cast);
+        }
+
+        public ElementKind getKind() {
+            return ElementKind.CROSS_PARAMETER;
+        }
+    }
+
+    public static class MethodNodeImpl extends NodeImpl implements Path.MethodNode {
+        public MethodNodeImpl(final Node cast) {
+            super(cast);
+            if (MethodNodeImpl.class.isInstance(cast)) {
+                setParameterTypes(MethodNodeImpl.class.cast(cast).getParameterTypes());
+            }
+        }
+
+        public MethodNodeImpl(final String name, final List<Class<?>> classes) {
+            super(name);
+            setParameterTypes(classes);
+        }
+
+        public ElementKind getKind() {
+            return ElementKind.METHOD;
+        }
+    }
+
+    public static class ReturnValueNodeImpl extends NodeImpl implements Path.ReturnValueNode {
+        public ReturnValueNodeImpl(final Node cast) {
+            super(cast);
+        }
+
+        public ReturnValueNodeImpl() {
+            super("<return value>");
+        }
+
+        public ElementKind getKind() {
+            return ElementKind.RETURN_VALUE;
+        }
+    }
+
+    public static class PropertyNodeImpl extends NodeImpl implements Path.PropertyNode {
+        public PropertyNodeImpl(final String name) {
+            super(name);
+        }
+
+        public PropertyNodeImpl(final Node cast) {
+            super(cast);
+        }
+
+        public ElementKind getKind() {
+            return ElementKind.PROPERTY;
+        }
+    }
+
+    public static class BeanNodeImpl extends NodeImpl implements Path.BeanNode {
+        public BeanNodeImpl() {
+            // no-op
+        }
+
+        public BeanNodeImpl(final Node cast) {
+            super(cast);
+        }
+
+        public ElementKind getKind() {
+            return ElementKind.BEAN;
+        }
+    }
+}

Added: bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/util/PathImpl.java
URL: http://svn.apache.org/viewvc/bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/util/PathImpl.java?rev=1517540&view=auto
==============================================================================
--- bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/util/PathImpl.java (added)
+++ bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/util/PathImpl.java Mon Aug 26 13:59:15 2013
@@ -0,0 +1,362 @@
+/*
+ * 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.util;
+
+import javax.validation.Path;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Description: object holding the property path as a list of nodes.
+ * (Implementation partially based on reference implementation)
+ * <br/>
+ * This class is not synchronized.
+ * 
+ * @version $Rev: 1498347 $ $Date: 2013-07-01 12:06:18 +0200 (lun., 01 juil. 2013) $
+ */
+public class PathImpl implements Path, Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    static final String PROPERTY_PATH_SEPARATOR = ".";
+
+    /**
+     * Builds non-root paths from expressions.
+     */
+    private static class PathImplBuilder implements PathNavigation.Callback<PathImpl> {
+        PathImpl result = new PathImpl();
+
+        /**
+         * {@inheritDoc}
+         */
+        public void handleProperty(String name) {
+            result.addProperty(name);
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        public void handleIndexOrKey(String value) {
+            // with no context to guide us, we can only parse ints and fall back to String keys:
+            NodeImpl node;
+            try {
+                node = NodeImpl.atIndex(Integer.parseInt(value));
+            } catch (NumberFormatException e) {
+                node = NodeImpl.atKey(value);
+            }
+            result.addNode(node);
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        public PathImpl result() {
+            if (result.nodeList.isEmpty()) {
+                throw new IllegalStateException();
+            }
+            return result;
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        public void handleGenericInIterable() {
+            result.addNode(NodeImpl.atIndex(null));
+        }
+
+    }
+
+    private final List<Node> nodeList;
+
+    /**
+     * Returns a {@code Path} instance representing the path described by the given string. To create a root node the
+     * empty string should be passed. Note: This signature is to maintain pluggability with the RI impl.
+     * 
+     * @param propertyPath
+     *            the path as string representation.
+     * @return a {@code Path} instance representing the path described by the given string.
+     */
+    public static PathImpl createPathFromString(String propertyPath) {
+        if (propertyPath == null || propertyPath.length() == 0) {
+            return create();
+        }
+        return PathNavigation.navigateAndReturn(propertyPath, new PathImplBuilder());
+    }
+
+    /**
+     * Create a {@link PathImpl} instance representing the specified path.
+     *
+     * @return PathImpl
+     */
+    public static PathImpl create() {
+        final PathImpl path = new PathImpl();
+        final NodeImpl node = new NodeImpl.BeanNodeImpl();
+        path.addNode(node);
+        return path;
+    }
+
+    /**
+     * Copy another Path.
+     * 
+     * @param path
+     * @return new {@link PathImpl}
+     */
+    public static PathImpl copy(Path path) {
+        return path == null ? null : new PathImpl(path);
+    }
+
+    private PathImpl(Path path) {
+        this.nodeList = new ArrayList<Node>();
+        for (final Object aPath : path) {
+            nodeList.add(newNode(Node.class.cast(aPath)));
+        }
+    }
+
+    private static Node newNode(final Node cast) {
+        if (PropertyNode.class.isInstance(cast)) {
+            return new NodeImpl.PropertyNodeImpl(cast);
+        }
+        if (BeanNode.class.isInstance(cast)) {
+            return new NodeImpl.BeanNodeImpl(cast);
+        }
+        if (MethodNode.class.isInstance(cast)) {
+            return new NodeImpl.MethodNodeImpl(cast);
+        }
+        if (ConstructorNode.class.isInstance(cast)) {
+            return new NodeImpl.ConstructorNodeImpl(cast);
+        }
+        if (ConstructorNode.class.isInstance(cast)) {
+            return new NodeImpl.ConstructorNodeImpl(cast);
+        }
+        if (ReturnValueNode.class.isInstance(cast)) {
+            return new NodeImpl.ReturnValueNodeImpl(cast);
+        }
+        if (ParameterNode.class.isInstance(cast)) {
+            return new NodeImpl.ParameterNodeImpl(cast);
+        }
+        if (CrossParameterNode.class.isInstance(cast)) {
+            return new NodeImpl.CrossParameterNodeImpl(cast);
+        }
+        return new NodeImpl(cast);
+    }
+
+    private PathImpl() {
+        nodeList = new ArrayList<Node>();
+    }
+
+    private PathImpl(List<Node> nodeList) {
+        this.nodeList = new ArrayList<Node>();
+        for (Node node : nodeList) {
+            this.nodeList.add(new NodeImpl(node));
+        }
+    }
+
+    /**
+     * Learn whether this {@link PathImpl} points to the root of its graph.
+     * 
+     * @return true if no child nodes
+     */
+    // our implementation stores a nameless root node.
+    public boolean isRootPath() {
+        if (nodeList.size() != 1) {
+            return false;
+        }
+        Path.Node first = nodeList.get(0);
+        return !first.isInIterable() && first.getName() == null;
+    }
+
+    /**
+     * Return a new {@link PathImpl} that represents <code>this</code> minus its leaf node (if present).
+     * 
+     * @return PathImpl
+     */
+    public PathImpl getPathWithoutLeafNode() {
+        List<Node> nodes = new ArrayList<Node>(nodeList);
+        PathImpl path = null;
+        if (nodes.size() > 1) {
+            nodes.remove(nodes.size() - 1);
+            path = new PathImpl(nodes);
+        }
+        return path;
+    }
+
+    /**
+     * Add a node to this {@link PathImpl}.
+     * 
+     * @param node
+     *            to add
+     */
+    public void addNode(Node node) {
+        if (isRootPath()) {
+            nodeList.set(0, node);
+        } else {
+            nodeList.add(node);
+        }
+    }
+
+    /**
+     * Encapsulate the node manipulations needed to add a named property to this path.
+     * 
+     * @param name
+     */
+    public void addProperty(String name) {
+        if (!nodeList.isEmpty()) {
+            NodeImpl leaf = getLeafNode();
+            if (leaf != null && leaf.isInIterable() && leaf.getName() == null) { // TODO: avoid to be here
+                if (!PropertyNode.class.isInstance(leaf)) {
+                    final NodeImpl tmp = new NodeImpl.PropertyNodeImpl(leaf);
+                    removeLeafNode();
+                    addNode(tmp);
+                    leaf = tmp;
+                }
+                leaf.setName(name);
+                return;
+            }
+        }
+
+        final NodeImpl node;
+        if ("<cross-parameter>".equals(name)) {
+            node = new NodeImpl.CrossParameterNodeImpl();
+        } else {
+            node = new NodeImpl.PropertyNodeImpl(name);
+        }
+        addNode(node);
+
+    }
+
+    /**
+     * Trim the leaf node from this {@link PathImpl}.
+     * 
+     * @return the node removed
+     * @throws IllegalStateException
+     *             if no nodes are found
+     */
+    public Node removeLeafNode() {
+        if (isRootPath() || nodeList.size() == 0) {
+            throw new IllegalStateException("No nodes in path!");
+        }
+        try {
+            return nodeList.remove(nodeList.size() - 1);
+        } finally {
+            if (nodeList.isEmpty()) {
+                nodeList.add(new NodeImpl((String) null));
+            }
+        }
+    }
+
+    /**
+     * Get the leaf node (if any) from this {@link PathImpl}
+     * 
+     * @return {@link NodeImpl}
+     */
+    public NodeImpl getLeafNode() {
+        if (nodeList.size() == 0) {
+            return null;
+        }
+        return (NodeImpl) nodeList.get(nodeList.size() - 1);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Iterator<Path.Node> iterator() {
+        return nodeList.iterator();
+    }
+
+    /**
+     * Learn whether <code>path</code> is a parent to <code>this</code>.
+     * 
+     * @param path
+     * @return <code>true</code> if our nodes begin with nodes equal to those found in <code>path</code>
+     */
+    public boolean isSubPathOf(Path path) {
+        if (path instanceof PathImpl && ((PathImpl) path).isRootPath()) {
+            return true;
+        }
+        Iterator<Node> pathIter = path.iterator();
+        Iterator<Node> thisIter = iterator();
+        while (pathIter.hasNext()) {
+            Node pathNode = pathIter.next();
+            if (!thisIter.hasNext()) {
+                return false;
+            }
+            Node thisNode = thisIter.next();
+            if (pathNode.isInIterable()) {
+                if (!thisNode.isInIterable()) {
+                    return false;
+                }
+                if (pathNode.getIndex() != null && !pathNode.getIndex().equals(thisNode.getIndex())) {
+                    return false;
+                }
+                if (pathNode.getKey() != null && !pathNode.getKey().equals(thisNode.getKey())) {
+                    return false;
+                }
+            } else if (thisNode.isInIterable()) {
+                // in this case we have shown that the proposed parent is not
+                // indexed, and we are, thus the paths cannot match
+                return false;
+            }
+            if (pathNode.getName() == null || pathNode.getName().equals(thisNode.getName())) {
+                continue;
+            }
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder();
+        for (Path.Node node : this) {
+            NodeImpl.appendNode(node, builder);
+        }
+        return builder.toString();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+
+        PathImpl path = (PathImpl) o;
+        return !(nodeList != null && !nodeList.equals(path.nodeList)) && !(nodeList == null && path.nodeList != null);
+
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode() {
+        return nodeList != null ? nodeList.hashCode() : 0;
+    }
+
+}

Added: bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/util/PathNavigation.java
URL: http://svn.apache.org/viewvc/bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/util/PathNavigation.java?rev=1517540&view=auto
==============================================================================
--- bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/util/PathNavigation.java (added)
+++ bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/util/PathNavigation.java Mon Aug 26 13:59:15 2013
@@ -0,0 +1,326 @@
+/*
+ *  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.util;
+
+import org.apache.commons.lang3.StringEscapeUtils;
+
+import javax.validation.ValidationException;
+import java.io.StringWriter;
+import java.text.ParsePosition;
+
+/**
+ * Defines a path navigation algorithm and a means of interacting with same.
+ * 
+ * @version $Rev: 1136233 $ $Date: 2011-06-15 17:49:27 -0500 (Wed, 15 Jun 2011) $
+ */
+public class PathNavigation {
+
+    /**
+     * Path traversal callback function interface.
+     */
+    public interface Callback<T> {
+        /**
+         * Handle a .-delimited property.
+         * 
+         * @param name
+         */
+        void handleProperty(String name);
+
+        /**
+         * Handle an index or key embedded in [].
+         * 
+         * @param value
+         */
+        void handleIndexOrKey(String value);
+
+        /**
+         * Handle contiguous [].
+         */
+        void handleGenericInIterable();
+
+        /**
+         * Return a result. Called after navigation is complete.
+         * 
+         * @return result
+         */
+        T result();
+    }
+
+    /**
+     * Callback "procedure" that always returns null.
+     */
+    public static abstract class CallbackProcedure implements Callback<Object> {
+
+        /**
+         * {@inheritDoc}
+         */
+        public final Object result() {
+            complete();
+            return null;
+        }
+
+        /**
+         * Complete this CallbackProcedure. Default implementation is noop.
+         */
+        protected void complete() {
+        }
+    }
+
+    /**
+     * Create a new PathNavigation instance.
+     */
+    private PathNavigation() {
+    }
+
+    /**
+     * Navigate a path using the specified callback, returning its result.
+     * 
+     * @param <T>
+     * @param propertyPath
+     *            , null is assumed empty/root
+     * @param callback
+     * @return T result
+     */
+    public static <T> T navigateAndReturn(CharSequence propertyPath, Callback<? extends T> callback) {
+        try {
+            parse(propertyPath == null ? "" : propertyPath, new PathPosition(callback));
+        } catch (ValidationException ex) {
+            throw ex;
+        } catch (Exception ex) {
+            throw new ValidationException(String.format("invalid property: %s", propertyPath), ex);
+        }
+        return callback.result();
+    }
+
+    /**
+     * Navigate a path using the specified callback.
+     * 
+     * @param propertyPath
+     * @param callback
+     */
+    public static void navigate(CharSequence propertyPath, Callback<?> callback) {
+        navigateAndReturn(propertyPath, callback);
+    }
+
+    private static void parse(CharSequence path, PathPosition pos) throws Exception {
+        int len = path.length();
+        boolean sep = true;
+        while (pos.getIndex() < len) {
+            int here = pos.getIndex();
+            char c = path.charAt(here);
+            switch (c) {
+            case ']':
+                throw new IllegalStateException(String.format("Position %s: unexpected '%s'", here, c));
+            case '[':
+                handleIndex(path, pos.next());
+                break;
+            case '.':
+                if (sep) {
+                    throw new IllegalStateException(String.format("Position %s: expected property, index/key, or end of expression", here));
+                }
+                sep = true;
+                pos.next();
+                // fall through:
+            default:
+                if (!sep) {
+                    throw new IllegalStateException(String.format("Position %s: expected property path separator, index/key, or end of expression", here));
+                }
+                pos.handleProperty(parseProperty(path, pos));
+            }
+            sep = false;
+        }
+    }
+
+    private static String parseProperty(CharSequence path, PathPosition pos) throws Exception {
+        int len = path.length();
+        int start = pos.getIndex();
+        loop: while (pos.getIndex() < len) {
+            switch (path.charAt(pos.getIndex())) {
+            case '[':
+            case ']':
+            case '.':
+                break loop;
+            }
+            pos.next();
+        }
+        if (pos.getIndex() > start) {
+            return path.subSequence(start, pos.getIndex()).toString();
+        }
+        throw new IllegalStateException(String.format("Position %s: expected property", start));
+    }
+
+    /**
+     * Handles an index/key. If the text contained between [] is surrounded by a pair of " or ', it will be treated as a
+     * string which may contain Java escape sequences.
+     * 
+     * @param path
+     * @param pos
+     * @throws Exception
+     */
+    private static void handleIndex(CharSequence path, PathPosition pos) throws Exception {
+        int len = path.length();
+        int start = pos.getIndex();
+        if (start < len) {
+            char first = path.charAt(pos.getIndex());
+            if (first == '"' || first == '\'') {
+                String s = parseQuotedString(path, pos);
+                if (s != null && path.charAt(pos.getIndex()) == ']') {
+                    pos.handleIndexOrKey(s);
+                    pos.next();
+                    return;
+                }
+            }
+            // no quoted string; match ] greedily
+            while (pos.getIndex() < len) {
+                int here = pos.getIndex();
+                try {
+                    if (path.charAt(here) == ']') {
+                        if (here == start) {
+                            pos.handleGenericInIterable();
+                        } else {
+                            pos.handleIndexOrKey(path.subSequence(start, here).toString());
+                        }
+                        return;
+                    }
+                } finally {
+                    pos.next();
+                }
+            }
+        }
+        throw new IllegalStateException(String.format("Position %s: unparsable index", start));
+    }
+
+    private static String parseQuotedString(CharSequence path, PathPosition pos) throws Exception {
+        int len = path.length();
+        int start = pos.getIndex();
+        if (start < len) {
+            char quote = path.charAt(start);
+            pos.next();
+            StringWriter w = new StringWriter();
+            while (pos.getIndex() < len) {
+                int here = pos.getIndex();
+                // look for matching quote
+                if (path.charAt(here) == quote) {
+                    pos.next();
+                    return w.toString();
+                }
+                int codePoints = StringEscapeUtils.UNESCAPE_JAVA.translate(path, here, w);
+                if (codePoints == 0) {
+                    w.write(Character.toChars(Character.codePointAt(path, here)));
+                    pos.next();
+                } else {
+                    for (int i = 0; i < codePoints; i++) {
+                        pos.plus(Character.charCount(Character.codePointAt(path, pos.getIndex())));
+                    }
+                }
+            }
+            // if reached, reset due to no ending quote found
+            pos.setIndex(start);
+        }
+        return null;
+    }
+
+    /**
+     * ParsePosition/Callback
+     */
+    private static class PathPosition extends ParsePosition implements Callback<Object> {
+        final Callback<?> delegate;
+
+        /**
+         * Create a new {@link PathPosition} instance.
+         * 
+         * @param delegate
+         */
+        private PathPosition(Callback<?> delegate) {
+            super(0);
+            this.delegate = delegate;
+        }
+
+        /**
+         * Increment and return this.
+         * 
+         * @return this
+         */
+        public PathPosition next() {
+            return plus(1);
+        }
+
+        /**
+         * Increase position and return this.
+         * 
+         * @param addend
+         * @return this
+         */
+        public PathPosition plus(int addend) {
+            setIndex(getIndex() + addend);
+            return this;
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        public void handleProperty(String name) {
+            delegate.handleProperty(name);
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        public void handleIndexOrKey(String value) {
+            delegate.handleIndexOrKey(value);
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        public void handleGenericInIterable() {
+            delegate.handleGenericInIterable();
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        public Object result() {
+            return null;
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        /*
+         * Override equals to make findbugs happy;
+         * would simply ignore but doesn't seem to be possible at the inner class level
+         * without attaching the filter to the containing class.
+         */
+        @Override
+        public boolean equals(Object obj) {
+            return super.equals(obj);
+        }
+        
+        /**
+         * {@inheritDoc}
+         */
+        /*
+         * Override hashCode to make findbugs happy in the presence of overridden #equals :P
+         */
+        @Override
+        public int hashCode() {
+            return super.hashCode();
+        }
+    }
+
+}

Added: bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/util/Proxies.java
URL: http://svn.apache.org/viewvc/bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/util/Proxies.java?rev=1517540&view=auto
==============================================================================
--- bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/util/Proxies.java (added)
+++ bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/util/Proxies.java Mon Aug 26 13:59:15 2013
@@ -0,0 +1,33 @@
+/*
+ * 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.util;
+
+public final class Proxies {
+    // get rid of proxies which probably contains wrong annotation metamodel
+    public static <T> Class<?> classFor(final Class<?> clazz) { // TODO: do we want a SPI with impl for guice, owb, openejb, ...?
+        if (!clazz.getSimpleName().contains("$$")) { // a lot of proxies use this convention to avoid conflicts with inner/anonymous classes
+            return clazz;
+        }
+        return classFor(clazz.getSuperclass());
+    }
+
+    private Proxies() {
+        // no-op
+    }
+}

Added: bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/util/ValidationContextTraversal.java
URL: http://svn.apache.org/viewvc/bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/util/ValidationContextTraversal.java?rev=1517540&view=auto
==============================================================================
--- bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/util/ValidationContextTraversal.java (added)
+++ bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/util/ValidationContextTraversal.java Mon Aug 26 13:59:15 2013
@@ -0,0 +1,204 @@
+/*
+ * 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.util;
+
+import org.apache.bval.DynamicMetaBean;
+import org.apache.bval.jsr.JsrMetaBeanFactory;
+import org.apache.bval.jsr.UnknownPropertyException;
+import org.apache.bval.jsr.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;
+
+import java.lang.reflect.Type;
+
+/**
+ * {@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 = JsrMetaBeanFactory.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)));
+        }
+    }
+}
\ No newline at end of file

Added: bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/xml/AnnotationIgnores.java
URL: http://svn.apache.org/viewvc/bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/xml/AnnotationIgnores.java?rev=1517540&view=auto
==============================================================================
--- bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/xml/AnnotationIgnores.java (added)
+++ bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/xml/AnnotationIgnores.java Mon Aug 26 13:59:15 2013
@@ -0,0 +1,200 @@
+/*
+ * 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.xml;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Member;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * Description: This class instantiated during the parsing of the XML configuration
+ * data and keeps track of the annotations which should be ignored.<br/>
+ */
+public final class AnnotationIgnores {
+
+    private static final Logger log = Logger.getLogger(AnnotationIgnores.class.getName());
+
+    /**
+     * Keeps track whether the 'ignore-annotations' flag is set on bean level in the
+     * xml configuration. 
+     * If 'ignore-annotations' is not specified: default = true
+     */
+    private final Map<Class<?>, Boolean> ignoreAnnotationDefaults = new HashMap<Class<?>, Boolean>();
+
+    /**
+     * Keeps track of explicitly excluded members (fields and properties) for a given class.
+     * If a member appears in
+     * the list mapped to a given class 'ignore-annotations' was explicitly set to
+     * <code>true</code> in the configuration
+     * for this class.
+     */
+    private final Map<Class<?>, Map<Member, Boolean>> ignoreAnnotationOnMember = new HashMap<Class<?>, Map<Member, Boolean>>();
+
+    private final Map<Class<?>, Boolean> ignoreAnnotationOnClass = new HashMap<Class<?>, Boolean>();
+
+    private final Map<Class<?>, Map<Member, Map<Integer, Boolean>>> ignoreAnnotationOnParameter = new HashMap<Class<?>, Map<Member, Map<Integer, Boolean>>>();
+    private final Map<Member, Boolean> ignoreAnnotationOnReturn = new HashMap<Member, Boolean>();
+    private final Map<Member, Boolean> ignoreAnnotationOnCrossParameter = new HashMap<Member, Boolean>();
+
+    /**
+     * Record the ignore state for a particular annotation type.
+     * @param clazz
+     * @param b, default true if null
+     */
+    public void setDefaultIgnoreAnnotation(Class<?> clazz, Boolean b) {
+        ignoreAnnotationDefaults.put(clazz, b == null || b.booleanValue());
+    }
+
+    /**
+     * Learn whether the specified annotation type should be ignored.
+     * @param clazz
+     * @return boolean
+     */
+    public boolean getDefaultIgnoreAnnotation(Class<?> clazz) {
+        return ignoreAnnotationDefaults.containsKey(clazz)
+                && ignoreAnnotationDefaults.get(clazz);
+    }
+
+    /**
+     * Ignore annotations on a particular {@link Member} of a class.
+     * @param member
+     */
+    public void setIgnoreAnnotationsOnMember(Member member, boolean value) {
+        Class<?> beanClass = member.getDeclaringClass();
+        Map<Member, Boolean> memberList = ignoreAnnotationOnMember.get(beanClass);
+        if (memberList == null) {
+            memberList = new HashMap<Member, Boolean>();
+            ignoreAnnotationOnMember.put(beanClass, memberList);
+        }
+        memberList.put(member, value);
+    }
+
+    /**
+     * Learn whether annotations should be ignored on a particular {@link Member} of a class.
+     * @param member
+     * @return boolean
+     */
+    public boolean isIgnoreAnnotations(final Member member) {
+        final Class<?> clazz = member.getDeclaringClass();
+        final Map<Member, Boolean> ignoreAnnotationForMembers = ignoreAnnotationOnMember.get(clazz);
+        if (ignoreAnnotationForMembers != null && ignoreAnnotationForMembers.containsKey(member)) {
+            final boolean value = ignoreAnnotationForMembers.get(member);
+            if (value) {
+                logMessage(member, clazz);
+            }
+            return value;
+        }
+
+        final boolean ignoreAnnotation = getDefaultIgnoreAnnotation(clazz);
+        if (ignoreAnnotation) {
+            logMessage(member, clazz);
+        }
+        return ignoreAnnotation;
+    }
+
+    public void setIgnoreAnnotationsOnParameter(final Member method, final int i, final boolean value) {
+        final Class<?> beanClass = method.getDeclaringClass();
+        Map<Member, Map<Integer, Boolean>> memberList = ignoreAnnotationOnParameter.get(beanClass);
+        if (memberList == null) {
+            memberList = new HashMap<Member, Map<Integer, Boolean>>();
+            ignoreAnnotationOnParameter.put(beanClass, memberList);
+        }
+        Map<Integer, Boolean> indexes = memberList.get(method);
+        if (indexes == null) {
+            indexes = new HashMap<Integer, Boolean>();
+            memberList.put(method, indexes);
+        }
+        indexes.put(i, value);
+    }
+
+    public boolean isIgnoreAnnotationOnParameter(final Member m, final int i) {
+        final Map<Member, Map<Integer, Boolean>> members = ignoreAnnotationOnParameter.get(m.getDeclaringClass());
+        if (members != null) {
+            final Map<Integer, Boolean> indexes = members.get(m);
+            if (indexes != null && indexes.containsKey(i)) {
+                return indexes.get(i);
+            }
+        }
+        return false;
+    }
+
+    private void logMessage(Member member, Class<?> clazz) {
+        String type;
+        if (member instanceof Field) {
+            type = "Field";
+        } else {
+            type = "Property";
+        }
+        log.log(Level.FINEST, String.format("%s level annotations are getting ignored for %s.%s", type, clazz.getName(), member.getName()));
+    }
+
+    /**
+     * Record the ignore state of a particular class. 
+     * @param clazz
+     * @param b
+     */
+    public void setIgnoreAnnotationsOnClass(Class<?> clazz, boolean b) {
+        ignoreAnnotationOnClass.put(clazz, b);
+    }
+
+    /**
+     * Learn whether annotations should be ignored for a given class.
+     * @param clazz to check
+     * @return boolean
+     */
+    public boolean isIgnoreAnnotations(Class<?> clazz) {
+        boolean ignoreAnnotation;
+        if (ignoreAnnotationOnClass.containsKey(clazz)) {
+            ignoreAnnotation = ignoreAnnotationOnClass.get(clazz);
+        } else {
+            ignoreAnnotation = getDefaultIgnoreAnnotation(clazz);
+        }
+        if (ignoreAnnotation) {
+        	log.log(Level.FINEST, String.format("Class level annotation are getting ignored for %s", clazz.getName()));
+        }
+        return ignoreAnnotation;
+    }
+
+    public void setIgnoreAnnotationOnReturn(final Member method, final boolean value) {
+        ignoreAnnotationOnReturn.put(method, value);
+    }
+
+    public boolean isIgnoreAnnotationOnReturn(final Member m) {
+        final Boolean value = ignoreAnnotationOnReturn.get(m);
+        if (value != null) {
+            return value;
+        }
+        return false;
+    }
+
+    public void setIgnoreAnnotationOnCrossParameter(final Member method, final boolean value) {
+        ignoreAnnotationOnCrossParameter.put(method, value);
+    }
+
+    public boolean isIgnoreAnnotationOnCrossParameter(final Member m) {
+        final Boolean value = ignoreAnnotationOnCrossParameter.get(m);
+        if (value != null) {
+            return value;
+        }
+        return false;
+    }
+}

Added: bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/xml/AnnotationProxy.java
URL: http://svn.apache.org/viewvc/bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/xml/AnnotationProxy.java?rev=1517540&view=auto
==============================================================================
--- bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/xml/AnnotationProxy.java (added)
+++ bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/xml/AnnotationProxy.java Mon Aug 26 13:59:15 2013
@@ -0,0 +1,113 @@
+/*
+ *  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.xml;
+
+import javax.validation.Valid;
+import java.io.Serializable;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+/**
+ * Description: <br/>
+ * InvocationHandler implementation of <code>Annotation</code> that pretends it
+ * is a "real" source code annotation.
+ * <p/>
+ */
+class AnnotationProxy implements Annotation, InvocationHandler, Serializable {
+
+    /** Serialization version */
+    private static final long serialVersionUID = 1L;
+
+    private final Class<? extends Annotation> annotationType;
+    private final Map<String, Object> values;
+
+    /**
+     * Create a new AnnotationProxy instance.
+     * 
+     * @param <A>
+     * @param descriptor
+     */
+    public <A extends Annotation> AnnotationProxy(AnnotationProxyBuilder<A> descriptor) {
+        this.annotationType = descriptor.getType();
+        values = getAnnotationValues(descriptor);
+    }
+
+    private <A extends Annotation> Map<String, Object> getAnnotationValues(AnnotationProxyBuilder<A> descriptor) {
+        final Map<String, Object> result = new HashMap<String, Object>();
+        int processedValuesFromDescriptor = 0;
+        for (final Method m : descriptor.getMethods()) {
+            if (descriptor.contains(m.getName())) {
+                result.put(m.getName(), descriptor.getValue(m.getName()));
+                processedValuesFromDescriptor++;
+            } else if (m.getDefaultValue() != null) {
+                result.put(m.getName(), m.getDefaultValue());
+            } else {
+                throw new IllegalArgumentException("No value provided for " + m.getName());
+            }
+        }
+        if (processedValuesFromDescriptor != descriptor.size()
+                && !Valid.class.equals(annotationType)) {
+            throw new RuntimeException("Trying to instanciate " + annotationType + " with unknown paramters.");
+        }
+        return result;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+        if (values.containsKey(method.getName())) {
+            return values.get(method.getName());
+        }
+        return method.invoke(this, args);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Class<? extends Annotation> annotationType() {
+        return annotationType;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String toString() {
+        StringBuilder result = new StringBuilder();
+        result.append('@').append(annotationType().getName()).append('(');
+        boolean comma = false;
+        for (String m : getMethodsSorted()) {
+            if (comma)
+                result.append(", ");
+            result.append(m).append('=').append(values.get(m));
+            comma = true;
+        }
+        result.append(")");
+        return result.toString();
+    }
+
+    private SortedSet<String> getMethodsSorted() {
+        SortedSet<String> result = new TreeSet<String>();
+        result.addAll(values.keySet());
+        return result;
+    }
+}

Added: bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/xml/AnnotationProxyBuilder.java
URL: http://svn.apache.org/viewvc/bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/xml/AnnotationProxyBuilder.java?rev=1517540&view=auto
==============================================================================
--- bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/xml/AnnotationProxyBuilder.java (added)
+++ bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/xml/AnnotationProxyBuilder.java Mon Aug 26 13:59:15 2013
@@ -0,0 +1,256 @@
+/*
+ *  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.xml;
+
+import org.apache.bval.jsr.ConstraintAnnotationAttributes;
+import org.apache.bval.util.reflection.Reflection;
+
+import javax.validation.Payload;
+import javax.validation.Valid;
+import javax.validation.ValidationException;
+import javax.validation.groups.ConvertGroup;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+/**
+ * Description: Holds the information and creates an annotation proxy during xml
+ * parsing of validation mapping constraints. <br/>
+ */
+// TODO move this guy up to org.apache.bval.jsr or
+// org.apache.bval.jsr.model
+final public class AnnotationProxyBuilder<A extends Annotation> {
+    private static final ConcurrentMap<Class<?>, Method[]> METHODS_CACHE = new ConcurrentHashMap<Class<?>, Method[]>();
+
+    private final Class<A> type;
+    private final Map<String, Object> elements = new HashMap<String, Object>();
+    private final Method[] methods;
+
+    /**
+     * Create a new AnnotationProxyBuilder instance.
+     *
+     * @param annotationType
+     */
+    public AnnotationProxyBuilder(final Class<A> annotationType) {
+        this.type = annotationType;
+        this.methods = findMethods(annotationType);
+    }
+
+    public static <A> Method[] findMethods(final Class<A> annotationType) {
+        if (annotationType.getName().startsWith("javax.validation.constraints.")) { // cache built-in constraints only to avoid mem leaks
+            Method[] mtd = METHODS_CACHE.get(annotationType);
+            if (mtd == null) {
+                final Method[] value = Reflection.INSTANCE.getDeclaredMethods(annotationType);
+                mtd = METHODS_CACHE.putIfAbsent(annotationType, value);
+                if (mtd == null) {
+                    mtd = value;
+                }
+            }
+            return mtd;
+        }
+        return Reflection.INSTANCE.getDeclaredMethods(annotationType);
+    }
+
+    /**
+     * Create a new AnnotationProxyBuilder instance.
+     *
+     * @param annotationType
+     * @param elements
+     */
+    public AnnotationProxyBuilder(Class<A> annotationType, Map<String, Object> elements) {
+        this(annotationType);
+        for (Map.Entry<String, Object> entry : elements.entrySet()) {
+            this.elements.put(entry.getKey(), entry.getValue());
+        }
+    }
+
+    /**
+     * Create a builder initially configured to create an annotation equivalent
+     * to <code>annot</code>.
+     * 
+     * @param annot Annotation to be replicated.
+     */
+    @SuppressWarnings("unchecked")
+    public AnnotationProxyBuilder(A annot) {
+        this((Class<A>) annot.annotationType());
+        // Obtain the "elements" of the annotation
+        for (Method m : methods) {
+            if (!m.isAccessible()) {
+                m.setAccessible(true);
+            }
+            try {
+                Object value = m.invoke(annot);
+                this.elements.put(m.getName(), value);
+            } catch (IllegalArgumentException e) {
+                // No args, so should not happen
+                throw new ValidationException("Cannot access annotation " + annot + " element: " + m.getName());
+            } catch (IllegalAccessException e) {
+                throw new ValidationException("Cannot access annotation " + annot + " element: " + m.getName());
+            } catch (InvocationTargetException e) {
+                throw new ValidationException("Cannot access annotation " + annot + " element: " + m.getName());
+            }
+        }
+    }
+
+    public Method[] getMethods() {
+        return methods;
+    }
+
+    /**
+     * Add an element to the configuration.
+     *
+     * @param elementName
+     * @param value
+     */
+    public void putValue(String elementName, Object value) {
+        elements.put(elementName, value);
+    }
+
+    /**
+     * Get the specified element value from the current configuration.
+     *
+     * @param elementName
+     * @return Object value
+     */
+    public Object getValue(String elementName) {
+        return elements.get(elementName);
+    }
+
+    /**
+     * Learn whether a given element has been configured.
+     *
+     * @param elementName
+     * @return <code>true</code> if an <code>elementName</code> element is found
+     *         on this annotation
+     */
+    public boolean contains(String elementName) {
+        return elements.containsKey(elementName);
+    }
+
+    /**
+     * Get the number of configured elements.
+     *
+     * @return int
+     */
+    public int size() {
+        return elements.size();
+    }
+
+    /**
+     * Get the configured Annotation type.
+     *
+     * @return Class<A>
+     */
+    public Class<A> getType() {
+        return type;
+    }
+
+    /**
+     * Configure the well-known JSR303 "message" element.
+     *
+     * @param message
+     */
+    public void setMessage(String message) {
+        ConstraintAnnotationAttributes.MESSAGE.put(elements, message);
+    }
+
+    /**
+     * Configure the well-known JSR303 "groups" element.
+     *
+     * @param groups
+     */
+    public void setGroups(Class<?>[] groups) {
+        ConstraintAnnotationAttributes.GROUPS.put(elements, groups);
+    }
+
+    /**
+     * Configure the well-known JSR303 "payload" element.
+     * 
+     * @param payload
+     */
+    public void setPayload(Class<? extends Payload>[] payload) {
+        ConstraintAnnotationAttributes.PAYLOAD.put(elements, payload);
+    }
+
+    /**
+     * Create the annotation represented by this builder.
+     *
+     * @return {@link Annotation}
+     */
+    public A createAnnotation() {
+        ClassLoader classLoader = Reflection.INSTANCE.getClassLoader(getType());
+        @SuppressWarnings("unchecked")
+        final Class<A> proxyClass = (Class<A>) Proxy.getProxyClass(classLoader, getType());
+        final InvocationHandler handler = new AnnotationProxy(this);
+        if (System.getSecurityManager() == null) {
+            return doCreateAnnotation(proxyClass, handler);
+        }
+        return AccessController.doPrivileged(new PrivilegedAction<A>() {
+            public A run() {
+                return doCreateAnnotation(proxyClass, handler);
+            }
+        });
+    }
+
+    private A doCreateAnnotation(final Class<A> proxyClass, final InvocationHandler handler) {
+        try {
+            Constructor<A> constructor = proxyClass.getConstructor(InvocationHandler.class);
+            return constructor.newInstance(handler);
+        } catch (Exception e) {
+            throw new ValidationException("Unable to create annotation for configured constraint", e);
+        }
+    }
+
+    public static final class ValidAnnotation implements Valid {
+        public static final ValidAnnotation INSTANCE = new ValidAnnotation();
+
+        public Class<? extends Annotation> annotationType() {
+            return Valid.class;
+        }
+    }
+
+    public static final class ConverGroupAnnotation implements ConvertGroup {
+        private final Class<?> from;
+        private final Class<?> to;
+
+        public ConverGroupAnnotation(final Class<?> from, final Class<?> to) {
+            this.from = from;
+            this.to = to;
+        }
+
+        public Class<? extends Annotation> annotationType() {
+            return ConvertGroup.class;
+        }
+
+        public Class<?> from() {
+            return from;
+        }
+
+        public Class<?> to() {
+            return to;
+        }
+    }
+}

Added: bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/xml/MetaConstraint.java
URL: http://svn.apache.org/viewvc/bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/xml/MetaConstraint.java?rev=1517540&view=auto
==============================================================================
--- bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/xml/MetaConstraint.java (added)
+++ bval/branches/bval-11/bval-jsr/src/main/java/org/apache/bval/jsr/xml/MetaConstraint.java Mon Aug 26 13:59:15 2013
@@ -0,0 +1,124 @@
+/*
+ *  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.xml;
+
+
+import org.apache.bval.ConstructorAccess;
+import org.apache.bval.util.AccessStrategy;
+import org.apache.bval.util.FieldAccess;
+import org.apache.bval.util.MethodAccess;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Member;
+import java.lang.reflect.Method;
+
+/**
+ * Description: hold parsed information from xml to complete MetaBean later<br/>
+ */
+//TODO move this guy up to org.apache.bval.jsr or org.apache.bval.jsr.model
+//to decouple ApacheValidatorFactory from xml package and allow others to consume MetaConstraint
+public class MetaConstraint<T, A extends Annotation> {
+
+    /** The member the constraint was defined on. */
+    private final Member member;
+
+    /** The class of the bean hosting this constraint. */
+    private final Class<T> beanClass;
+
+    /** constraint annotation (proxy) */
+    private final A annotation;
+
+    private Integer index; // for parameters
+
+    private final AccessStrategy accessStrategy;
+
+    /**
+     * Create a new MetaConstraint instance.
+     * @param beanClass The class in which the constraint is defined on
+     * @param member    The member on which the constraint is defined on, {@code null} if it is a class constraint}
+     * @param annotation
+     */
+    public MetaConstraint(Class<T> beanClass, Member member, A annotation) {
+        this.member = member;
+        this.beanClass = beanClass;
+        this.annotation = annotation;
+        if (member != null) {
+            accessStrategy = createAccessStrategy(member);
+            /*TODO: see if can really be removed
+            if (accessStrategy == null || accessStrategy.getPropertyName() == null) { // can happen if method does not follow the bean convention
+                throw new ValidationException("Annotated method does not follow the JavaBeans naming convention: " + member);
+            }
+            */
+        } else {
+            this.accessStrategy = null;
+        }
+    }
+
+    private static AccessStrategy createAccessStrategy(Member member) {
+        if (member instanceof Method) {
+            return new MethodAccess((Method) member);
+        } else if (member instanceof Field) {
+            return new FieldAccess((Field) member);
+        } else if (member instanceof Constructor<?>) {
+            return new ConstructorAccess((Constructor<?>) member);
+        } else {
+            return null; // class level
+        }
+    }
+
+    /**
+     * Get the bean class of this constraint.
+     * @return Class
+     */
+    public Class<T> getBeanClass() {
+        return beanClass;
+    }
+
+    /**
+     * Get the member to which this constraint applies.
+     * @return Member
+     */
+    public Member getMember() {
+        return member;
+    }
+
+    /**
+     * Get the annotation that defines this constraint.
+     * @return Annotation
+     */
+    public A getAnnotation() {
+        return annotation;
+    }
+
+    /**
+     * Get the access strategy used for the associated property.
+     * @return {@link AccessStrategy}
+     */
+    public AccessStrategy getAccessStrategy() {
+        return accessStrategy;
+    }
+
+    public Integer getIndex() {
+        return index;
+    }
+
+    public void setIndex(final int index) {
+        this.index = index;
+    }
+}