org.jboss.jandex.IndexReaderV1 Maven / Gradle / Ivy
/*
* 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.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Reads a Jandex index file and returns the saved index. See {@link org.jboss.jandex.Indexer}
* for a thorough description of how the Index data is produced.
*
*
* An IndexReader loads the stream passed to it's constructor and applies the
* appropriate buffering. The Jandex index format is designed for efficient
* reading and low final memory storage.
*
*
* Thread-Safety
*
* IndexReader is not thread-safe and can not be shared between concurrent
* threads. The resulting index, however, is.
*
* @author Jason T. Greene
*/
final class IndexReaderV1 extends IndexReaderImpl {
static final int MIN_VERSION = 2;
static final int MAX_VERSION = 3;
private static final byte FIELD_TAG = 1;
private static final byte METHOD_TAG = 2;
private static final byte METHOD_PARAMATER_TAG = 3;
private static final byte CLASS_TAG = 4;
private static final int AVALUE_BYTE = 1;
private static final int AVALUE_SHORT = 2;
private static final int AVALUE_INT = 3;
private static final int AVALUE_CHAR = 4;
private static final int AVALUE_FLOAT = 5;
private static final int AVALUE_DOUBLE = 6;
private static final int AVALUE_LONG = 7;
private static final int AVALUE_BOOLEAN = 8;
private static final int AVALUE_STRING = 9;
private static final int AVALUE_CLASS = 10;
private static final int AVALUE_ENUM = 11;
private static final int AVALUE_ARRAY = 12;
private static final int AVALUE_NESTED = 13;
private PackedDataInputStream input;
private DotName[] classTable;
private String[] stringTable;
private HashMap> masterAnnotations;
/**
* Constructs a new IndedReader using the passed stream. The stream is not
* read from until the read method is called.
*
* @param input a stream which points to a jandex index file
*/
IndexReaderV1(PackedDataInputStream input) {
this.input = input;
}
/**
* Read the index at the associated stream of this reader. This method can be called multiple
* times if the stream contains multiple index files.
*
* @return the Index contained in the stream
* @throws java.io.IOException if an I/O error occurs
* @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 {
try {
PackedDataInputStream stream = this.input;
masterAnnotations = new HashMap>();
readClassTable(stream);
readStringTable(stream);
return readClasses(stream, version);
} finally {
classTable = null;
stringTable = null;
masterAnnotations = null;
}
}
private Index readClasses(PackedDataInputStream stream, int version) throws IOException {
int entries = stream.readPackedU32();
HashMap> subclasses = new HashMap>();
HashMap> implementors = new HashMap>();
HashMap classes = new HashMap();
masterAnnotations = new HashMap>();
for (int i = 0; i < entries; i++) {
DotName name = classTable[stream.readPackedU32()];
DotName superName = classTable[stream.readPackedU32()];
short flags = stream.readShort();
// No copyParameters supported in version 3+
boolean hasNoArgsConstructor = version >= 3 && stream.readBoolean();
int numIntfs = stream.readPackedU32();
List interfaces = new ArrayList(numIntfs);
for (int j = 0; j < numIntfs; j++) {
interfaces.add(new ClassType(classTable[stream.readPackedU32()]));
}
Type[] interfaceTypes = interfaces.toArray(new Type[interfaces.size()]);
Map> annotations = new HashMap>();
Type superClassType = superName == null ? null : new ClassType(superName);
ClassInfo clazz = new ClassInfo(name, superClassType, flags, interfaceTypes, annotations, hasNoArgsConstructor);
classes.put(name, clazz);
addClassToMap(subclasses, superName, clazz);
for (Type interfaceName : interfaces) {
addClassToMap(implementors, interfaceName.name(), clazz);
}
readAnnotations(stream, annotations, clazz);
}
return Index.create(masterAnnotations, subclasses, implementors, classes);
}
private void readAnnotations(PackedDataInputStream stream, Map> annotations, ClassInfo clazz)
throws IOException {
int numAnnotations = stream.readPackedU32();
for (int j = 0; j < numAnnotations; j++) {
DotName annotationName = classTable[stream.readPackedU32()];
int numTargets = stream.readPackedU32();
for (int k = 0; k < numTargets; k++) {
int tag = stream.readPackedU32();
AnnotationTarget target;
switch (tag) {
case FIELD_TAG: {
String name = stringTable[stream.readPackedU32()];
Type type = readType(stream);
short flags = stream.readShort();
target = new FieldInfo(clazz, Utils.toUTF8(name), type, flags);
break;
}
case METHOD_TAG: {
target = readMethod(clazz, stream);
break;
}
case METHOD_PARAMATER_TAG: {
MethodInfo method = readMethod(clazz, stream);
target = new MethodParameterInfo(method, (short)stream.readPackedU32());
break;
}
case CLASS_TAG: {
target = clazz;
break;
}
default:
throw new UnsupportedOperationException();
}
AnnotationValue[] values = readAnnotationValues(stream);
AnnotationInstance instance = new AnnotationInstance(annotationName, target, values);
recordAnnotation(masterAnnotations, annotationName, instance);
recordAnnotation(annotations, annotationName, instance);
}
}
}
private AnnotationValue[] readAnnotationValues(PackedDataInputStream stream) throws IOException {
int numValues = stream.readPackedU32();
AnnotationValue[] values = new AnnotationValue[numValues];
for (int i = 0; i < numValues; i++) {
String name = stringTable[stream.readPackedU32()];
int tag = stream.readByte();
AnnotationValue value;
switch (tag) {
case AVALUE_BYTE:
value = new AnnotationValue.ByteValue(name, stream.readByte());
break;
case AVALUE_SHORT:
value = new AnnotationValue.ShortValue(name, (short) stream.readPackedU32());
break;
case AVALUE_INT:
value = new AnnotationValue.IntegerValue(name, stream.readPackedU32());
break;
case AVALUE_CHAR:
value = new AnnotationValue.CharacterValue(name, (char) stream.readPackedU32());
break;
case AVALUE_FLOAT:
value = new AnnotationValue.FloatValue(name, stream.readFloat());
break;
case AVALUE_DOUBLE:
value = new AnnotationValue.DoubleValue(name, stream.readDouble());
break;
case AVALUE_LONG:
value = new AnnotationValue.LongValue(name, stream.readLong());
break;
case AVALUE_BOOLEAN:
value = new AnnotationValue.BooleanValue(name, stream.readBoolean());
break;
case AVALUE_STRING:
value = new AnnotationValue.StringValue(name, stringTable[stream.readPackedU32()]);
break;
case AVALUE_CLASS:
value = new AnnotationValue.ClassValue(name, readType(stream));
break;
case AVALUE_ENUM:
value = new AnnotationValue.EnumValue(name, classTable[stream.readPackedU32()], stringTable[stream.readPackedU32()]);
break;
case AVALUE_ARRAY:
value = new AnnotationValue.ArrayValue(name, readAnnotationValues(stream));
break;
case AVALUE_NESTED: {
DotName nestedName = classTable[stream.readPackedU32()];
AnnotationInstance nestedInstance = new AnnotationInstance(nestedName, null, readAnnotationValues(stream));
value = new AnnotationValue.NestedAnnotation(name, nestedInstance);
break;
}
default:
throw new IllegalStateException("Invalid annotation value tag:" + tag);
}
values[i] = value;
}
return values;
}
private MethodInfo readMethod(ClassInfo clazz, PackedDataInputStream stream) throws IOException {
String name = stringTable[stream.readPackedU32()];
int numArgs = stream.readPackedU32();
List args = new ArrayList(numArgs);
for (int i = 0; i < numArgs; i ++) {
args.add(readType(stream));
}
Type[] parameters = args.toArray(new Type[args.size()]);
Type returnType = readType(stream);
short flags = stream.readShort();
byte[] bytes = Utils.toUTF8(name);
return new MethodInfo(clazz, bytes, parameters, returnType, flags);
}
private void recordAnnotation(Map> annotations, DotName annotation, AnnotationInstance instance) {
List list = annotations.get(annotation);
if (list == null) {
list = new ArrayList();
annotations.put(annotation, list);
}
list.add(instance);
}
private void addClassToMap(HashMap> map, DotName name, ClassInfo currentClass) {
List list = map.get(name);
if (list == null) {
list = new ArrayList();
map.put(name, list);
}
list.add(currentClass);
}
private Type readType(PackedDataInputStream stream) throws IOException {
Type.Kind kind = Type.Kind.fromOrdinal(stream.readByte());
DotName name = classTable[stream.readPackedU32()];
return Type.create(name, kind);
}
private void readStringTable(PackedDataInputStream stream) throws IOException {
int entries = stream.readPackedU32();
stringTable = new String[entries];
for (int i = 0; i < entries; i++) {
stringTable[i] = stream.readUTF();
}
}
private void readClassTable(PackedDataInputStream stream) throws IOException {
int entries = stream.readPackedU32();
int lastDepth = -1;
DotName curr = null;
// Null is the implicit first entry
classTable = new DotName[++entries];
for (int i = 1; i < entries; i++) {
int depth = stream.readPackedU32();
String local = stream.readUTF();
if (depth <= lastDepth) {
while (lastDepth-- >= depth)
curr = curr.prefix();
}
classTable[i] = curr = new DotName(curr, local, true, false);
lastDepth = depth;
}
}
int toDataVersion(int version) {
// From 1 to 3, every version changed the available data
return version;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy