📄 classmapping.java
字号:
/*
* Created on Apr 5, 2005
*/
package org.flexdock.util;
import java.util.WeakHashMap;
/**
* This class manages associations between classes and object instances. It
* allows for mappings between a class and its subclasses and another associated
* class, or an associated instance of a class.
* <p>
* This class is useful for "handler" type logic in which a handler class must
* be mapped to the classes it is designed to handle. Consider the class
* hierarchy of {@code Foo}, {@code Bar}, and {@code Baz}, where {@code Bar}
* extends {@code Foo} and {@code Baz} extends {@code Bar}.
*
* <pre>
* Foo.class
* |-Bar.class
* |-Baz.class
* </pre>
*
* Each of these classes is ultimately a type of {@code Foo}. Some operation is
* performed on instances of {@code Foo} and a set of handler classes are used
* to handle different types of {@code Foo}. Adding a mapping between
* {@code Foo.class} and {@code Handler1.class} will create an association
* between {@code Foo} and all <i>strict, non-specific</i> subclasses of
* {@code Foo} and {@code Handler1.class}.
* <p>
* This means that given any instance of {@code Foo}, calling
* {@code getClassMapping(Object obj)} will return {@code Handler1.class} as the
* class responsible for handling the {@code Foo} instance. This includes
* {@code Bar} and {@code Baz}. All types of {@code Foo} now have a implicit
* association with {@code Handler1.class}
* <p>
* However, if this method is subsequently called with arguments of
* {@code Baz.class} and {@code Handler2.class}, then a <i>specific</i>
* subclass mapping has been introduced for {@code Baz}. Associations apply to
* the given class and <i>non-specific</i> subclasses. Thus, the
* {@code Handler1.class} association remains for {@code Foo} and {@code Bar},
* but no longer for {@code Baz}. Calling {@code getClassMapping(Object obj)}
* with an instance of {@code Baz} will now return {@code Handler2.class}.
*
* <pre>
* Foo.class ---------------> (maps to Handler1.class)
* |-Bar.class -----------> (maps to Handler1.class)
* |-Baz.class -------> (maps to Handler2.class)
* </pre>
*
* Polymorphic identity within the class association uses <i>strict</i>
* subclasses. This means that the {@code Handler1.class} mapping for
* {@code Foo}, {@code Bar}, and all non-specific subclasses will hold true.
* However, if {@code Foo} happens to implement the interface {@code Qwerty},
* the class mapping relationship will not hold true for all implementations of
* {@code Qwerty}. Only subclasses of {@code Foo}.
*
* <pre>
* Foo.class (implements Qwerty) ----------------> (maps to Handler1.class)
* |-Bar.class (implements Qwerty) ------------> (maps to Handler1.class)
* |-Baz.class (implements Qwerty) --------> (maps to Handler2.class)
* Asdf.class (implements Qwerty) ---------------> (maps to nothing)
* </pre>
*
* @author Christopher Butler
*/
public class ClassMapping {
private WeakHashMap classes;
private WeakHashMap instances;
private Class defaultClass;
private Object defaultInstance;
/**
* Creates a new {@code ClassMapping} instance with the specified default
* values. All calls to {@code getClassMapping(Class key)} for this
* {@code ClassMapping} in which a specific mapping cannot be found will
* return the specified {@code defaultClass}. All calls to
* {@code getClassInstance(Class key)} in which a specific mapping cannot be
* found will return the specified {@code defaultInstance}.
*
* @param defaultClass
* the default class used by this {@code ClassMapping}
* @param defaultInstance
* the default object instance used by this {@code ClassMapping}
*/
public ClassMapping(Class defaultClass, Object defaultInstance) {
this.defaultClass = defaultClass;
this.defaultInstance = defaultInstance;
classes = new WeakHashMap(4);
instances = new WeakHashMap(4);
}
/**
* Adds a mapping between the {@code Class} type of the specified
* {@code Object} and the specified {@code value}. This method calls
* {@code getClass()} on the specified {@code Object} and dispatches to
* {@code addClassMapping(Class key, Class value)}. If either {@code obj}
* or {@code value} are {@code null}, then this method returns with no
* action taken. The {@code value} class may later be retrieved by calling
* {@code getClassMapping(Class key)} using the specified {@code key} class ({@code obj.getClass()})
* or any subclass thereof for which a specific class mapping does not
* already exist.
*
* @param obj
* the {@code Object} whose {@code Class} will be mapped to the
* specified {@code value}.
* @param value
* the {@code Class} to be associated with the specified <b>key</b>
* @see #addClassMapping(Object, Class)
* @see #getClassMapping(Object)
* @see #getClassMapping(Class)
* @see #removeClassMapping(Object)
* @see #removeClassMapping(Class)
*/
public void addClassMapping(Object obj, Class value) {
Class key = obj == null ? null : obj.getClass();
addClassMapping(key, value);
}
/**
* Adds a mapping between the key {@code Class} and the specified
* {@code value}. If either {@code key} or {@code value} are {@code null},
* then this method returns with no action taken. This method creates an
* association between the specified {@code key} {@code Class} and all
* strict, non-specific subclasses and the specified {@code value}
* {@code Class}. The {@code value} class may later be retrieved by calling
* getClassMapping(Class key) using the specified {@code key} class or any
* subclass thereof for which a specific class mapping does not already
* exist.
*
* @param key
* the {@code Class} to be mapped to the specified {@code value}.
* @param value
* the {@code Class} to be associated with the specified <b>key</b>
* @see #addClassMapping(Class, Class, Object)
* @see #getClassMapping(Class)
* @see #removeClassMapping(Class)
*/
public void addClassMapping(Class key, Class value) {
addClassMapping(key, value, null);
}
/**
* Adds a mapping between the key {@code Class} and both the specified
* {@code value} and specified object instance.. If either {@code key} or
* {@code value} are {@code null}, then this method returns with no action
* taken. This method creates an association between the specified
* {@code key} {@code Class} and all strict, non-specific subclasses and the
* specified {@code value} {@code Class}. The {@code value} class may later
* be retrieved by calling {@code getClassMapping(Class key)} using the
* specified {@code key} class or any subclass thereof for which a specific
* class mapping does not already exist.
* <p>
* This method also creates an optional mapping between the {@code key} and
* a particular object instance, defined by the {@code instance} parameter.
* If {@code instance} is non-{@code null}, then a mapping is defined
* between {@code key} and all strict, non-specific subclasses and the
* object instance itself. The {@code instance} object may later be
* retrieved by calling {@code getClassInstance(Class key)} using the
* specified {@code key} class or any subclass thereof for which a specific
* instance mapping does not already exist. If {@code instance} is
* {@code null}, then no instance mapping is created.
*
* @param key
* the {@code Class} to be mapped to the specified {@code value}.
* @param value
* the {@code Class} to be associated with the specified <b>key</b>
* @param instance
* the object instance to be associated with the specified <b>key</b>
* @see #getClassMapping(Class)
* @see #getClassInstance(Class)
* @see #removeClassMapping(Class)
*/
public void addClassMapping(Class key, Class value, Object instance) {
if (key == null || value == null)
return;
synchronized (classes) {
classes.put(key, value);
}
if (instance != null) {
synchronized (instances) {
instances.put(key, instance);
}
}
}
/**
* Removes any existing class mappings for the {@code Class} type of the
* specified {@code Object}. This method calls {@code getClass()} on the
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -