com.google.gwt.validation.rebind.Util Maven / Gradle / Ivy
/*
* Copyright 2010 Google Inc.
*
* 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 com.google.gwt.validation.rebind;
import com.google.gwt.thirdparty.guava.common.base.Function;
import com.google.gwt.thirdparty.guava.common.base.Functions;
import com.google.gwt.thirdparty.guava.common.base.Predicate;
import com.google.gwt.thirdparty.guava.common.collect.ImmutableList;
import com.google.gwt.thirdparty.guava.common.collect.ImmutableSet;
import com.google.gwt.thirdparty.guava.common.collect.Iterables;
import com.google.gwt.thirdparty.guava.common.collect.Lists;
import com.google.gwt.thirdparty.guava.common.collect.Sets;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
/**
* Static utilities for the validation rebind package.
*/
final class Util {
/**
* Creates a Predicate that returns false if source contains an associated
* class that is a super type of the class associated with the tested T.
*
* @param the type to test
* @param source the set of to look for class matches.
* @param toClass Function from T to Class
* @return newly create predicate.
*/
static Predicate createMostSpecificMatchPredicate(
final Iterable source, final Function> toClass) {
return new Predicate() {
@Override
public boolean apply(T input) {
Class> inputClass = toClass.apply(input);
for (Class> match : Iterables.transform(source, toClass)) {
if (!inputClass.equals(match) && inputClass.isAssignableFrom(match)) {
return false;
}
}
return true;
}
};
}
/**
* Selects first only the classes that are assignable from the target, and
* then returns the most specific matching classes.
*
* @param target the Class to match
* @param availableClasses classes to search
* @return Set of only the most specific classes that match the target.
*/
static Set> findBestMatches(Class> target,
Set> availableClasses) {
Set> matches = new HashSet>();
if (availableClasses.contains(target)) {
return ImmutableSet.> of(target);
} else {
for (Class> clazz : availableClasses) {
if (clazz.isAssignableFrom(target)) {
matches.add(clazz);
}
}
}
Predicate> moreSpecificClassPredicate = createMostSpecificMatchPredicate(
matches, Functions.> identity());
return Sets.filter(matches, moreSpecificClassPredicate);
}
/**
* Returns a Immutable List sorted with the most specific associated class
* first. Each element is guaranteed to not be assignable to any element that
* appears before it in the list.
*/
static ImmutableList sortMostSpecificFirst(Iterable classes,
Function> toClass) {
List working = Lists.newArrayList();
// strip duplicates
for (T t : classes) {
if (!working.contains(t)) {
working.add(t);
}
}
List sorted = Lists.newArrayList();
Predicate mostSpecific = createMostSpecificMatchPredicate(working,
toClass);
boolean changed = false;
do {
changed = false;
for (Iterator iterator = working.iterator(); iterator.hasNext();) {
T t = iterator.next();
if (mostSpecific.apply(t)) {
sorted.add(t);
iterator.remove();
changed = true;
}
}
} while (changed);
if (!working.isEmpty()) {
throw new IllegalStateException(
"Unable to find a element that does not have a more specific element in the set "
+ working);
}
return ImmutableList.copyOf(sorted);
}
private Util() {
}
}