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

org.jboss.jandex.Index Maven / Gradle / Ivy

There is a newer version: 62
Show newest version
/*
 * JBoss, Home of Professional Open Source.
 * Copyright 2013 Red Hat, Inc., and individual contributors
 * as indicated by the @author tags.
 *
 * 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.jboss.jandex;

import java.lang.reflect.Modifier;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * An index useful for quickly processing annotations. The index is read-only and supports
 * concurrent access. Also the index is optimized for memory efficiency by using componentized
 * DotName values.
 *
 * 

It contains the following information: *

    *
  1. All annotations and a collection of targets they refer to
  2. *
  3. All classes (including methodParameters) scanned during the indexing process (typical all classes in a jar)
  4. *
  5. All subclasses indexed by super class known to this index
  6. *
* * @author Jason T. Greene * */ public final class Index implements IndexView { private static final List EMPTY_ANNOTATION_LIST = Collections.emptyList(); private static final List EMPTY_CLASSINFO_LIST = Collections.emptyList(); final Map> annotations; final Map> subclasses; final Map> implementors; final Map classes; Index(Map> annotations, Map> subclasses, Map> implementors, Map classes) { this.annotations = Collections.unmodifiableMap(annotations); this.classes = Collections.unmodifiableMap(classes); this.subclasses = Collections.unmodifiableMap(subclasses); this.implementors = Collections.unmodifiableMap(implementors); } /** * Constructs a "mock" Index using the passed values. All passed values MUST NOT BE MODIFIED AFTER THIS CALL. * Otherwise the resulting object would not conform to the contract outlined above. Also, to conform to the * memory efficiency contract this method should be passed componentized DotNames, which all share common root * instances. Of course for testing code this doesn't really matter. * * @param annotations A map to lookup annotation instances by class name * @param subclasses A map to lookup subclasses by super class name * @param implementors A map to lookup implementing classes by interface name * @param classes A map to lookup classes by class name * @return the index */ public static Index create(Map> annotations, Map> subclasses, Map> implementors, Map classes) { return new Index(annotations, subclasses, implementors, classes); } /** * {@inheritDoc} */ public List getAnnotations(DotName annotationName) { List list = annotations.get(annotationName); return list == null ? EMPTY_ANNOTATION_LIST: Collections.unmodifiableList(list); } /** * {@inheritDoc} */ public List getKnownDirectSubclasses(DotName className) { List list = subclasses.get(className); return list == null ? EMPTY_CLASSINFO_LIST : Collections.unmodifiableList(list); } @Override public Collection getAllKnownSubclasses(DotName className) { final Set allKnown = new HashSet(); final Set processedClasses = new HashSet(); getAllKnownSubClasses(className, allKnown, processedClasses); return allKnown; } private void getAllKnownSubClasses(DotName className, Set allKnown, Set processedClasses) { final Set subClassesToProcess = new HashSet(); subClassesToProcess.add(className); while (!subClassesToProcess.isEmpty()) { final Iterator toProcess = subClassesToProcess.iterator(); DotName name = toProcess.next(); toProcess.remove(); processedClasses.add(name); getAllKnownSubClasses(name, allKnown, subClassesToProcess, processedClasses); } } private void getAllKnownSubClasses(DotName name, Set allKnown, Set subClassesToProcess, Set processedClasses) { final List list = getKnownDirectSubclasses(name); if (list != null) { for (final ClassInfo clazz : list) { final DotName className = clazz.name(); if (!processedClasses.contains(className)) { allKnown.add(clazz); subClassesToProcess.add(className); } } } } /** * {@inheritDoc} */ public List getKnownDirectImplementors(DotName className) { List list = implementors.get(className); return list == null ? EMPTY_CLASSINFO_LIST : Collections.unmodifiableList(list); } @Override public Set getAllKnownImplementors(final DotName interfaceName) { final Set allKnown = new HashSet(); final Set subInterfacesToProcess = new HashSet(); final Set processedClasses = new HashSet(); subInterfacesToProcess.add(interfaceName); while (!subInterfacesToProcess.isEmpty()) { final Iterator toProcess = subInterfacesToProcess.iterator(); DotName name = toProcess.next(); toProcess.remove(); processedClasses.add(name); getKnownImplementors(name, allKnown, subInterfacesToProcess, processedClasses); } return allKnown; } private void getKnownImplementors(DotName name, Set allKnown, Set subInterfacesToProcess, Set processedClasses) { final List list = getKnownDirectImplementors(name); if (list != null) { for (final ClassInfo clazz : list) { final DotName className = clazz.name(); if (!processedClasses.contains(className)) { if (Modifier.isInterface(clazz.flags())) { subInterfacesToProcess.add(className); } else { if (!allKnown.contains(clazz)) { allKnown.add(clazz); processedClasses.add(className); getAllKnownSubClasses(className, allKnown, processedClasses); } } } } } } /** * {@inheritDoc} */ @Override public ClassInfo getClassByName(DotName className) { return classes.get(className); } /** * {@inheritDoc} */ public Collection getKnownClasses() { return classes.values(); } /** * Print all annotations known by this index to stdout. */ public void printAnnotations() { System.out.println("Annotations:"); for (Map.Entry> e : annotations.entrySet()) { System.out.println(e.getKey() + ":"); for (AnnotationInstance instance : e.getValue()) { AnnotationTarget target = instance.target(); if (target instanceof ClassInfo) { System.out.println(" Class: " + target); } else if (target instanceof FieldInfo) { System.out.println(" Field: " + target); } else if (target instanceof MethodInfo) { System.out.println(" Method: " + target); } else if (target instanceof MethodParameterInfo) { System.out.println(" Parameter: " + target); } List values = instance.values(); if (values.size() < 1) continue; StringBuilder builder = new StringBuilder(" ("); for (int i = 0; i < values.size(); i ++) { builder.append(values.get(i)); if (i < values.size() - 1) builder.append(", "); } builder.append(')'); System.out.println(builder.toString()); } } } /** * Print all classes that have known subclasses, and all their subclasses */ public void printSubclasses() { System.out.println("Subclasses:"); for (Map.Entry> entry : subclasses.entrySet()) { System.out.println(entry.getKey() + ":"); for (ClassInfo clazz : entry.getValue()) System.out.println(" " + clazz.name()); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy