162 lines
4.5 KiB
Java
162 lines
4.5 KiB
Java
/*
|
|
* Copyright 2006-2013 the original author or authors.
|
|
*
|
|
* 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 org.springframework.classify;
|
|
|
|
import java.io.Serializable;
|
|
import java.util.Comparator;
|
|
import java.util.HashMap;
|
|
import java.util.Map;
|
|
import java.util.Set;
|
|
import java.util.TreeSet;
|
|
import java.util.concurrent.ConcurrentHashMap;
|
|
import java.util.concurrent.ConcurrentMap;
|
|
|
|
/**
|
|
* A {@link Classifier} for a parameterised object type based on a map.
|
|
* Classifies objects according to their inheritance relation with the supplied
|
|
* type map. If the object to be classified is one of the keys of the provided
|
|
* map, or is a subclass of one of the keys, then the map entry value for that
|
|
* key is returned. Otherwise returns the default value which is null by
|
|
* default.
|
|
*
|
|
* @author Dave Syer
|
|
* @author Gary Russell
|
|
*
|
|
*/
|
|
public class SubclassClassifier<T, C> implements Classifier<T, C> {
|
|
|
|
private ConcurrentMap<Class<? extends T>, C> classified = new ConcurrentHashMap<Class<? extends T>, C>();
|
|
|
|
private C defaultValue = null;
|
|
|
|
/**
|
|
* Create a {@link SubclassClassifier} with null default value.
|
|
*
|
|
*/
|
|
public SubclassClassifier() {
|
|
this(null);
|
|
}
|
|
|
|
/**
|
|
* Create a {@link SubclassClassifier} with supplied default value.
|
|
*
|
|
* @param defaultValue the default value
|
|
*/
|
|
public SubclassClassifier(C defaultValue) {
|
|
this(new HashMap<Class<? extends T>, C>(), defaultValue);
|
|
}
|
|
|
|
/**
|
|
* Create a {@link SubclassClassifier} with supplied default value.
|
|
*
|
|
* @param defaultValue the default value
|
|
* @param typeMap the map of types
|
|
*/
|
|
public SubclassClassifier(Map<Class<? extends T>, C> typeMap, C defaultValue) {
|
|
super();
|
|
this.classified = new ConcurrentHashMap<Class<? extends T>, C>(typeMap);
|
|
this.defaultValue = defaultValue;
|
|
}
|
|
|
|
/**
|
|
* Public setter for the default value for mapping keys that are not found
|
|
* in the map (or their subclasses). Defaults to false.
|
|
*
|
|
* @param defaultValue the default value to set
|
|
*/
|
|
public void setDefaultValue(C defaultValue) {
|
|
this.defaultValue = defaultValue;
|
|
}
|
|
|
|
/**
|
|
* Set the classifications up as a map. The keys are types and these will be
|
|
* mapped along with all their subclasses to the corresponding value. The
|
|
* most specific types will match first.
|
|
*
|
|
* @param map a map from type to class
|
|
*/
|
|
public void setTypeMap(Map<Class<? extends T>, C> map) {
|
|
this.classified = new ConcurrentHashMap<Class<? extends T>, C>(map);
|
|
}
|
|
|
|
/**
|
|
* Return the value from the type map whose key is the class of the given
|
|
* Throwable, or its nearest ancestor if a subclass.
|
|
*
|
|
* @return C the classified value
|
|
* @param classifiable the classifiable thing
|
|
*/
|
|
public C classify(T classifiable) {
|
|
|
|
if (classifiable == null) {
|
|
return defaultValue;
|
|
}
|
|
|
|
@SuppressWarnings("unchecked")
|
|
Class<? extends T> exceptionClass = (Class<? extends T>) classifiable.getClass();
|
|
if (classified.containsKey(exceptionClass)) {
|
|
return classified.get(exceptionClass);
|
|
}
|
|
|
|
// check for subclasses
|
|
Set<Class<? extends T>> classes = new TreeSet<Class<? extends T>>(new ClassComparator());
|
|
classes.addAll(classified.keySet());
|
|
for (Class<? extends T> cls : classes) {
|
|
if (cls.isAssignableFrom(exceptionClass)) {
|
|
C value = classified.get(cls);
|
|
this.classified.put(exceptionClass, value);
|
|
return value;
|
|
}
|
|
}
|
|
|
|
return defaultValue;
|
|
}
|
|
|
|
/**
|
|
* Return the default value supplied in the constructor (default false).
|
|
*
|
|
* @return C the default value
|
|
*/
|
|
final public C getDefault() {
|
|
return defaultValue;
|
|
}
|
|
|
|
protected Map<Class<? extends T>, C> getClassified() {
|
|
return classified;
|
|
}
|
|
|
|
/**
|
|
* Comparator for classes to order by inheritance.
|
|
*
|
|
* @author Dave Syer
|
|
*
|
|
*/
|
|
@SuppressWarnings("serial")
|
|
private static class ClassComparator implements Comparator<Class<?>>, Serializable {
|
|
/**
|
|
* @return 1 if arg0 is assignable from arg1, -1 otherwise
|
|
* @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
|
|
*/
|
|
public int compare(Class<?> arg0, Class<?> arg1) {
|
|
if (arg0.isAssignableFrom(arg1)) {
|
|
return 1;
|
|
}
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
}
|