All Downloads are FREE. Search and download functionalities are using the official Maven repository.

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