All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.bval.jsr303.util.PathImpl Maven / Gradle / Ivy

There is a newer version: 4.0.1
Show newest version
/*
 * 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 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)
 * 
* This class is not synchronized. * * @version $Rev: 1166451 $ $Date: 2011-09-07 17:32:26 -0500 (Wed, 07 Sep 2011) $ */ 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 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 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(null); } return PathNavigation.navigateAndReturn(propertyPath, new PathImplBuilder()); } /** * Create a {@link PathImpl} instance representing the specified path. * * @param name * @return PathImpl */ public static PathImpl create(String name) { PathImpl path = new PathImpl(); NodeImpl node = new NodeImpl(name); 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(); for (Object aPath : path) { nodeList.add(new NodeImpl((Node) aPath)); } } private PathImpl() { nodeList = new ArrayList(); } private PathImpl(List nodeList) { this.nodeList = new ArrayList(); 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 this minus its leaf node (if present). * * @return PathImpl */ public PathImpl getPathWithoutLeafNode() { List nodes = new ArrayList(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) { leaf.setName(name); return; } } addNode(new NodeImpl(name)); } /** * 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 iterator() { return nodeList.iterator(); } /** * Learn whether path is a parent to this. * * @param path * @return true if our nodes begin with nodes equal to those found in path */ public boolean isSubPathOf(Path path) { if (path instanceof PathImpl && ((PathImpl) path).isRootPath()) { return true; } Iterator pathIter = path.iterator(); Iterator 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; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy