AnnotationWriter.java revision 3e5b0c401c8d93182e9f0ce6f0de81f7574f5aca
1/*
2 * Copyright 2016 Google Inc. All Rights Reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.google.turbine.bytecode;
18
19import com.google.common.collect.ImmutableList;
20import com.google.common.io.ByteArrayDataOutput;
21import com.google.turbine.bytecode.ClassFile.AnnotationInfo;
22import com.google.turbine.bytecode.ClassFile.AnnotationInfo.ElementValue;
23import com.google.turbine.bytecode.ClassFile.AnnotationInfo.ElementValue.AnnotationValue;
24import com.google.turbine.bytecode.ClassFile.AnnotationInfo.ElementValue.ArrayValue;
25import com.google.turbine.bytecode.ClassFile.AnnotationInfo.ElementValue.ConstClassValue;
26import com.google.turbine.bytecode.ClassFile.AnnotationInfo.ElementValue.ConstValue;
27import com.google.turbine.bytecode.ClassFile.AnnotationInfo.ElementValue.EnumConstValue;
28import com.google.turbine.bytecode.ClassFile.TypeAnnotationInfo;
29import com.google.turbine.bytecode.ClassFile.TypeAnnotationInfo.FormalParameterTarget;
30import com.google.turbine.bytecode.ClassFile.TypeAnnotationInfo.SuperTypeTarget;
31import com.google.turbine.bytecode.ClassFile.TypeAnnotationInfo.Target;
32import com.google.turbine.bytecode.ClassFile.TypeAnnotationInfo.ThrowsTarget;
33import com.google.turbine.bytecode.ClassFile.TypeAnnotationInfo.TypeParameterBoundTarget;
34import com.google.turbine.bytecode.ClassFile.TypeAnnotationInfo.TypeParameterTarget;
35import com.google.turbine.bytecode.ClassFile.TypeAnnotationInfo.TypePath;
36import com.google.turbine.model.Const.Value;
37import java.util.Map.Entry;
38
39/** Writes an {@link AnnotationInfo} to a class file. */
40public class AnnotationWriter {
41
42  final ConstantPool pool;
43  final ByteArrayDataOutput output;
44
45  public AnnotationWriter(ConstantPool pool, ByteArrayDataOutput output) {
46    this.pool = pool;
47    this.output = output;
48  }
49
50  public void writeAnnotation(AnnotationInfo annotation) {
51    output.writeShort(pool.utf8(annotation.typeName()));
52    output.writeShort(annotation.elementValuePairs().size());
53    for (Entry<String, ElementValue> entry : annotation.elementValuePairs().entrySet()) {
54      output.writeShort(pool.utf8(entry.getKey()));
55      writeElementValue(entry.getValue());
56    }
57  }
58
59  void writeElementValue(ElementValue value) {
60    switch (value.kind()) {
61      case CONST:
62        writeConstElementValue(((ConstValue) value).value());
63        break;
64      case ENUM:
65        writeEnumElementValue((EnumConstValue) value);
66        break;
67      case CLASS:
68        writeClassElementValue((ConstClassValue) value);
69        break;
70      case ARRAY:
71        writeArrayElementValue((ArrayValue) value);
72        break;
73      case ANNOTATION:
74        writeAnnotationElementValue((AnnotationValue) value);
75        break;
76      default:
77        throw new AssertionError(value.kind());
78    }
79  }
80
81  private void writeConstElementValue(Value value) {
82    switch (value.constantTypeKind()) {
83      case BYTE:
84        writeConst('B', pool.integer(value.asInteger().value()));
85        break;
86      case CHAR:
87        writeConst('C', pool.integer(value.asInteger().value()));
88        break;
89      case SHORT:
90        writeConst('S', pool.integer(value.asInteger().value()));
91        break;
92      case DOUBLE:
93        writeConst('D', pool.doubleInfo(value.asDouble().value()));
94        break;
95      case FLOAT:
96        writeConst('F', pool.floatInfo(value.asFloat().value()));
97        break;
98      case INT:
99        writeConst('I', pool.integer(value.asInteger().value()));
100        break;
101      case LONG:
102        writeConst('J', pool.longInfo(value.asLong().value()));
103        break;
104      case STRING:
105        writeConst('s', pool.utf8(value.asString().value()));
106        break;
107      case BOOLEAN:
108        writeConst('Z', pool.integer(value.asBoolean().value() ? 1 : 0));
109        break;
110      default:
111        throw new AssertionError(value.constantTypeKind());
112    }
113  }
114
115  private void writeConst(char tag, short index) {
116    output.writeByte(tag);
117    output.writeShort(index);
118  }
119
120  private void writeEnumElementValue(EnumConstValue value) {
121    output.writeByte('e');
122    output.writeShort(pool.utf8(value.typeName()));
123    output.writeShort(pool.utf8(value.constName()));
124  }
125
126  private void writeClassElementValue(ConstClassValue value) {
127    output.writeByte('c');
128    output.writeShort(pool.utf8(value.className()));
129  }
130
131  private void writeArrayElementValue(ArrayValue value) {
132    output.writeByte('[');
133    output.writeShort(value.elements().size());
134    for (ElementValue elementValue : value.elements()) {
135      writeElementValue(elementValue);
136    }
137  }
138
139  private void writeAnnotationElementValue(AnnotationValue value) {
140    output.writeByte('@');
141    writeAnnotation(value.annotation());
142  }
143
144  public void writeTypeAnnotation(TypeAnnotationInfo annotation) {
145    output.writeByte(annotation.targetType().tag());
146    writeTypeAnnotationTarget(annotation.target());
147    writePath(annotation.path());
148    writeAnnotation(annotation.anno());
149  }
150
151  private void writePath(TypePath path) {
152    ImmutableList<TypePath> flat = path.flatten();
153    output.writeByte(flat.size());
154    for (TypePath curr : flat) {
155      output.writeByte(curr.tag());
156      output.writeByte(curr.typeArgumentIndex());
157    }
158  }
159
160  private void writeTypeAnnotationTarget(Target target) {
161    switch (target.kind()) {
162      case EMPTY:
163        break;
164      case TYPE_PARAMETER:
165        output.writeByte(((TypeParameterTarget) target).index());
166        break;
167      case FORMAL_PARAMETER:
168        output.writeByte(((FormalParameterTarget) target).index());
169        break;
170      case THROWS:
171        output.writeShort(((ThrowsTarget) target).index());
172        break;
173      case SUPERTYPE:
174        output.writeShort(((SuperTypeTarget) target).index());
175        break;
176      case TYPE_PARAMETER_BOUND:
177        TypeParameterBoundTarget typeParameterBoundTarget = (TypeParameterBoundTarget) target;
178        output.writeByte(typeParameterBoundTarget.typeParameterIndex());
179        output.writeByte(typeParameterBoundTarget.boundIndex());
180        break;
181      default:
182        throw new AssertionError(target.kind());
183    }
184  }
185}
186