Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.hibernate.validator.internal.engine.path.NodeImpl Maven / Gradle / Ivy
Go to download
Hibernate's Bean Validation (JSR-380) reference implementation.
/*
* Hibernate Validator, declare and validate application constraints
*
* License: Apache License, Version 2.0
* See the license.txt file in the root directory or .
*/
package org.hibernate.validator.internal.engine.path;
import java.io.Serializable;
import java.lang.invoke.MethodHandles;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import javax.validation.ElementKind;
import javax.validation.Path;
import javax.validation.Path.BeanNode;
import javax.validation.Path.ConstructorNode;
import javax.validation.Path.ContainerElementNode;
import javax.validation.Path.CrossParameterNode;
import javax.validation.Path.MethodNode;
import javax.validation.Path.ParameterNode;
import javax.validation.Path.PropertyNode;
import javax.validation.Path.ReturnValueNode;
import org.hibernate.validator.internal.util.Contracts;
import org.hibernate.validator.internal.util.TypeVariables;
import org.hibernate.validator.internal.util.logging.Log;
import org.hibernate.validator.internal.util.logging.LoggerFactory;
/**
* Immutable implementation of a {@code Path.Node}.
*
* @author Hardy Ferentschik
* @author Gunnar Morling
* @author Guillaume Smet
*/
public class NodeImpl
implements Path.PropertyNode, Path.MethodNode, Path.ConstructorNode, Path.BeanNode, Path.ParameterNode, Path.ReturnValueNode, Path.CrossParameterNode, Path.ContainerElementNode,
org.hibernate.validator.path.PropertyNode, org.hibernate.validator.path.ContainerElementNode, Serializable {
private static final long serialVersionUID = 2075466571633860499L;
private static final Class[] EMPTY_CLASS_ARRAY = new Class[]{};
private static final Log LOG = LoggerFactory.make( MethodHandles.lookup() );
private static final String INDEX_OPEN = "[";
private static final String INDEX_CLOSE = "]";
private static final String TYPE_PARAMETER_OPEN = "<";
private static final String TYPE_PARAMETER_CLOSE = ">";
public static final String RETURN_VALUE_NODE_NAME = "";
public static final String CROSS_PARAMETER_NODE_NAME = "";
public static final String ITERABLE_ELEMENT_NODE_NAME = "";
public static final String LIST_ELEMENT_NODE_NAME = "";
public static final String MAP_KEY_NODE_NAME = "";
public static final String MAP_VALUE_NODE_NAME = "";
private final String name;
private final NodeImpl parent;
private final boolean isIterable;
private final Integer index;
private final Object key;
private final ElementKind kind;
//type-specific attributes
private final Class[] parameterTypes;
private final Integer parameterIndex;
private final Object value;
private final Class containerClass;
private final Integer typeArgumentIndex;
private int hashCode = -1;
private String asString;
private NodeImpl(String name, NodeImpl parent, boolean isIterable, Integer index, Object key, ElementKind kind, Class[] parameterTypes,
Integer parameterIndex, Object value, Class containerClass, Integer typeArgumentIndex) {
this.name = name;
this.parent = parent;
this.index = index;
this.key = key;
this.value = value;
this.isIterable = isIterable;
this.kind = kind;
this.parameterTypes = parameterTypes;
this.parameterIndex = parameterIndex;
this.containerClass = containerClass;
this.typeArgumentIndex = typeArgumentIndex;
}
//TODO It would be nicer if we could return PropertyNode
public static NodeImpl createPropertyNode(String name, NodeImpl parent) {
return new NodeImpl(
name,
parent,
false,
null,
null,
ElementKind.PROPERTY,
EMPTY_CLASS_ARRAY,
null,
null,
null,
null
);
}
public static NodeImpl createContainerElementNode(String name, NodeImpl parent) {
return new NodeImpl(
name,
parent,
false,
null,
null,
ElementKind.CONTAINER_ELEMENT,
EMPTY_CLASS_ARRAY,
null,
null,
null,
null
);
}
public static NodeImpl createParameterNode(String name, NodeImpl parent, int parameterIndex) {
return new NodeImpl(
name,
parent,
false,
null,
null,
ElementKind.PARAMETER,
EMPTY_CLASS_ARRAY,
parameterIndex,
null,
null,
null
);
}
public static NodeImpl createCrossParameterNode(NodeImpl parent) {
return new NodeImpl(
CROSS_PARAMETER_NODE_NAME,
parent,
false,
null,
null,
ElementKind.CROSS_PARAMETER,
EMPTY_CLASS_ARRAY,
null,
null,
null,
null
);
}
public static NodeImpl createMethodNode(String name, NodeImpl parent, Class[] parameterTypes) {
return new NodeImpl( name, parent, false, null, null, ElementKind.METHOD, parameterTypes, null, null, null, null );
}
public static NodeImpl createConstructorNode(String name, NodeImpl parent, Class[] parameterTypes) {
return new NodeImpl( name, parent, false, null, null, ElementKind.CONSTRUCTOR, parameterTypes, null, null, null, null );
}
public static NodeImpl createBeanNode(NodeImpl parent) {
return new NodeImpl(
null,
parent,
false,
null,
null,
ElementKind.BEAN,
EMPTY_CLASS_ARRAY,
null,
null,
null,
null
);
}
public static NodeImpl createReturnValue(NodeImpl parent) {
return new NodeImpl(
RETURN_VALUE_NODE_NAME,
parent,
false,
null,
null,
ElementKind.RETURN_VALUE,
EMPTY_CLASS_ARRAY,
null,
null,
null,
null
);
}
public static NodeImpl makeIterable(NodeImpl node) {
return new NodeImpl(
node.name,
node.parent,
true,
null,
null,
node.kind,
node.parameterTypes,
node.parameterIndex,
node.value,
node.containerClass,
node.typeArgumentIndex
);
}
public static NodeImpl makeIterableAndSetIndex(NodeImpl node, Integer index) {
return new NodeImpl(
node.name,
node.parent,
true,
index,
null,
node.kind,
node.parameterTypes,
node.parameterIndex,
node.value,
node.containerClass,
node.typeArgumentIndex
);
}
public static NodeImpl makeIterableAndSetMapKey(NodeImpl node, Object key) {
return new NodeImpl(
node.name,
node.parent,
true,
null,
key,
node.kind,
node.parameterTypes,
node.parameterIndex,
node.value,
node.containerClass,
node.typeArgumentIndex
);
}
public static NodeImpl setPropertyValue(NodeImpl node, Object value) {
return new NodeImpl(
node.name,
node.parent,
node.isIterable,
node.index,
node.key,
node.kind,
node.parameterTypes,
node.parameterIndex,
value,
node.containerClass,
node.typeArgumentIndex
);
}
public static NodeImpl setTypeParameter(NodeImpl node, Class containerClass, Integer typeArgumentIndex) {
return new NodeImpl(
node.name,
node.parent,
node.isIterable,
node.index,
node.key,
node.kind,
node.parameterTypes,
node.parameterIndex,
node.value,
containerClass,
typeArgumentIndex
);
}
@Override
public final String getName() {
return name;
}
@Override
public final boolean isInIterable() {
return parent != null && parent.isIterable();
}
public final boolean isIterable() {
return isIterable;
}
@Override
public final Integer getIndex() {
if ( parent == null ) {
return null;
}
else {
return parent.index;
}
}
@Override
public final Object getKey() {
if ( parent == null ) {
return null;
}
else {
return parent.key;
}
}
@Override
public Class getContainerClass() {
Contracts.assertTrue(
kind == ElementKind.BEAN || kind == ElementKind.PROPERTY || kind == ElementKind.CONTAINER_ELEMENT,
"getContainerClass() may only be invoked for nodes of type ElementKind.BEAN, ElementKind.PROPERTY or ElementKind.CONTAINER_ELEMENT."
);
if ( parent == null ) {
return null;
}
return parent.containerClass;
}
@Override
public Integer getTypeArgumentIndex() {
Contracts.assertTrue(
kind == ElementKind.BEAN || kind == ElementKind.PROPERTY || kind == ElementKind.CONTAINER_ELEMENT,
"getTypeArgumentIndex() may only be invoked for nodes of type ElementKind.BEAN, ElementKind.PROPERTY or ElementKind.CONTAINER_ELEMENT."
);
if ( parent == null ) {
return null;
}
return parent.typeArgumentIndex;
}
public final NodeImpl getParent() {
return parent;
}
@Override
public ElementKind getKind() {
return kind;
}
@Override
public T as(Class nodeType) {
if ( ( kind == ElementKind.BEAN && nodeType == BeanNode.class ) ||
( kind == ElementKind.CONSTRUCTOR && nodeType == ConstructorNode.class ) ||
( kind == ElementKind.CROSS_PARAMETER && nodeType == CrossParameterNode.class ) ||
( kind == ElementKind.METHOD && nodeType == MethodNode.class ) ||
( kind == ElementKind.PARAMETER && nodeType == ParameterNode.class ) ||
( kind == ElementKind.PROPERTY && ( nodeType == PropertyNode.class || nodeType == org.hibernate.validator.path.PropertyNode.class ) ) ||
( kind == ElementKind.RETURN_VALUE && nodeType == ReturnValueNode.class ) ||
( kind == ElementKind.CONTAINER_ELEMENT
&& ( nodeType == ContainerElementNode.class || nodeType == org.hibernate.validator.path.ContainerElementNode.class ) ) ) {
return nodeType.cast( this );
}
throw LOG.getUnableToNarrowNodeTypeException( this.getClass(), kind, nodeType );
}
@Override
public List> getParameterTypes() {
return Arrays.asList( parameterTypes );
}
@Override
public int getParameterIndex() {
Contracts.assertTrue(
kind == ElementKind.PARAMETER,
"getParameterIndex() may only be invoked for nodes of type ElementKind.PARAMETER."
);
return parameterIndex.intValue();
}
@Override
public Object getValue() {
return value;
}
@Override
public String toString() {
return asString();
}
public final String asString() {
if ( asString == null ) {
asString = buildToString();
}
return asString;
}
private String buildToString() {
StringBuilder builder = new StringBuilder();
if ( getName() != null ) {
builder.append( getName() );
}
if ( includeTypeParameterInformation( containerClass, typeArgumentIndex ) ) {
builder.append( TYPE_PARAMETER_OPEN );
builder.append( TypeVariables.getTypeParameterName( containerClass, typeArgumentIndex ) );
builder.append( TYPE_PARAMETER_CLOSE );
}
if ( isIterable() ) {
builder.append( INDEX_OPEN );
if ( index != null ) {
builder.append( index );
}
else if ( key != null ) {
builder.append( key );
}
builder.append( INDEX_CLOSE );
}
return builder.toString();
}
// TODO: this is used to reduce the number of differences until we agree on the string representation
// it introduces some inconsistent behavior e.g. you get '' for a Multimap but not for a Map
private static boolean includeTypeParameterInformation(Class containerClass, Integer typeArgumentIndex) {
if ( containerClass == null || typeArgumentIndex == null ) {
return false;
}
if ( containerClass.getTypeParameters().length < 2 ) {
return false;
}
if ( Map.class.isAssignableFrom( containerClass ) && typeArgumentIndex == 1 ) {
return false;
}
return true;
}
public final int buildHashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ( ( index == null ) ? 0 : index.hashCode() );
result = prime * result + ( isIterable ? 1231 : 1237 );
result = prime * result + ( ( key == null ) ? 0 : key.hashCode() );
result = prime * result + ( ( kind == null ) ? 0 : kind.hashCode() );
result = prime * result + ( ( name == null ) ? 0 : name.hashCode() );
result = prime * result + ( ( parameterIndex == null ) ? 0 : parameterIndex.hashCode() );
result = prime * result + ( ( parameterTypes == null ) ? 0 : Arrays.hashCode( parameterTypes ) );
result = prime * result + ( ( containerClass == null ) ? 0 : containerClass.hashCode() );
result = prime * result + ( ( typeArgumentIndex == null ) ? 0 : typeArgumentIndex.hashCode() );
return result;
}
@Override
public int hashCode() {
if ( hashCode == -1 ) {
hashCode = buildHashCode();
}
return hashCode;
}
@Override
public boolean equals(Object obj) {
if ( this == obj ) {
return true;
}
if ( obj == null ) {
return false;
}
if ( getClass() != obj.getClass() ) {
return false;
}
NodeImpl other = (NodeImpl) obj;
if ( index == null ) {
if ( other.index != null ) {
return false;
}
}
else if ( !index.equals( other.index ) ) {
return false;
}
if ( isIterable != other.isIterable ) {
return false;
}
if ( key == null ) {
if ( other.key != null ) {
return false;
}
}
else if ( !key.equals( other.key ) ) {
return false;
}
if ( containerClass == null ) {
if ( other.containerClass != null ) {
return false;
}
}
else if ( !containerClass.equals( other.containerClass ) ) {
return false;
}
if ( typeArgumentIndex == null ) {
if ( other.typeArgumentIndex != null ) {
return false;
}
}
else if ( !typeArgumentIndex.equals( other.typeArgumentIndex ) ) {
return false;
}
if ( kind != other.kind ) {
return false;
}
if ( name == null ) {
if ( other.name != null ) {
return false;
}
}
else if ( !name.equals( other.name ) ) {
return false;
}
if ( parameterIndex == null ) {
if ( other.parameterIndex != null ) {
return false;
}
}
else if ( !parameterIndex.equals( other.parameterIndex ) ) {
return false;
}
if ( parameterTypes == null ) {
if ( other.parameterTypes != null ) {
return false;
}
}
else if ( !Arrays.equals( parameterTypes, other.parameterTypes ) ) {
return false;
}
return true;
}
}