Skip to content

Commit

Permalink
add IndexView.getKnownDirectSubinterfaces and getAllKnownSubinterfaces
Browse files Browse the repository at this point in the history
This is technically a breaking change, but only for users who
extend/implement the `IndexView` interface. Callers are fine.
It is tempting to fix `IndexView.getKnownDirectImplementors`
to no longer return subinterfaces, but we refrain from doing so
to maintain behavioral compatibility.

This change requires persistent format version bump. That has already
happened on the `smallrye` branch, so this commit doesn't bump
again, but note that this commit can't be backported to Jandex 2.x.
  • Loading branch information
Ladicek committed Apr 14, 2022
1 parent 2a80a50 commit 6c0226a
Show file tree
Hide file tree
Showing 9 changed files with 444 additions and 71 deletions.
4 changes: 2 additions & 2 deletions core/src/main/java/org/jboss/jandex/ClassInfo.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
* Only the methods and fields which are references by an annotation are stored.
*
* <p>
* Global information including the parent class, implemented methodParameters, and
* Global information including the parent class, implemented interfaces, and
* access flags are also provided since this information is often necessary.
*
* <p>
Expand Down Expand Up @@ -196,7 +196,7 @@ public String toString() {
* @param name the name of this class
* @param superName the name of the parent class
* @param flags the class attributes
* @param interfaces the methodParameters this class implements
* @param interfaces the interfaces this class implements
* @param annotations the annotations on this class
* @param hasNoArgsConstructor whether this class has a no arg constructor
* @return a new mock class representation
Expand Down
55 changes: 55 additions & 0 deletions core/src/main/java/org/jboss/jandex/CompositeIndex.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,15 @@
package org.jboss.jandex;

import java.lang.reflect.Modifier;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Queue;
import java.util.Set;

/**
Expand Down Expand Up @@ -63,6 +65,7 @@ public static CompositeIndex createMerged(final CompositeIndex... indexes) {
/**
* {@inheritDoc}
*/
@Override
public List<AnnotationInstance> getAnnotations(final DotName annotationName) {
final List<AnnotationInstance> allInstances = new ArrayList<AnnotationInstance>();
for (IndexView index : indexes) {
Expand All @@ -77,6 +80,7 @@ public List<AnnotationInstance> getAnnotations(final DotName annotationName) {
/**
* {@inheritDoc}
*/
@Override
public Collection<AnnotationInstance> getAnnotationsWithRepeatable(DotName annotationName, IndexView index) {
List<AnnotationInstance> allInstances = new ArrayList<AnnotationInstance>();
for (IndexView i : indexes) {
Expand All @@ -88,6 +92,7 @@ public Collection<AnnotationInstance> getAnnotationsWithRepeatable(DotName annot
/**
* {@inheritDoc}
*/
@Override
public Set<ClassInfo> getKnownDirectSubclasses(final DotName className) {
final Set<ClassInfo> allKnown = new HashSet<ClassInfo>();
for (IndexView index : indexes) {
Expand All @@ -102,6 +107,7 @@ public Set<ClassInfo> getKnownDirectSubclasses(final DotName className) {
/**
* {@inheritDoc}
*/
@Override
public Set<ClassInfo> getAllKnownSubclasses(final DotName className) {
final Set<ClassInfo> allKnown = new HashSet<ClassInfo>();
final Set<DotName> processedClasses = new HashSet<DotName>();
Expand Down Expand Up @@ -140,6 +146,50 @@ private void getAllKnownSubClasses(DotName name, Set<ClassInfo> allKnown, Set<Do
/**
* {@inheritDoc}
*/
@Override
public Collection<ClassInfo> getKnownDirectSubinterfaces(DotName interfaceName) {
Set<ClassInfo> allKnown = new HashSet<>();
for (IndexView index : indexes) {
Collection<ClassInfo> list = index.getKnownDirectSubinterfaces(interfaceName);
if (list != null) {
allKnown.addAll(list);
}
}
return Collections.unmodifiableSet(allKnown);
}

/**
* {@inheritDoc}
*/
@Override
public Collection<ClassInfo> getAllKnownSubinterfaces(DotName interfaceName) {
Set<ClassInfo> result = new HashSet<>();

Queue<DotName> workQueue = new ArrayDeque<>();
Set<DotName> alreadyProcessed = new HashSet<>();

workQueue.add(interfaceName);
while (!workQueue.isEmpty()) {
DotName iface = workQueue.remove();
if (!alreadyProcessed.add(iface)) {
continue;
}

for (IndexView index : indexes) {
for (ClassInfo directSubinterface : index.getKnownDirectSubinterfaces(iface)) {
result.add(directSubinterface);
workQueue.add(directSubinterface.name());
}
}
}

return result;
}

/**
* {@inheritDoc}
*/
@Override
public Collection<ClassInfo> getKnownDirectImplementors(final DotName className) {
final Set<ClassInfo> allKnown = new HashSet<ClassInfo>();
for (IndexView index : indexes) {
Expand All @@ -154,6 +204,7 @@ public Collection<ClassInfo> getKnownDirectImplementors(final DotName className)
/**
* {@inheritDoc}
*/
@Override
public Set<ClassInfo> getAllKnownImplementors(final DotName interfaceName) {
final Set<ClassInfo> allKnown = new HashSet<ClassInfo>();
final Set<DotName> subInterfacesToProcess = new HashSet<DotName>();
Expand Down Expand Up @@ -195,6 +246,7 @@ private void getKnownImplementors(DotName name, Set<ClassInfo> allKnown, Set<Dot
/**
* {@inheritDoc}
*/
@Override
public ClassInfo getClassByName(final DotName className) {
for (IndexView index : indexes) {
final ClassInfo info = index.getClassByName(className);
Expand All @@ -208,6 +260,7 @@ public ClassInfo getClassByName(final DotName className) {
/**
* {@inheritDoc}
*/
@Override
public Collection<ClassInfo> getKnownClasses() {
final List<ClassInfo> allKnown = new ArrayList<ClassInfo>();
for (IndexView index : indexes) {
Expand All @@ -222,6 +275,7 @@ public Collection<ClassInfo> getKnownClasses() {
/**
* {@inheritDoc}
*/
@Override
public ModuleInfo getModuleByName(final DotName moduleName) {
for (IndexView index : indexes) {
final ModuleInfo info = index.getModuleByName(moduleName);
Expand All @@ -235,6 +289,7 @@ public ModuleInfo getModuleByName(final DotName moduleName) {
/**
* {@inheritDoc}
*/
@Override
public Collection<ModuleInfo> getKnownModules() {
final List<ModuleInfo> allKnown = new ArrayList<ModuleInfo>();
for (IndexView index : indexes) {
Expand Down
118 changes: 95 additions & 23 deletions core/src/main/java/org/jboss/jandex/Index.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Modifier;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
Expand All @@ -33,21 +34,26 @@
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

/**
* 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.
* concurrent access. Also, the index is optimized for memory efficiency by using componentized
* {@code DotName} values.
*
* <p>
* It contains the following information:
* <ol>
* <li>All annotations and a collection of targets they refer to</li>
* <li>All classes (including methodParameters) scanned during the indexing process (typical all classes in a jar)</li>
* <li>All subclasses indexed by super class known to this index</li>
* <li>All classes (including interfaces) scanned during the indexing process (typically all classes in a jar)</li>
* <li>All modules scanned during the indexing process (typically one module in a jar)</li>
* <li>All subclasses for each class known to this index</li>
* <li>All subinterfaces for each interface known to this index</li>
* <li>All implementors for each interface known to this index</li>
* <li>All users of each class known to this index</li>
* </ol>
*
* @author Jason T. Greene
Expand All @@ -61,17 +67,19 @@ public final class Index implements IndexView {

final Map<DotName, List<AnnotationInstance>> annotations;
final Map<DotName, List<ClassInfo>> subclasses;
final Map<DotName, List<ClassInfo>> subinterfaces;
final Map<DotName, List<ClassInfo>> implementors;
final Map<DotName, ClassInfo> classes;
final Map<DotName, ModuleInfo> modules;
final Map<DotName, List<ClassInfo>> users;

Index(Map<DotName, List<AnnotationInstance>> annotations, Map<DotName, List<ClassInfo>> subclasses,
Map<DotName, List<ClassInfo>> implementors, Map<DotName, ClassInfo> classes, Map<DotName, ModuleInfo> modules,
Map<DotName, List<ClassInfo>> users) {
Map<DotName, List<ClassInfo>> subinterfaces, Map<DotName, List<ClassInfo>> implementors,
Map<DotName, ClassInfo> classes, Map<DotName, ModuleInfo> modules, Map<DotName, List<ClassInfo>> users) {
this.annotations = Collections.unmodifiableMap(annotations);
this.classes = Collections.unmodifiableMap(classes);
this.subclasses = Collections.unmodifiableMap(subclasses);
this.subinterfaces = Collections.unmodifiableMap(subinterfaces);
this.implementors = Collections.unmodifiableMap(implementors);
this.modules = Collections.unmodifiableMap(modules);
this.users = Collections.unmodifiableMap(users);
Expand All @@ -91,8 +99,8 @@ public final class Index implements IndexView {
*/
public static Index create(Map<DotName, List<AnnotationInstance>> annotations, Map<DotName, List<ClassInfo>> subclasses,
Map<DotName, List<ClassInfo>> implementors, Map<DotName, ClassInfo> classes) {
return new Index(annotations, subclasses, implementors, classes, Collections.<DotName, ModuleInfo> emptyMap(),
Collections.<DotName, List<ClassInfo>> emptyMap());
return new Index(annotations, subclasses, Collections.emptyMap(), implementors, classes, Collections.emptyMap(),
Collections.emptyMap());
}

/**
Expand All @@ -109,9 +117,28 @@ public static Index create(Map<DotName, List<AnnotationInstance>> annotations, M
* @return the index
*/
public static Index create(Map<DotName, List<AnnotationInstance>> annotations, Map<DotName, List<ClassInfo>> subclasses,
Map<DotName, List<ClassInfo>> implementors, Map<DotName, ClassInfo> classes,
Map<DotName, List<ClassInfo>> users) {
return new Index(annotations, subclasses, implementors, classes, Collections.<DotName, ModuleInfo> emptyMap(), users);
Map<DotName, List<ClassInfo>> implementors, Map<DotName, ClassInfo> classes, Map<DotName, List<ClassInfo>> users) {
return new Index(annotations, subclasses, Collections.emptyMap(), implementors, classes, Collections.emptyMap(), users);
}

/**
* 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 subinterfaces A map to lookup subinterfaces by super interface name
* @param implementors A map to lookup implementing classes by interface name
* @param classes A map to lookup classes by class name
* @param users A map to lookup class users
* @return the index
*/
public static Index create(Map<DotName, List<AnnotationInstance>> annotations, Map<DotName, List<ClassInfo>> subclasses,
Map<DotName, List<ClassInfo>> subinterfaces, Map<DotName, List<ClassInfo>> implementors,
Map<DotName, ClassInfo> classes, Map<DotName, List<ClassInfo>> users) {
return new Index(annotations, subclasses, subinterfaces, implementors, classes, Collections.emptyMap(), users);
}

/**
Expand Down Expand Up @@ -194,6 +221,7 @@ public boolean accept(File pathname) {
/**
* {@inheritDoc}
*/
@Override
public List<AnnotationInstance> getAnnotations(DotName annotationName) {
List<AnnotationInstance> list = annotations.get(annotationName);
return list == null ? EMPTY_ANNOTATION_LIST : Collections.unmodifiableList(list);
Expand All @@ -202,6 +230,7 @@ public List<AnnotationInstance> getAnnotations(DotName annotationName) {
/**
* {@inheritDoc}
*/
@Override
public Collection<AnnotationInstance> getAnnotationsWithRepeatable(DotName annotationName, IndexView index) {
ClassInfo annotationClass = index.getClassByName(annotationName);
if (annotationClass == null) {
Expand Down Expand Up @@ -234,6 +263,7 @@ private Collection<AnnotationInstance> getRepeatableAnnotations(DotName annotati
/**
* {@inheritDoc}
*/
@Override
public List<ClassInfo> getKnownDirectSubclasses(DotName className) {
List<ClassInfo> list = subclasses.get(className);
return list == null ? EMPTY_CLASSINFO_LIST : Collections.unmodifiableList(list);
Expand Down Expand Up @@ -276,11 +306,50 @@ private void getAllKnownSubClasses(DotName name, Set<ClassInfo> allKnown, Set<Do
/**
* {@inheritDoc}
*/
@Override
public List<ClassInfo> getKnownDirectSubinterfaces(DotName interfaceName) {
List<ClassInfo> list = subinterfaces.get(interfaceName);
return list == null ? EMPTY_CLASSINFO_LIST : Collections.unmodifiableList(list);
}

/**
* {@inheritDoc}
*/
@Override
public Collection<ClassInfo> getAllKnownSubinterfaces(DotName interfaceName) {
Set<ClassInfo> result = new HashSet<>();

Queue<DotName> workQueue = new ArrayDeque<>();
Set<DotName> alreadyProcessed = new HashSet<>();

workQueue.add(interfaceName);
while (!workQueue.isEmpty()) {
DotName iface = workQueue.remove();
if (!alreadyProcessed.add(iface)) {
continue;
}

for (ClassInfo directSubinterface : getKnownDirectSubinterfaces(iface)) {
result.add(directSubinterface);
workQueue.add(directSubinterface.name());
}
}

return result;
}

/**
* {@inheritDoc}
*/
@Override
public List<ClassInfo> getKnownDirectImplementors(DotName className) {
List<ClassInfo> list = implementors.get(className);
return list == null ? EMPTY_CLASSINFO_LIST : Collections.unmodifiableList(list);
}

/**
* {@inheritDoc}
*/
@Override
public Set<ClassInfo> getAllKnownImplementors(final DotName interfaceName) {
final Set<ClassInfo> allKnown = new HashSet<ClassInfo>();
Expand Down Expand Up @@ -329,6 +398,7 @@ public ClassInfo getClassByName(DotName className) {
/**
* {@inheritDoc}
*/
@Override
public Collection<ClassInfo> getKnownClasses() {
return classes.values();
}
Expand All @@ -349,6 +419,20 @@ public ModuleInfo getModuleByName(DotName moduleName) {
return modules.get(moduleName);
}

/**
* {@inheritDoc}
*/
@Override
public List<ClassInfo> getKnownUsers(DotName className) {
List<ClassInfo> ret = users.get(className);
if (ret == null) {
return EMPTY_CLASSINFO_LIST;
}
return Collections.unmodifiableList(ret);
}

// ---

/**
* Print all annotations known by this index to stdout.
*/
Expand Down Expand Up @@ -397,16 +481,4 @@ public void printSubclasses() {
System.out.println(" " + clazz.name());
}
}

/**
* {@inheritDoc}
*/
@Override
public List<ClassInfo> getKnownUsers(DotName className) {
List<ClassInfo> ret = users.get(className);
if (ret == null) {
return EMPTY_CLASSINFO_LIST;
}
return Collections.unmodifiableList(ret);
}
}
Loading

0 comments on commit 6c0226a

Please sign in to comment.