org.apache.bval.jsr303.groups.GroupsComputer Maven / Gradle / Ivy
/*
* 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.groups;
import javax.validation.GroupDefinitionException;
import javax.validation.GroupSequence;
import javax.validation.ValidationException;
import javax.validation.groups.Default;
import java.util.*;
/**
* Description: compute group order, based on the RI behavior as to guarantee
* compatibility with interpretations of the spec.
* Implementation is thread-safe.
*/
public class GroupsComputer {
/** The default group array used in case any of the validate methods is called without a group. */
private static final Groups DEFAULT_GROUPS;
static {
DEFAULT_GROUPS = new GroupsComputer().computeGroups(Arrays.asList(getDefaultGroupArray()));
}
/**
* Get the default group array.
* @return {@link Default}.class
only
*/
public static Class>[] getDefaultGroupArray() {
return new Class>[] { Default.class };
}
/** caching resolved groups in a thread-safe map. */
private final Map, List> resolvedSequences = Collections
.synchronizedMap(new HashMap, List>());
/**
* Compute groups from an array of group classes.
* @param groups
* @return {@link Groups}
*/
public Groups computeGroups(Class>[] groups) {
if (groups == null) {
throw new IllegalArgumentException("null passed as group");
}
// if no groups is specified use the default
if (groups.length == 0) {
return DEFAULT_GROUPS;
}
return computeGroups(Arrays.asList(groups));
}
/**
* Main compute implementation.
* @param groups
* @return {@link Groups}
*/
protected Groups computeGroups(Collection> groups) {
if (groups == null || groups.size() == 0) {
throw new IllegalArgumentException("At least one group has to be specified.");
}
for (Class> clazz : groups) {
if (!clazz.isInterface()) {
throw new ValidationException(
"A group has to be an interface. " + clazz.getName() + " is not.");
}
}
Groups chain = new Groups();
for (Class> clazz : groups) {
GroupSequence anno = clazz.getAnnotation(GroupSequence.class);
if (anno == null) {
Group group = new Group(clazz);
chain.insertGroup(group);
insertInheritedGroups(clazz, chain);
} else {
insertSequence(clazz, anno, chain);
}
}
return chain;
}
private void insertInheritedGroups(Class> clazz, Groups chain) {
for (Class> extendedInterface : clazz.getInterfaces()) {
Group group = new Group(extendedInterface);
chain.insertGroup(group);
insertInheritedGroups(extendedInterface, chain);
}
}
private void insertSequence(Class> clazz, GroupSequence anno, Groups chain) {
List sequence;
if (resolvedSequences.containsKey(clazz)) {
sequence = resolvedSequences.get(clazz);
} else {
sequence = resolveSequence(clazz, anno, new HashSet>());
}
chain.insertSequence(sequence);
}
private List resolveSequence(Class> group, GroupSequence sequenceAnnotation,
Set> processedSequences) {
if (processedSequences.contains(group)) {
throw new GroupDefinitionException("Cyclic dependency in groups definition");
} else {
processedSequences.add(group);
}
List resolvedGroupSequence = new LinkedList();
Class>[] sequenceArray = sequenceAnnotation.value();
for (Class> clazz : sequenceArray) {
GroupSequence anno = clazz.getAnnotation(GroupSequence.class);
if (anno == null) {
resolvedGroupSequence.add(new Group(clazz)); // group part of sequence
} else {
List tmpSequence =
resolveSequence(clazz, anno, processedSequences); // recursion!
resolvedGroupSequence.addAll(tmpSequence);
}
}
resolvedSequences.put(group, resolvedGroupSequence);
return resolvedGroupSequence;
}
}