![JAR search and dependency download from the Maven repository](/logo.png)
it.tidalwave.metadata.spi.ClassMap Maven / Gradle / Ivy
The newest version!
/***********************************************************************************************************************
*
* blueMarine Metadata - open source media workflow
* Copyright (C) 2007-2011 by Tidalwave s.a.s. (http://www.tidalwave.it)
*
***********************************************************************************************************************
*
* 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.
*
***********************************************************************************************************************
*
* WWW: http://bluemarine.tidalwave.it
* SCM: https://kenai.com/hg/bluemarine~metadata-src
*
**********************************************************************************************************************/
package it.tidalwave.metadata.spi;
import java.util.Comparator;
import java.util.Map;
import java.util.TreeMap;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
/*******************************************************************************
*
* A {@link Map} whose key is a {@link Class}. The {@link #get(Object)} method returns
* a value even when there is not an exact match for the key, but a subclass of
* the key exists in the map. Furthermore, if multiple classes in a hierarchy
* are present and an exact match is not found, get()
is guaranteed
* to match the most specialized class.
*
* For instance, consider to have classes A
, B
and
* C
, such as B extends A
and C extends B
;
* and suppose to have:
*
*
* ClassMap<String> map = new ClassMap<String>();
* map.put(A.class, "one");
* map.put(B.class, "two");
*
*
* Then, the following holds true:
*
*
* String s1 = map.get(A.class); // returns "one"
* String s2 = map.get(B.class); // returns "two"
* String s3 = map.get(C.class); // returns "two"
*
*
* ClassMap
is useful for registering services bound to a specific
* class and generically to all of its subclasses (this e.g. happens when you use
* a bytecode enhancer such as CGLIB that produces objects which are instances
* of synthetic subclasses, like C
in the example); and where it's
* possible that a specific subclass is bound to a specific service (like
* B
in the example).
*
* @hidden
*
* @author Fabrizio Giudici
* @version $Id$
*
******************************************************************************/
public class ClassMap extends TreeMap, T>
{
private static final long serialVersionUID = -8094417265456628888L;
public ClassMap()
{
// This Comparator makes sure that entries are sorted by revered
// hierarchy depth, that is subclasses come first.
super(new Comparator>()
{
public int compare (@Nonnull final Class> c1, @Nonnull final Class> c2)
{
final int sgn = (int)Math.signum(depth(c2) - depth(c1));
if (sgn == 0) // be deterministic in any case
{
return c1.getName().compareTo(c2.getName());
}
return sgn;
}
private int depth (@Nonnull final Class> clazz)
{
final Class> superClass = clazz.getSuperclass();
return (superClass == null) ? 0 : depth(superClass) + 1;
}
});
}
/***************************************************************************
*
* Returns the object bound to the given key.
*
* The search is performed by just looking at all the entries in the map;
* since they are sorted in reversal hyerarchy depth it's ok to return the
* first match (any further match would refer to superclasses).
*
**************************************************************************/
@Override
@CheckForNull
public T get (@Nonnull final Object key)
{
for (final Map.Entry, T> entry : entrySet())
{
if (entry.getKey().isAssignableFrom((Class)key))
{
return entry.getValue();
}
}
return null;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy