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

org.nuiton.jaxx.compiler.ClassMap Maven / Gradle / Ivy

There is a newer version: 3.1.5
Show newest version
/*
 * #%L
 * JAXX :: Compiler
 * %%
 * Copyright (C) 2008 - 2018 Code Lutin, Ultreia.io
 * %%
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as 
 * published by the Free Software Foundation, either version 3 of the 
 * License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Lesser Public License for more details.
 * 
 * You should have received a copy of the GNU General Lesser Public 
 * License along with this program.  If not, see
 * .
 * #L%
 */

package org.nuiton.jaxx.compiler;

import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
import org.nuiton.jaxx.compiler.reflect.ClassDescriptor;
import org.nuiton.jaxx.compiler.reflect.ClassDescriptorHelper;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

/**
 * A Map implementation which uses Classes as keys.  ClassMap differs from typical maps
 * in that it takes subclasses into account;  mapping a class to a value also maps all subclasses of
 * that class to the value.
 *
 * A get operation will return the value associated with the class itself, or failing
 * that, with its nearest ancestor for which there exists a mapping.
 *
 * @param  type of the class
 */
public class ClassMap extends HashMap {

    private static final long serialVersionUID = 5149779660675529037L;

    /**
     * Logger
     */
    protected static final Logger log = LogManager.getLogger(ClassMap.class);

    /**
     * Keeps track of automatically-added Classes so we can distinguish them from user-added
     * Classes.  Unknown Classes are automatically added to the map during get
     * calls to speed up subsequent requests, but they must be updated when the mappings
     * for their superclasses are modified.
     */
    private final List autoKeys = new ArrayList<>();

    /**
     * Returns the value associated with the key Class.  If the class itself does not have
     * a mapping, its superclass will be checked, and so on until an ancestor class with a mapping is
     * located.  If none of the class' ancestors have a mapping, null is returned.
     *
     * @param key the class to check
     * @return the mapping for the class
     */
    @Override
    public T get(Object key) {
        T result = null;
        ClassDescriptor c = (ClassDescriptor) key;
        while (c != null) {
            result = super.get(c);
            if (result != null) {
                break;
            }
            c = c.getSuperclass();
        }

        if (result == null && ((ClassDescriptor) key).isInterface()) {
            result = get(ClassDescriptorHelper.getClassDescriptor(Object.class));
        }

        if (c != key && result != null) { // no mapping for the class itself, but found one for a superclass
            put((ClassDescriptor) key, result);
            autoKeys.add((ClassDescriptor) key);
        }
        return result;
    }

    /**
     * Associates a value with a class and all of its descendents.
     *
     * @param key   the class to map
     * @param value the value to map to the class
     * @return the old value associated with the class
     */
    @Override
    public T put(ClassDescriptor key, T value) {
        //if (!(key instanceof ClassDescriptor)) {
        //    throw new IllegalArgumentException("expected ClassDescriptor, got " + key);
        //}
        if (autoKeys.size() > 0) { // remove all automatic keys which descend from the class being modified
            Iterator i = autoKeys.iterator();
            while (i.hasNext()) {
                ClassDescriptor auto = i.next();
                if (key.isAssignableFrom(auto)) {
                    i.remove();
                    remove(auto);
                }
            }
        }
        return super.put(key, value);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy