public void validateAdditionalRules(ValidationErrors errors) { // all previous validations return no errors if (crossFieldValidate && errors.isEmpty()) { BeanValidation beanValidation = AppBeans.get(BeanValidation.NAME); Validator validator = beanValidation.getValidator(); Set<ConstraintViolation<Entity>> violations = validator.validate(getItem(), UiCrossFieldChecks.class); violations.stream() .filter(violation -> { Path propertyPath = violation.getPropertyPath(); Path.Node lastNode = Iterables.getLast(propertyPath); return lastNode.getKind() == ElementKind.BEAN; }) .forEach(violation -> errors.add(violation.getMessage())); } }
/** * Test of extractViolationInfoFromNode method, of class ConstraintServices. */ @Test public void testExtractViolationInfoFromNode() { System.out.println("extractViolationInfoFromNode"); Path.Node node = mock(Path.Node.class); when(node.getKind()).thenReturn(ElementKind.METHOD).thenReturn(ElementKind.PARAMETER).thenReturn(ElementKind.PROPERTY); when(node.getName()).thenReturn("arg0").thenReturn("prop"); doReturn(5).when(instance).getIndexFromArgname(anyString()); ConstraintViolation cv = new ConstraintViolation(); instance.extractViolationInfoFromNode(node, cv); assertThat(cv.getMessage()).isNull(); assertThat(cv.getIndex()).isEqualTo(0); assertThat(cv.getProp()).isNull(); cv = new ConstraintViolation(); instance.extractViolationInfoFromNode(node, cv); assertThat(cv.getMessage()).isNull(); assertThat(cv.getIndex()).isEqualTo(5); assertThat(cv.getProp()).isNull(); cv = new ConstraintViolation(); instance.extractViolationInfoFromNode(node, cv); assertThat(cv.getMessage()).isNull(); assertThat(cv.getIndex()).isEqualTo(0); assertThat(cv.getProp()).isEqualTo("prop"); }
/** * constructor, do not use. */ public NodeImpl(final String name, final NodeImpl parent, final boolean isIterable, final Integer index, final Object key, final ElementKind kind, final Class<?>[] parameterTypes, final Integer parameterIndex, final Object value, final Class<?> containerClass, final Integer typeArgumentIndex) { this.name = name; this.parent = parent; this.index = index; this.key = key; this.value = value; this.isIterableValue = isIterable; this.kind = kind; this.parameterTypes = parameterTypes; this.parameterIndex = parameterIndex; this.containerClass = containerClass; this.typeArgumentIndex = typeArgumentIndex; }
/** * create property node. * * @param name name of the node * @param parent parent node * @return new node implementation */ // TODO It would be nicer if we could return PropertyNode public static NodeImpl createPropertyNode(final String name, final NodeImpl parent) { return new NodeImpl( // name, // parent, // false, // null, // null, // ElementKind.PROPERTY, // EMPTY_CLASS_ARRAY, // null, // null, // null, // null // ); }
/** * create container element node. * * @param name name of the node * @param parent parent node * @return new node implementation */ public static NodeImpl createContainerElementNode(final String name, final NodeImpl parent) { return new NodeImpl( // name, // parent, // false, // null, // null, // ElementKind.CONTAINER_ELEMENT, // EMPTY_CLASS_ARRAY, // null, // null, // null, // null // ); }
/** * create parameter node. * * @param name name of the node * @param parent parent node * @return new node implementation */ public static NodeImpl createParameterNode(final String name, final NodeImpl parent, final int parameterIndex) { return new NodeImpl( // name, // parent, // false, // null, // null, // ElementKind.PARAMETER, // EMPTY_CLASS_ARRAY, // parameterIndex, // null, // null, // null // ); }
/** * create cross parameter node node. * * @param parent parent node * @return new node implementation */ public static NodeImpl createCrossParameterNode(final NodeImpl parent) { return new NodeImpl( // CROSS_PARAMETER_NODE_NAME, // parent, // false, // null, // null, // ElementKind.CROSS_PARAMETER, // EMPTY_CLASS_ARRAY, // null, // null, // null, // null // ); }
/** * create method node. * * @param name name of the node * @param parent parent node * @param parameterTypes parameter types * @return new node implementation */ public static NodeImpl createMethodNode(final String name, final NodeImpl parent, final Class<?>[] parameterTypes) { return new NodeImpl( // name, // parent, // false, // null, // null, // ElementKind.METHOD, // parameterTypes, // null, // null, // null, // null // ); }
/** * create constructor node. * * @param name name of the node * @param parent parent node * @param parameterTypes parameter types * @return new node implementation */ public static NodeImpl createConstructorNode(final String name, final NodeImpl parent, final Class<?>[] parameterTypes) { return new NodeImpl( // name, // parent, // false, // null, // null, // ElementKind.CONSTRUCTOR, // parameterTypes, // null, // null, // null, // null // ); }
/** * create return node. * * @param parent parent node * @return new node implementation */ public static NodeImpl createReturnValue(final NodeImpl parent) { return new NodeImpl( // RETURN_VALUE_NODE_NAME, // parent, // false, // null, // null, // ElementKind.RETURN_VALUE, // EMPTY_CLASS_ARRAY, // null, // null, // null, // null // ); }
@SuppressWarnings("unchecked") @Override public <T extends Path.Node> T as(final Class<T> nodeType) throws ClassCastException { // NOPMD if (this.kind == ElementKind.BEAN && nodeType == BeanNode.class || this.kind == ElementKind.CONSTRUCTOR && nodeType == ConstructorNode.class || this.kind == ElementKind.CROSS_PARAMETER && nodeType == CrossParameterNode.class || this.kind == ElementKind.METHOD && nodeType == MethodNode.class || this.kind == ElementKind.PARAMETER && nodeType == ParameterNode.class || this.kind == ElementKind.PROPERTY && (nodeType == PropertyNode.class || nodeType == org.hibernate.validator.path.PropertyNode.class) || this.kind == ElementKind.RETURN_VALUE && nodeType == ReturnValueNode.class || this.kind == ElementKind.CONTAINER_ELEMENT && (nodeType == ContainerElementNode.class || nodeType == org.hibernate.validator.path.ContainerElementNode.class)) { return (T) this; } throw LOG.getUnableToNarrowNodeTypeException(this.getClass(), this.kind, nodeType); }
/** * Determine the response status (400 or 500) from the given BV exception. * * @param violation BV exception. * @return response status (400 or 500). */ public static Response.Status getResponseStatus(final ConstraintViolationException violation) { final Iterator<ConstraintViolation<?>> iterator = violation.getConstraintViolations().iterator(); if (iterator.hasNext()) { for (final Path.Node node : iterator.next().getPropertyPath()) { final ElementKind kind = node.getKind(); if (ElementKind.RETURN_VALUE.equals(kind)) { return Response.Status.INTERNAL_SERVER_ERROR; } } } return Response.Status.BAD_REQUEST; }
@Override public ValidationErrorMessage createBody(ConstraintViolationException ex, HttpServletRequest req) { ErrorMessage tmpl = super.createBody(ex, req); ValidationErrorMessage msg = new ValidationErrorMessage(tmpl); for (ConstraintViolation<?> violation : ex.getConstraintViolations()) { Node pathNode = findLastNonEmptyPathNode(violation.getPropertyPath()); // path is probably useful only for properties (fields) if (pathNode != null && pathNode.getKind() == ElementKind.PROPERTY) { msg.addError(pathNode.getName(), convertToString(violation.getInvalidValue()), violation.getMessage()); // type level constraints etc. } else { msg.addError(violation.getMessage()); } } return msg; }
@Override public void beforeNode(Object obj, DescriptorPath path) { if (path.getHeadNode().getKind() != ElementKind.BEAN) { return; } BeanDescriptorNode node = path.getHeadNode().as(BeanDescriptorNode.class); Named named = ReflectionHelper.findAnnotation(node.getBean().getClass(), Named.class); Referenced referenced = ReflectionHelper.findAnnotation(node.getBean().getClass(), Referenced.class); if (referenced != null) { if (referenced.as().length == 0 && named == null) { throw new IllegalStateException("The @Referenced annotation requires the @Named to also exist."); } ReferenceType type = referenced.type(); references.put(type, path.onlyInclude(ElementKind.BEAN)); } }
private void callReferenceConstraints(Object obj, DescriptorPath path) { DescriptorNode node = path.getHeadNode(); for (ReferenceConstraint<T> constraint : constraints) { if (node.getClass().isAssignableFrom(constraint.getNodeType())) { continue; } Annotation annotation; Class<? extends Annotation> annClass = constraint.getAnnotationType(); if (node.getKind() == ElementKind.BEAN) { annotation = ReflectionHelper.findAnnotation(obj.getClass(), annClass); } else if (node.getKind() == ElementKind.PROPERTY) { Method method = node.as(PropertyNode.class).getMethod(); annotation = ReflectionHelper.findAnnotation(method, annClass); } else { throw new IllegalStateException(node.getKind() + " is an unsupported type."); } if (annotation == null) { continue; } this.violations.addAll(constraint.checkConstraint(annotation, obj, path, allowedRefs)); } }
private String printPropertyPath(Path path) { if (path == null) return "UNKNOWN"; String propertyPath = ""; Path.Node parameterNode = null; // Construct string representation of property path. // This will strip away any other nodes added by RESTEasy (method, parameter, ...). for (Path.Node node : path) { if (node.getKind() == ElementKind.PARAMETER) { parameterNode = node; } if (node.getKind() == ElementKind.PROPERTY) { if (!propertyPath.isEmpty()) { propertyPath += "."; } propertyPath += node; } } if (propertyPath.isEmpty() && parameterNode != null) { // No property path constructed, assume this is a validation failure on a request parameter. propertyPath = parameterNode.toString(); } return propertyPath; }
/** * Translate validated bean and root path into validated resource and * resource path. For example, embeddables belonging to an entity document * are mapped back to an entity violation and a proper path to the * embeddable attribute. * * @param violation to compute the reference * @return computaed reference */ private ResourceRef resolvePath(ConstraintViolation<?> violation) { Object resource = violation.getRootBean(); Object nodeObject = resource; ResourceRef ref = new ResourceRef(resource); Iterator<Node> iterator = violation.getPropertyPath().iterator(); while (iterator.hasNext()) { Node node = iterator.next(); // ignore methods/parameters if (node.getKind() == ElementKind.METHOD) { continue; } if (node.getKind() == ElementKind.PARAMETER) { resource = getParameterValue(node); nodeObject = resource; ref = new ResourceRef(resource); assertResource(resource); continue; } // visit list, set, map references nodeObject = ref.getNodeReference(nodeObject, node); ref.visitNode(nodeObject); // visit property nodeObject = ref.visitProperty(nodeObject, node); } return ref; }
public Object visitProperty(Object nodeObject, Node node) { Object next; if (node.getKind() == ElementKind.PROPERTY) { next = PropertyUtils.getProperty(nodeObject, node.getName()); } else if (node.getKind() == ElementKind.BEAN) { next = nodeObject; } else { throw new UnsupportedOperationException("unknown node: " + node); } if (node.getName() != null) { appendSeparator(); if (!isResource(nodeObject.getClass()) || isPrimaryKey(nodeObject.getClass(), node.getName())) { // continue along attributes path or primary key on root appendSourcePointer(node.getName()); } else if (isAssociation(nodeObject.getClass(), node.getName())) { appendSourcePointer("/data/relationships/"); appendSourcePointer(node.getName()); } else { appendSourcePointer("/data/attributes/"); appendSourcePointer(node.getName()); } } return next; }
@Override public ElementKind getKind() { if (path == null) { return ElementKind.BEAN; } else { return ElementKind.PROPERTY; } }
private String printPropertyPath(Path path) { if (path == null) { return "UNKNOWN"; } String propertyPath = ""; Path.Node parameterNode = null; // Construct string representation of property path. // This will strip away any other nodes added by RESTEasy (method, parameter, ...). for (Path.Node node : path) { if (node.getKind() == ElementKind.PARAMETER) { parameterNode = node; } if (node.getKind() == ElementKind.PROPERTY) { if (!propertyPath.isEmpty()) { propertyPath += "."; } propertyPath += node; } } if (propertyPath.isEmpty() && parameterNode != null) { // No property path constructed, assume this is a validation failure on a request parameter. propertyPath = parameterNode.toString(); } return propertyPath; }
@Override public String toString() { final StringBuilder b = new StringBuilder(); for (final Node node : nodes) { if (b.length() > 0 && node.getKind() == ElementKind.PROPERTY) { b.append('.'); } b.append(node.toString()); } return b.toString(); }
@Test public void testSimplePath() { final MinijaxPath path = new MinijaxPath(Arrays.asList(new MinijaxPropertyNode(0, "foo"))); assertEquals("foo", path.toString()); for (final Node node : path) { assertTrue(node.isInIterable()); assertNotNull(node.getName()); assertNull(node.getKey()); assertEquals(ElementKind.PROPERTY, node.getKind()); assertEquals(node, node.as(PropertyNode.class)); assertNull(node.as(PropertyNode.class).getContainerClass()); assertEquals(0, (int) node.as(PropertyNode.class).getTypeArgumentIndex()); } }
/** * Return the property path from the given validation error. */ private String getPropertyPath(final ConstraintViolation<?> error) { if (((PathImpl) error.getPropertyPath()).getLeafNode().getKind() == ElementKind.PARAMETER) { // JSR-349 - Parameter, drop parent context return ((PathImpl) error.getPropertyPath()).getLeafNode().getName(); } // JSR-303 - Bean violation return error.getPropertyPath().toString(); }
private static String constructJsonPath(Path path) { StringBuilder jsonPath = new StringBuilder("#"); path.forEach(pathComponent -> { if (pathComponent.getKind() == ElementKind.PROPERTY) { jsonPath.append("/").append(pathComponent.getName()); } }); return jsonPath.toString(); }
private Status getResponseStatus(final ConstraintViolation<?> violation) { for (Path.Node node : violation.getPropertyPath()) { ElementKind kind = node.getKind(); if (ElementKind.RETURN_VALUE.equals(kind)) { return Status.INTERNAL_SERVER_ERROR; } } return Status.BAD_REQUEST; }
public ValidationResponse(final ConstraintViolationException cause) { super(false, new ArrayList<>()); //noinspection ThrowableResultOfMethodCallIgnored checkNotNull(cause); Set<ConstraintViolation<?>> violations = cause.getConstraintViolations(); if (violations != null && !violations.isEmpty()) { for (ConstraintViolation<?> violation : violations) { List<String> entries = new ArrayList<>(); // iterate path to get the full path Iterator<Node> it = violation.getPropertyPath().iterator(); while (it.hasNext()) { Node node = it.next(); if (ElementKind.PROPERTY == node.getKind() || (ElementKind.PARAMETER == node.getKind() && !it.hasNext())) { if (node.getKey() != null) { entries.add(node.getKey().toString()); } entries.add(node.getName()); } } if (entries.isEmpty()) { if (messages == null) { messages = new ArrayList<>(); } messages.add(violation.getMessage()); } else { if (errors == null) { errors = new HashMap<>(); } errors.put(Joiner.on('.').join(entries), violation.getMessage()); } } } else if (cause.getMessage() != null) { messages = new ArrayList<>(); messages.add(cause.getMessage()); } }
protected String derivePropertyPathByNode(ConstraintViolation<Object> vio) { final StringBuilder sb = new StringBuilder(); final Path path = vio.getPropertyPath(); int elementCount = 0; for (Path.Node node : path) { if (node.isInIterable()) { // building e.g. "[0]" of seaList[0] Object nodeIndex = node.getIndex(); if (nodeIndex == null) { nodeIndex = node.getKey(); // null if e.g. iterable } sb.append("[").append(nodeIndex != null ? nodeIndex : "").append("]"); // e.g. [0] or [] } final String nodeName = node.getName(); if (nodeName != null && node.getKind() == ElementKind.PROPERTY) { // _/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/ // if e.g. // private List<@Required String> seaList; // then path is "seaList[0].<list element>" since Hibernate Validator-6.x // <list element> part is unneeded for property path of message so skip here // _/_/_/_/_/_/_/_/_/_/ if (!nodeName.startsWith("<")) { // except e.g. <list element> if (elementCount > 0) { sb.append("."); } sb.append(nodeName); ++elementCount; } } } return sb.toString(); // e.g. sea, sea.hangar, seaList[0], seaList[0].hangar }
void extractViolationInfoFromNode(Path.Node node, ConstraintViolation cv) { ElementKind kind = node.getKind(); logger.debug("Kind:{} Index:{} Key:{} Name:{}", kind, node.getIndex(), node.getKey(), node.getName()); if (ElementKind.PARAMETER.equals(kind)) { cv.setIndex(getIndexFromArgname(node.getName())); } else if (ElementKind.PROPERTY.equals(kind)) { cv.setProp(node.getName()); } }
/** * create bean node. * * @param parent parent node * @return new node implementation */ public static NodeImpl createBeanNode(final NodeImpl parent) { return new NodeImpl( // null, // parent, // false, // null, // null, // ElementKind.BEAN, EMPTY_CLASS_ARRAY, // null, // null, // null, // null // ); }
@Override public Class<?> getContainerClass() { Contracts.assertTrue( this.kind == ElementKind.BEAN || this.kind == ElementKind.PROPERTY || this.kind == ElementKind.CONTAINER_ELEMENT, "getContainerClass() may only be invoked for nodes of type ElementKind.BEAN, " + "ElementKind.PROPERTY or ElementKind.CONTAINER_ELEMENT."); if (this.parent == null) { return null; } return this.parent.containerClass; }
@Override public Integer getTypeArgumentIndex() { Contracts.assertTrue( this.kind == ElementKind.BEAN || this.kind == ElementKind.PROPERTY || this.kind == ElementKind.CONTAINER_ELEMENT, "getTypeArgumentIndex() may only be invoked for nodes of type ElementKind.BEAN, " + "ElementKind.PROPERTY or ElementKind.CONTAINER_ELEMENT."); if (this.parent == null) { return null; } return this.parent.typeArgumentIndex; }
public NodeImpl setLeafNodeValueIfRequired(final Object value) { // The value is only exposed for property and container element nodes if (this.currentLeafNode.getKind() == ElementKind.PROPERTY || this.currentLeafNode.getKind() == ElementKind.CONTAINER_ELEMENT) { this.requiresWriteableNodeList(); this.currentLeafNode = NodeImpl.setPropertyValue(this.currentLeafNode, value); this.nodeList.set(this.nodeList.size() - 1, this.currentLeafNode); // the property value is not part of the NodeImpl hashCode so we don't need to reset the // PathImpl hashCode } return this.currentLeafNode; }
public ClassCastException getUnableToNarrowNodeTypeException( final Class<? extends NodeImpl> pclass, final ElementKind pkind, final Class<?> pnodeType) { final ClassCastException result = new ClassCastException(); final StackTraceElement[] st = result.getStackTrace(); result.setStackTrace(Arrays.copyOfRange(st, 1, st.length)); return result; }
protected NodeImpl(final String pname, final org.hibernate.validator.internal.engine.path.NodeImpl pparent, final boolean pindexable, final Integer pindex, final Object pkey, final ElementKind pkind, final Class<?>[] pparameterTypes, final Integer pparameterIndex, final Object pvalue) { super(pname, pparent, pindexable, pindex, pkey, pkind, pparameterTypes, pparameterIndex, pvalue, null, null); }
private Map<String, ExecutableDescriptorImpl> getConstrainedMethodsAsDescriptors() { Map<String, ExecutableDescriptorImpl> constrainedMethodDescriptors = newHashMap(); for (ExecutableMetaData executableMetaData : executableMetaDataMap.values()) { if (executableMetaData.getKind() == ElementKind.METHOD && executableMetaData.isConstrained()) { constrainedMethodDescriptors.put(executableMetaData.getIdentifier(), executableMetaData.asDescriptor( defaultGroupSequenceIsRedefined(), getDefaultGroupSequence(null))); } } return constrainedMethodDescriptors; }
private Map<String, ConstructorDescriptor> getConstrainedConstructorsAsDescriptors() { Map<String, ConstructorDescriptor> constrainedMethodDescriptors = newHashMap(); for (ExecutableMetaData executableMetaData : executableMetaDataMap.values()) { if (executableMetaData.getKind() == ElementKind.CONSTRUCTOR && executableMetaData.isConstrained()) { constrainedMethodDescriptors.put(executableMetaData.getIdentifier(), executableMetaData.asDescriptor( defaultGroupSequenceIsRedefined(), getDefaultGroupSequence(null))); } } return constrainedMethodDescriptors; }
private SetMultimap<ReferenceType, String> getRelatedPaths(Object obj, DescriptorPath path) { SetMultimap<ReferenceType, String> refs = LinkedHashMultimap.create(); String additionalScope = ""; IncludeAdditionalReferences scope = ReflectionHelper.findAnnotation(obj.getClass(), IncludeAdditionalReferences.class); if (scope != null) { additionalScope = ReflectionHelper.propertyValueByName(obj, scope.value(), String.class); } DescriptorPath trimmedPath = path.onlyInclude(ElementKind.BEAN); for (Map.Entry<ReferenceType, DescriptorPath> entry : allRefs.entries()) { DescriptorPath refPath = entry.getValue(); DescriptorPath prefix = refPath.removeFromHead(); if (trimmedPath.equals(prefix) || (refPath.contains(additionalScope, ElementKind.BEAN))) { DescriptorNode headNode = refPath.getHeadNode(); boolean addedNames = false; if (ElementKind.BEAN.equals(headNode.getKind())) { Referenced referenced = ReflectionHelper.findAnnotation( ((BeanNode) headNode).getBean().getClass(), Referenced.class); if (null != referenced && referenced.as().length > 0) { for (String name : referenced.as()) { refs.put(entry.getKey(), name); } addedNames = true; } } if (!addedNames) { refs.put(entry.getKey(), headNode.getName()); } } } return refs; }
public DescriptorNodeImpl(String name, boolean iterable, Integer index, Object key, ElementKind kind) { this.name = name; this.iterable = iterable; this.index = index; this.key = key; this.kind = kind; }
public PropertyNode(String name, boolean iterable, Integer index, Method method) { super(name, iterable, index, null, ElementKind.PROPERTY); this.method = method; }
public BeanNode(String name, Object key, Object bean, boolean isNamed) { super(name, false, null, key, ElementKind.BEAN); this.isNamed = isNamed; this.bean = bean; }