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

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

There is a newer version: 1.3.3
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.io.BufferedOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;

/**
 * Writes a Jandex index file to a stream. The write process is somewhat more
 * expensive to allow for fast reads and a compact size. For more information on
 * the index content, see the documentation on {@link org.jboss.jandex.Indexer}.
 *
 * 

* The IndexWriter operates on standard output streams, and also provides * suitable buffering. * *

* Thread-Safety *

* IndexWriter is not thread-safe and can not be shared between concurrent * threads. * * @see org.jboss.jandex.Indexer * @see org.jboss.jandex.Index * @author Jason T. Greene * */ final class IndexWriterV1 extends IndexWriterImpl { // babelfish (no h) private static final int MAGIC = 0xBABE1F15; static final int MIN_VERSION = 1; 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 final OutputStream out; private StrongInternPool pool; StrongInternPool.Index poolIndex; private TreeMap classTable; /** * Constructs an IndexWriter using the specified stream * * @param out a stream to write an index to */ IndexWriterV1(OutputStream out) { this.out = out; } /** * Writes the specified index to the associated output stream. This may be called multiple times in order * to write multiple indexes. * * @param index the index to write to the stream * @param version the index file version * @return the number of bytes written to the stream * @throws java.io.IOException if any i/o error occurs */ int write(Index index, int version) throws IOException { if (version < MIN_VERSION || version > MAX_VERSION) { throw new UnsupportedVersion("Version: " + version); } PackedDataOutputStream stream = new PackedDataOutputStream(new BufferedOutputStream(out)); stream.writeInt(MAGIC); stream.writeByte(version); buildTables(index); writeClassTable(stream); writeStringTable(stream); writeClasses(stream, index, version); stream.flush(); return stream.size(); } private void writeStringTable(PackedDataOutputStream stream) throws IOException { stream.writePackedU32(pool.size()); Iterator iter = pool.iterator(); while (iter.hasNext()) { String string = iter.next(); stream.writeUTF(string); } } private void writeClassTable(PackedDataOutputStream stream) throws IOException { stream.writePackedU32(classTable.size()); // Zero is reserved for null int pos = 1; for (Entry entry : classTable.entrySet()) { entry.setValue(pos++); DotName name = entry.getKey(); assert name.isComponentized(); int nameDepth = 0; for (DotName prefix = name.prefix(); prefix != null; prefix = prefix.prefix()) nameDepth++; stream.writePackedU32(nameDepth); stream.writeUTF(name.local()); } } private int positionOf(String string) { // V1 format does not use 0 as a null placeholder int i = poolIndex.positionOf(string) - 1; if (i < 0) throw new IllegalStateException(); return i; } private int positionOf(DotName className) { className = downgradeName(className); Integer i = classTable.get(className); if (i == null) throw new IllegalStateException("Class not found in class table:" + className); return i.intValue(); } private void writeClasses(PackedDataOutputStream stream, Index index, int version) throws IOException { Collection classes = index.getKnownClasses(); stream.writePackedU32(classes.size()); for (ClassInfo clazz: classes) { stream.writePackedU32(positionOf(clazz.name())); stream.writePackedU32(clazz.superName() == null ? 0 : positionOf(clazz.superName())); stream.writeShort(clazz.flags()); // hasNoArgsConstructor supported since version 3 if (version >= 3) { stream.writeBoolean(clazz.hasNoArgsConstructor()); } DotName[] interfaces = clazz.interfaces(); stream.writePackedU32(interfaces.length); for (DotName intf: interfaces) stream.writePackedU32(positionOf(intf)); Set>> entrySet = clazz.annotations().entrySet(); stream.writePackedU32(entrySet.size()); for (Entry> entry : entrySet) { stream.writePackedU32(positionOf(entry.getKey())); List instances = entry.getValue(); stream.writePackedU32(instances.size()); for (AnnotationInstance instance : instances) { AnnotationTarget target = instance.target(); if (target instanceof FieldInfo) { FieldInfo field = (FieldInfo) target; stream.writeByte(FIELD_TAG); stream.writePackedU32(positionOf(field.name())); writeType(stream, field.type()); stream.writeShort(field.flags()); } else if (target instanceof MethodInfo) { MethodInfo method = (MethodInfo) target; stream.writeByte(METHOD_TAG); stream.writePackedU32(positionOf(method.name())); stream.writePackedU32(method.args().length); for (int i = 0; i < method.args().length; i ++) { writeType(stream, method.args()[i]); } writeType(stream, method.returnType()); stream.writeShort(method.flags()); } else if (target instanceof MethodParameterInfo) { MethodParameterInfo param = (MethodParameterInfo) target; MethodInfo method = param.method(); stream.writeByte(METHOD_PARAMATER_TAG); stream.writePackedU32(positionOf(method.name())); stream.writePackedU32(method.args().length); for (int i = 0; i < method.args().length; i ++) { writeType(stream, method.args()[i]); } writeType(stream, method.returnType()); stream.writeShort(method.flags()); stream.writePackedU32(param.position()); } else if (target instanceof ClassInfo) { stream.writeByte(CLASS_TAG); } else throw new IllegalStateException("Unknown target"); Collection values = instance.values(); writeAnnotationValues(stream, values); } } } } private void writeAnnotationValues(PackedDataOutputStream stream, Collection values) throws IOException { stream.writePackedU32(values.size()); for (AnnotationValue value : values) { writeAnnotationValue(stream, value); } } private void writeAnnotationValue(PackedDataOutputStream stream, AnnotationValue value) throws IOException { stream.writePackedU32(positionOf(value.name())); if (value instanceof AnnotationValue.ByteValue) { stream.writeByte(AVALUE_BYTE); stream.writeByte(value.asByte() & 0xFF); } else if (value instanceof AnnotationValue.ShortValue) { stream.writeByte(AVALUE_SHORT); stream.writePackedU32(value.asShort() & 0xFFFF); } else if (value instanceof AnnotationValue.IntegerValue) { stream.writeByte(AVALUE_INT); stream.writePackedU32(value.asInt()); } else if (value instanceof AnnotationValue.CharacterValue) { stream.writeByte(AVALUE_CHAR); stream.writePackedU32(value.asChar()); } else if (value instanceof AnnotationValue.FloatValue) { stream.writeByte(AVALUE_FLOAT); stream.writeFloat(value.asFloat()); } else if (value instanceof AnnotationValue.DoubleValue) { stream.writeByte(AVALUE_DOUBLE); stream.writeDouble(value.asDouble()); } else if (value instanceof AnnotationValue.LongValue) { stream.writeByte(AVALUE_LONG); stream.writeLong(value.asLong()); } else if (value instanceof AnnotationValue.BooleanValue) { stream.writeByte(AVALUE_BOOLEAN); stream.writeBoolean(value.asBoolean()); } else if (value instanceof AnnotationValue.StringValue) { stream.writeByte(AVALUE_STRING); stream.writePackedU32(positionOf(value.asString())); } else if (value instanceof AnnotationValue.ClassValue) { stream.writeByte(AVALUE_CLASS); writeType(stream, value.asClass()); } else if (value instanceof AnnotationValue.EnumValue) { stream.writeByte(AVALUE_ENUM); stream.writePackedU32(positionOf(value.asEnumType())); stream.writePackedU32(positionOf(value.asEnum())); } else if (value instanceof AnnotationValue.ArrayValue) { AnnotationValue[] array = value.asArray(); int length = array.length; stream.writeByte(AVALUE_ARRAY); stream.writePackedU32(length); for (int i = 0; i < length; i++) { writeAnnotationValue(stream, array[i]); } } else if (value instanceof AnnotationValue.NestedAnnotation) { AnnotationInstance instance = value.asNested(); Collection values = instance.values(); stream.writeByte(AVALUE_NESTED); stream.writePackedU32(positionOf(instance.name())); writeAnnotationValues(stream, values); } } private void writeType(PackedDataOutputStream stream, Type type) throws IOException { stream.writeByte(type.kind().ordinal()); stream.writePackedU32(positionOf(type.name())); } private void buildTables(Index index) { pool = new StrongInternPool(); classTable = new TreeMap(); // Build the pool for all strings for (ClassInfo clazz: index.getKnownClasses()) { addClassName(clazz.name()); if (clazz.superName() != null) addClassName(clazz.superName()); for (DotName intf: clazz.interfaces()) addClassName(intf); for (Entry> entry : clazz.annotations().entrySet()) { addClassName(entry.getKey()); for (AnnotationInstance instance: entry.getValue()) { AnnotationTarget target = instance.target(); if (target instanceof FieldInfo) { FieldInfo field = (FieldInfo) target; intern(field.name()); addClassName(field.type().name()); } else if (target instanceof MethodInfo) { MethodInfo method = (MethodInfo) target; intern(method.name()); for (Type type : method.args()) addClassName(type.name()); addClassName(method.returnType().name()); } else if (target instanceof MethodParameterInfo) { MethodParameterInfo param = (MethodParameterInfo) target; intern(param.method().name()); for (Type type : param.method().args()) addClassName(type.name()); addClassName(param.method().returnType().name()); } for (AnnotationValue value : instance.values()) buildAValueEntries(index, value); } } } poolIndex = pool.index(); } private void buildAValueEntries(Index index, AnnotationValue value) { intern(value.name()); if (value instanceof AnnotationValue.StringValue) { intern(value.asString()); } else if (value instanceof AnnotationValue.ClassValue) { addClassName(value.asClass().name()); } else if (value instanceof AnnotationValue.EnumValue) { addClassName(value.asEnumType()); intern(value.asEnum()); } else if (value instanceof AnnotationValue.ArrayValue) { for (AnnotationValue entry : value.asArray()) buildAValueEntries(index, entry); } else if (value instanceof AnnotationValue.NestedAnnotation) { AnnotationInstance instance = value.asNested(); Collection values = instance.values(); addClassName(instance.name()); for (AnnotationValue entry : values) { buildAValueEntries(index, entry); } } } private String intern(String name) { return pool.intern(name); } private void addClassName(DotName name) { name = downgradeName(name); if (! classTable.containsKey(name)) classTable.put(name, null); DotName prefix = name.prefix(); if (prefix != null) addClassName(prefix); } private DotName downgradeName(DotName name) { DotName n = name; StringBuilder builder = null; while (n.isInner()) { if (builder == null) { builder = new StringBuilder(); } builder.insert(0, n.local()).insert(0, '$'); if (! n.prefix().isInner()) { builder.insert(0, n.prefix().local()); name = new DotName(n.prefix().prefix(), builder.toString(), true, false); } n = n.prefix(); } return name; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy