/* * Copyright 2010 Google Inc. Copyright 2016 Manfred Tremmel * * Licensed 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 de.knightsoftnet.validators.client.impl; import de.knightsoftnet.validators.client.impl.metadata.MessageAndPath; import org.hibernate.validator.internal.engine.path.NodeImpl; import org.hibernate.validator.internal.engine.path.PathImpl; import java.lang.annotation.Annotation; import java.util.HashSet; import java.util.Set; import javax.validation.ConstraintValidatorContext; import javax.validation.ConstraintValidatorContext.ConstraintViolationBuilder.LeafNodeBuilderCustomizableContext; import javax.validation.ConstraintValidatorContext.ConstraintViolationBuilder.NodeBuilderCustomizableContext; import javax.validation.ConstraintValidatorContext.ConstraintViolationBuilder.NodeBuilderDefinedContext; import javax.validation.ConstraintValidatorContext.ConstraintViolationBuilder.NodeContextBuilder; import javax.validation.ConstraintViolation; import javax.validation.metadata.ConstraintDescriptor; /** * GWT safe immutable implementation of {@link ConstraintValidatorContext} * <p> * These objects are very short lived. * </p> * * @param <A> the constraint being validated * @param <T> the type of object being validated */ public class ConstraintValidatorContextImpl<A extends Annotation, T> implements ConstraintValidatorContext { /** * Builder for {@link ConstraintValidatorContextImpl}. */ public final class ConstraintViolationBuilderImpl implements ConstraintViolationBuilder { private final ConstraintValidatorContextImpl<A, T> context; private final String messageTemplate; /** * constructor. * * @param constraintValidatorContextImpl context * @param messageTemplate message template */ public ConstraintViolationBuilderImpl( final ConstraintValidatorContextImpl<A, T> constraintValidatorContextImpl, final String messageTemplate) { this.context = constraintValidatorContextImpl; this.messageTemplate = messageTemplate; } @Override public ConstraintValidatorContext addConstraintViolation() { ConstraintValidatorContextImpl.this.messages .add(new MessageAndPath(this.context.basePath, this.messageTemplate)); return this.context; } @Override public NodeBuilderDefinedContext addNode(final String name) { this.context.basePath.addPropertyNode(name); return new NodeBuilderDefinedContextImpl(this, this.messageTemplate, this.context.basePath); } @Override public NodeBuilderCustomizableContext addPropertyNode(final String pname) { this.context.basePath.addPropertyNode(pname); return new NodeBuilderCustomizableContextImpl(this, this.messageTemplate, this.context.basePath); } @Override public LeafNodeBuilderCustomizableContext addBeanNode() { throw new UnsupportedOperationException("GWT Validation does not support addBeanNode()"); } @Override public NodeBuilderDefinedContext addParameterNode(final int pindex) { this.context.basePath.addParameterNode(null, pindex); return new NodeBuilderDefinedContextImpl(this, this.messageTemplate, this.context.basePath); } } /** * Immutable GWT safe {@link NodeBuilderCustomizableContext}. */ public final class NodeBuilderCustomizableContextImpl implements NodeBuilderCustomizableContext { private final String messageTemplate; private final ConstraintViolationBuilderImpl parent; private final PathImpl path; /** * constructor. * * @param parent ConstraintViolationBuilderImpl which is parent * @param messageTemplate message template * @param path path of the element */ public NodeBuilderCustomizableContextImpl(final ConstraintViolationBuilderImpl parent, final String messageTemplate, final PathImpl path) { super(); this.parent = parent; this.messageTemplate = messageTemplate; this.path = path; } @Override public ConstraintValidatorContext addConstraintViolation() { ConstraintValidatorContextImpl.this.messages .add(new MessageAndPath(this.path, this.messageTemplate)); return this.parent.context; } @Override public NodeBuilderCustomizableContext addNode(final String name) { this.path.addPropertyNode(name); return new NodeBuilderCustomizableContextImpl(this.parent, this.messageTemplate, this.path); } @Override public NodeBuilderCustomizableContext addPropertyNode(final String pname) { this.path.addPropertyNode(pname); return new NodeBuilderCustomizableContextImpl(this.parent, this.messageTemplate, this.path); } @Override public NodeContextBuilder inIterable() { return new NodeContextBuilderImpl(this.path, this.messageTemplate, this.parent); } @Override public LeafNodeBuilderCustomizableContext addBeanNode() { throw new UnsupportedOperationException("GWT Validation does not support addBeanNode()"); } } /** * Immutable GWT safe {@link NodeBuilderDefinedContext}. */ public final class NodeBuilderDefinedContextImpl implements NodeBuilderDefinedContext { private final String messageTemplate; private final ConstraintViolationBuilderImpl parent; private final PathImpl path; /** * constructor. * * @param parent ConstraintViolationBuilderImpl which is parent * @param messageTemplate message template * @param path path of the element */ public NodeBuilderDefinedContextImpl(final ConstraintViolationBuilderImpl parent, final String messageTemplate, final PathImpl path) { this.parent = parent; this.messageTemplate = messageTemplate; this.path = path; } @Override public ConstraintValidatorContext addConstraintViolation() { ConstraintValidatorContextImpl.this.messages .add(new MessageAndPath(this.path, this.messageTemplate)); return this.parent.context; } @Override public NodeBuilderCustomizableContext addNode(final String name) { this.path.addPropertyNode(name); return new NodeBuilderCustomizableContextImpl(this.parent, this.messageTemplate, this.path); } @Override public NodeBuilderCustomizableContext addPropertyNode(final String pname) { this.path.addPropertyNode(pname); return new NodeBuilderCustomizableContextImpl(this.parent, this.messageTemplate, this.path); } @Override public LeafNodeBuilderCustomizableContext addBeanNode() { throw new UnsupportedOperationException("GWT Validation does not support addBeanNode()"); } } /** * Immutable GWT safe {@link NodeContextBuilder}. */ public final class NodeContextBuilderImpl implements NodeContextBuilder { private final String messageTemplate; private final ConstraintViolationBuilderImpl parent; private final PathImpl path; /** * constructor. * * @param parent ConstraintViolationBuilderImpl which is parent * @param messageTemplate message template * @param path path of the element */ public NodeContextBuilderImpl(final PathImpl path, final String messageTemplate, final ConstraintViolationBuilderImpl parent) { super(); this.path = path; this.messageTemplate = messageTemplate; this.parent = parent; } @Override public ConstraintValidatorContext addConstraintViolation() { return null; } @Override public NodeBuilderCustomizableContext addNode(final String name) { this.path.addPropertyNode(name); return new NodeBuilderCustomizableContextImpl(this.parent, this.messageTemplate, this.path); } @Override public NodeBuilderCustomizableContext addPropertyNode(final String pname) { this.path.addPropertyNode(pname); return new NodeBuilderCustomizableContextImpl(this.parent, this.messageTemplate, this.path); } @Override public NodeBuilderDefinedContext atIndex(final Integer index) { this.path.addParameterNode(null, index.intValue()); return new NodeBuilderDefinedContextImpl(this.parent, this.messageTemplate, this.path); } @Override public NodeBuilderDefinedContext atKey(final Object key) { NodeImpl.setMapKey(this.path.getLeafNode(), key); return new NodeBuilderDefinedContextImpl(this.parent, this.messageTemplate, this.path); } @Override public LeafNodeBuilderCustomizableContext addBeanNode() { throw new UnsupportedOperationException("GWT Validation does not support addBeanNode()"); // this.path.addBeanNode(); // return new NodeBuilderCustomizableContextImpl(this.parent, this.messageTemplate, // this.path); } } private final PathImpl basePath; private final ConstraintDescriptor<A> descriptor; private boolean disableDefault; private final Set<ConstraintViolation<T>> violations = new HashSet<>(); private final HashSet<MessageAndPath> messages = new HashSet<>(); /** * constructor. * * @param path path of the element * @param descriptor constraint descriptor */ public ConstraintValidatorContextImpl(final PathImpl path, final ConstraintDescriptor<A> descriptor) { super(); this.basePath = path; this.descriptor = descriptor; } @Override public ConstraintViolationBuilder buildConstraintViolationWithTemplate( final String messageTemplate) { return new ConstraintViolationBuilderImpl(new ConstraintValidatorContextImpl<A, T>( PathImpl.createCopy(this.basePath), this.descriptor), messageTemplate); } @Override public void disableDefaultConstraintViolation() { this.disableDefault = true; } @Override public String getDefaultConstraintMessageTemplate() { return (String) this.descriptor.getAttributes().get("message"); } /** * getter for message and path. * * @return set which includes message and path */ public Set<MessageAndPath> getMessageAndPaths() { if (!this.disableDefault) { this.messages .add(new MessageAndPath(this.basePath, this.getDefaultConstraintMessageTemplate())); } return this.messages; } public Set<ConstraintViolation<T>> getViolations() { return this.violations; } @SuppressWarnings("hiding") @Override public <T> T unwrap(final Class<T> ptype) { throw new UnsupportedOperationException("GWT Validation does not support upwrap()"); } }