Skip to content

Commit

Permalink
Merge pull request #129 from MikeEdgar/invisible_annotations
Browse files Browse the repository at this point in the history
Read RuntimeInvisible*Annotations in Indexer
  • Loading branch information
Ladicek committed Sep 14, 2021
2 parents 006bf03 + 22e183a commit cc91220
Show file tree
Hide file tree
Showing 17 changed files with 342 additions and 132 deletions.
72 changes: 61 additions & 11 deletions core/src/main/java/org/jboss/jandex/AnnotationInstance.java
Original file line number Diff line number Diff line change
Expand Up @@ -46,34 +46,49 @@ public final class AnnotationInstance {
private final DotName name;
private AnnotationTarget target;
private final AnnotationValue[] values;
private final boolean runtimeVisible;

static class InstanceNameComparator implements Comparator<AnnotationInstance> {
public int compare(AnnotationInstance instance, AnnotationInstance instance2) {
return instance.name().compareTo(instance2.name());
}
}

AnnotationInstance(AnnotationInstance instance, AnnotationTarget target) {
this.name = instance.name;
this.values = instance.values;
this.target = target;
}

AnnotationInstance(DotName name, AnnotationTarget target, AnnotationValue[] values) {
private AnnotationInstance(DotName name, AnnotationTarget target, AnnotationValue[] values, boolean runtimeVisible) {
this.name = name;
this.target = target;
this.values = values != null && values.length > 0 ? values : AnnotationValue.EMPTY_VALUE_ARRAY;
this.runtimeVisible = runtimeVisible;
}

static AnnotationInstance create(AnnotationInstance instance, AnnotationTarget target) {
return new AnnotationInstance(instance.name, target, instance.values, instance.runtimeVisible);
}

/**
* Construct a new mock annotation instance. The passed values array will be defensively copied.
* It is assumed that the annotation is {@link #runtimeVisible()}.
*
* @param name the name of the annotation instance
* @param target the thing the annotation is declared on
* @param values the values of this annotation instance
* @return the new mock Annotation Instance
*/
public static final AnnotationInstance create(DotName name, AnnotationTarget target, AnnotationValue[] values) {
public static AnnotationInstance create(DotName name, AnnotationTarget target, AnnotationValue[] values) {
return create(name, true, target, values);
}

/**
* Construct a new mock annotation instance. The passed values array will be defensively copied.
*
* @param name the name of the annotation instance
* @param visible whether the annotation is visible at runtime via the reflection API
* @param target the thing the annotation is declared on
* @param values the values of this annotation instance
* @return the new mock Annotation Instance
*/
public static AnnotationInstance create(DotName name, boolean visible, AnnotationTarget target,
AnnotationValue[] values) {
if (name == null)
throw new IllegalArgumentException("Name can't be null");

Expand All @@ -89,25 +104,47 @@ public int compare(AnnotationValue o1, AnnotationValue o2) {
}
});

return new AnnotationInstance(name, target, values);
return new AnnotationInstance(name, target, values, visible);
}

/**
* Construct a new mock annotation instance. The passed values list will be defensively copied.
* It is assumed that the annotation is {@link #runtimeVisible()}.
*
* @param name the name of the annotation instance
* @param target the thing the annotation is declared on
* @param values the values of this annotation instance
* @return the new mock Annotation Instance
*/
public static final AnnotationInstance create(DotName name, AnnotationTarget target, List<AnnotationValue> values) {
public static AnnotationInstance create(DotName name, AnnotationTarget target, List<AnnotationValue> values) {
return create(name, true, target, values);
}

/**
* Construct a new mock annotation instance. The passed values list will be defensively copied.
*
* @param name the name of the annotation instance
* @param visible whether the annotation is visible at runtime via the reflection API
* @param target the thing the annotation is declared on
* @param values the values of this annotation instance
* @return the new mock Annotation Instance
*/
public static AnnotationInstance create(DotName name, boolean visible, AnnotationTarget target,
List<AnnotationValue> values) {
if (name == null)
throw new IllegalArgumentException("Name can't be null");

if (values == null)
throw new IllegalArgumentException("Values can't be null");

return create(name, target, values.toArray(ANNOTATION_VALUES_TYPE));
return create(name, visible, target, values.toArray(ANNOTATION_VALUES_TYPE));
}

static AnnotationInstance binarySearch(AnnotationInstance[] annotations, DotName name) {
// only `name` is significant in `key`, the rest can be arbitrary
AnnotationInstance key = new AnnotationInstance(name, null, null, false);
int i = Arrays.binarySearch(annotations, key, AnnotationInstance.NAME_COMPARATOR);
return i >= 0 ? annotations[i] : null;
}

/**
Expand Down Expand Up @@ -278,6 +315,16 @@ AnnotationValue[] valueArray() {
return values;
}

/**
* Returns true if this annotation uses RetentionPolicy.RUNTIME and is
* visible to runtime reflection.
*
* @since 3.0
*/
public boolean runtimeVisible() {
return this.runtimeVisible;
}

/**
* Returns an optionally simplified string that represents this annotation instance.
* If simplified the output is smaller but missing information, such as the package
Expand Down Expand Up @@ -321,6 +368,9 @@ void setTarget(AnnotationTarget target) {
this.target = target;
}

// runtime visibility is ignored for the purpose of equality and hash code, because
// the annotation type identity (the name) already includes that information

/**
* Returns whether or not this annotation instance is equivalent to another instance.
* An annotation instance is equivalent if its name and values are equal, and it shares
Expand Down
4 changes: 1 addition & 3 deletions core/src/main/java/org/jboss/jandex/FieldInternal.java
Original file line number Diff line number Diff line change
Expand Up @@ -123,9 +123,7 @@ final AnnotationInstance[] annotationArray() {
}

final AnnotationInstance annotation(DotName name) {
AnnotationInstance key = new AnnotationInstance(name, null, null);
int i = Arrays.binarySearch(annotations, key, AnnotationInstance.NAME_COMPARATOR);
return i >= 0 ? annotations[i] : null;
return AnnotationInstance.binarySearch(annotations, name);
}

final boolean hasAnnotation(DotName name) {
Expand Down
3 changes: 1 addition & 2 deletions core/src/main/java/org/jboss/jandex/Index.java
Original file line number Diff line number Diff line change
Expand Up @@ -201,8 +201,7 @@ private Collection<AnnotationInstance> getRepeatableAnnotations(DotName annotati
for (AnnotationInstance containingInstance : getAnnotations(containingAnnotationName)) {
for (AnnotationInstance nestedInstance : containingInstance.value().asNestedArray()) {
// We need to set the target of the containing instance
instances.add(new AnnotationInstance(nestedInstance.name(), containingInstance.target(),
nestedInstance.valueArray()));
instances.add(AnnotationInstance.create(nestedInstance, containingInstance.target()));
}
}
return instances;
Expand Down
6 changes: 3 additions & 3 deletions core/src/main/java/org/jboss/jandex/IndexReader.java
Original file line number Diff line number Diff line change
Expand Up @@ -73,15 +73,15 @@ public Index read() throws IOException {
readVersion();
}

return reader.read(version);
return reader.read();
}

private void initReader(int version) throws IOException {
IndexReaderImpl reader;
if (version >= IndexReaderV1.MIN_VERSION && version <= IndexReaderV1.MAX_VERSION) {
reader = new IndexReaderV1(input);
reader = new IndexReaderV1(input, version);
} else if (version >= IndexReaderV2.MIN_VERSION && version <= IndexReaderV2.MAX_VERSION) {
reader = new IndexReaderV2(input);
reader = new IndexReaderV2(input, version);
} else {
input.close();
throw new UnsupportedVersion("Can't read index version " + version
Expand Down
2 changes: 1 addition & 1 deletion core/src/main/java/org/jboss/jandex/IndexReaderImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
* @author Jason T. Greene
*/
abstract class IndexReaderImpl {
abstract Index read(int version) throws IOException;
abstract Index read() throws IOException;

abstract int toDataVersion(int version);
}
17 changes: 10 additions & 7 deletions core/src/main/java/org/jboss/jandex/IndexReaderV1.java
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@ final class IndexReaderV1 extends IndexReaderImpl {
private static final int AVALUE_ARRAY = 12;
private static final int AVALUE_NESTED = 13;

private PackedDataInputStream input;
private final PackedDataInputStream input;
private final int version;
private DotName[] classTable;
private String[] stringTable;
private HashMap<DotName, List<AnnotationInstance>> masterAnnotations;
Expand All @@ -75,8 +76,9 @@ final class IndexReaderV1 extends IndexReaderImpl {
*
* @param input a stream which points to a jandex index file
*/
IndexReaderV1(PackedDataInputStream input) {
IndexReaderV1(PackedDataInputStream input, int version) {
this.input = input;
this.version = version;
}

/**
Expand All @@ -88,21 +90,21 @@ final class IndexReaderV1 extends IndexReaderImpl {
* @throws IllegalArgumentException if the stream does not point to Jandex index data
* @throws org.jboss.jandex.UnsupportedVersion if the index data is tagged with a version not known to this reader
*/
Index read(int version) throws IOException {
Index read() throws IOException {
try {
PackedDataInputStream stream = this.input;
masterAnnotations = new HashMap<DotName, List<AnnotationInstance>>();
readClassTable(stream);
readStringTable(stream);
return readClasses(stream, version);
return readClasses(stream);
} finally {
classTable = null;
stringTable = null;
masterAnnotations = null;
}
}

private Index readClasses(PackedDataInputStream stream, int version) throws IOException {
private Index readClasses(PackedDataInputStream stream) throws IOException {
int entries = stream.readPackedU32();
HashMap<DotName, List<ClassInfo>> subclasses = new HashMap<DotName, List<ClassInfo>>();
HashMap<DotName, List<ClassInfo>> implementors = new HashMap<DotName, List<ClassInfo>>();
Expand Down Expand Up @@ -177,7 +179,7 @@ private void readAnnotations(PackedDataInputStream stream, Map<DotName, List<Ann
}

AnnotationValue[] values = readAnnotationValues(stream);
AnnotationInstance instance = new AnnotationInstance(annotationName, target, values);
AnnotationInstance instance = AnnotationInstance.create(annotationName, target, values);

recordAnnotation(masterAnnotations, annotationName, instance);
recordAnnotation(annotations, annotationName, instance);
Expand Down Expand Up @@ -235,7 +237,8 @@ private AnnotationValue[] readAnnotationValues(PackedDataInputStream stream) thr
break;
case AVALUE_NESTED: {
DotName nestedName = classTable[stream.readPackedU32()];
AnnotationInstance nestedInstance = new AnnotationInstance(nestedName, null, readAnnotationValues(stream));
AnnotationInstance nestedInstance = AnnotationInstance.create(nestedName, null,
readAnnotationValues(stream));
value = new AnnotationValue.NestedAnnotation(name, nestedInstance);
break;
}
Expand Down
Loading

0 comments on commit cc91220

Please sign in to comment.