/* * Copyright 2012 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.BeanMetadata; import de.knightsoftnet.validators.client.impl.metadata.ValidationGroupsMetadata; import java.lang.annotation.ElementType; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import javax.validation.groups.Default; import javax.validation.metadata.ConstraintDescriptor; import javax.validation.metadata.ElementDescriptor.ConstraintFinder; import javax.validation.metadata.Scope; /** * Finds constraints declared on an element using specified criteria. */ public final class ConstraintFinderImpl implements ConstraintFinder { private final Set<ConstraintDescriptorImpl<?>> constraintDescriptors; private final ValidationGroupsMetadata validationGroupsMetadata; private List<Class<?>> groups; private final Set<ConstraintOrigin> definedInSet; private final Set<ElementType> elementTypes; private final BeanMetadata beanMetadata; /** * constructor. * * @param beanMetadata bean meta data to set * @param validationGroupsMetadata validation groups meta data * @param constraintDescriptors constraint descriptors */ public ConstraintFinderImpl(final BeanMetadata beanMetadata, final ValidationGroupsMetadata validationGroupsMetadata, final Set<ConstraintDescriptorImpl<?>> constraintDescriptors) { this.validationGroupsMetadata = validationGroupsMetadata; this.constraintDescriptors = constraintDescriptors; this.beanMetadata = beanMetadata; this.elementTypes = new HashSet<ElementType>(); this.elementTypes.add(ElementType.TYPE); this.elementTypes.add(ElementType.METHOD); this.elementTypes.add(ElementType.FIELD); this.definedInSet = new HashSet<ConstraintOrigin>(); this.definedInSet.add(ConstraintOrigin.DEFINED_LOCALLY); this.definedInSet.add(ConstraintOrigin.DEFINED_IN_HIERARCHY); this.groups = Collections.emptyList(); } @Override public ConstraintFinder declaredOn(final ElementType... types) { this.elementTypes.clear(); this.elementTypes.addAll(Arrays.asList(types)); return this; } @Override public Set<ConstraintDescriptor<?>> getConstraintDescriptors() { if (this.validationGroupsMetadata == null) { // sanity check - this could be null if the caller does not set group metadata first throw new IllegalStateException("ConstraintFinderImpl not initialized properly. A " + "ValidationGroupsMetadata object is required by GWT to properly find all constraint " + "descriptors."); } final Set<ConstraintDescriptor<?>> matchingDescriptors = new HashSet<ConstraintDescriptor<?>>(); this.findMatchingDescriptors(matchingDescriptors); return Collections.unmodifiableSet(matchingDescriptors); } @Override public boolean hasConstraints() { return !this.getConstraintDescriptors().isEmpty(); } @Override public ConstraintFinder lookingAt(final Scope scope) { if (scope.equals(Scope.LOCAL_ELEMENT)) { this.definedInSet.remove(ConstraintOrigin.DEFINED_IN_HIERARCHY); } return this; } @Override public ConstraintFinder unorderedAndMatchingGroups(final Class<?>... groups) { this.groups = new ArrayList<Class<?>>(); for (final Class<?> clazz : groups) { if (Default.class.equals(clazz) && this.beanMetadata.defaultGroupSequenceIsRedefined()) { this.groups.addAll(this.beanMetadata.getDefaultGroupSequence()); } else { this.groups.add(clazz); } } return this; } private void addMatchingDescriptorsForGroup(final Class<?> group, final Set<ConstraintDescriptor<?>> matchingDescriptors) { for (final ConstraintDescriptorImpl<?> descriptor : this.constraintDescriptors) { if (this.definedInSet.contains(descriptor.getDefinedOn()) && this.elementTypes.contains(descriptor.getElementType()) && descriptor.getGroups().contains(group)) { matchingDescriptors.add(descriptor); } } } private void findMatchingDescriptors(final Set<ConstraintDescriptor<?>> matchingDescriptors) { if (this.groups.isEmpty()) { for (final ConstraintDescriptorImpl<?> descriptor : this.constraintDescriptors) { if (this.definedInSet.contains(descriptor.getDefinedOn()) && this.elementTypes.contains(descriptor.getElementType())) { matchingDescriptors.add(descriptor); } } } else { final GroupChain groupChain = new GroupChainGenerator(this.validationGroupsMetadata).getGroupChainFor(this.groups); final Iterator<Group> groupIterator = groupChain.getGroupIterator(); while (groupIterator.hasNext()) { final Group g = groupIterator.next(); this.addMatchingDescriptorsForGroup(g.getGroup(), matchingDescriptors); } } } }