jaxp/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/AnnotationEntryGen.java
changeset 46174 5611d2529b49
equal deleted inserted replaced
46173:5546b5710844 46174:5611d2529b49
       
     1 /*
       
     2  * reserved comment block
       
     3  * DO NOT REMOVE OR ALTER!
       
     4  */
       
     5 /*
       
     6  * Licensed to the Apache Software Foundation (ASF) under one or more
       
     7  * contributor license agreements.  See the NOTICE file distributed with
       
     8  * this work for additional information regarding copyright ownership.
       
     9  * The ASF licenses this file to You under the Apache License, Version 2.0
       
    10  * (the "License"); you may not use this file except in compliance with
       
    11  * the License.  You may obtain a copy of the License at
       
    12  *
       
    13  *      http://www.apache.org/licenses/LICENSE-2.0
       
    14  *
       
    15  * Unless required by applicable law or agreed to in writing, software
       
    16  * distributed under the License is distributed on an "AS IS" BASIS,
       
    17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
       
    18  * See the License for the specific language governing permissions and
       
    19  * limitations under the License.
       
    20  */
       
    21 
       
    22 package com.sun.org.apache.bcel.internal.generic;
       
    23 
       
    24 import java.io.ByteArrayInputStream;
       
    25 import java.io.ByteArrayOutputStream;
       
    26 import java.io.DataInput;
       
    27 import java.io.DataInputStream;
       
    28 import java.io.DataOutputStream;
       
    29 import java.io.IOException;
       
    30 import java.util.ArrayList;
       
    31 import java.util.List;
       
    32 
       
    33 import com.sun.org.apache.bcel.internal.classfile.AnnotationEntry;
       
    34 import com.sun.org.apache.bcel.internal.classfile.Attribute;
       
    35 import com.sun.org.apache.bcel.internal.classfile.ConstantUtf8;
       
    36 import com.sun.org.apache.bcel.internal.classfile.ElementValuePair;
       
    37 import com.sun.org.apache.bcel.internal.classfile.RuntimeInvisibleAnnotations;
       
    38 import com.sun.org.apache.bcel.internal.classfile.RuntimeInvisibleParameterAnnotations;
       
    39 import com.sun.org.apache.bcel.internal.classfile.RuntimeVisibleAnnotations;
       
    40 import com.sun.org.apache.bcel.internal.classfile.RuntimeVisibleParameterAnnotations;
       
    41 
       
    42 /**
       
    43  * @since 6.0
       
    44  */
       
    45 public class AnnotationEntryGen {
       
    46     private int typeIndex;
       
    47 
       
    48     private List<ElementValuePairGen> evs;
       
    49 
       
    50     private final ConstantPoolGen cpool;
       
    51 
       
    52     private boolean isRuntimeVisible = false;
       
    53 
       
    54     /**
       
    55      * Here we are taking a fixed annotation of type Annotation and building a
       
    56      * modifiable AnnotationGen object. If the pool passed in is for a different
       
    57      * class file, then copyPoolEntries should have been passed as true as that
       
    58      * will force us to do a deep copy of the annotation and move the cpool
       
    59      * entries across. We need to copy the type and the element name value pairs
       
    60      * and the visibility.
       
    61      */
       
    62     public AnnotationEntryGen(final AnnotationEntry a, final ConstantPoolGen cpool,
       
    63                               final boolean copyPoolEntries) {
       
    64         this.cpool = cpool;
       
    65         if (copyPoolEntries) {
       
    66             typeIndex = cpool.addUtf8(a.getAnnotationType());
       
    67         } else {
       
    68             typeIndex = a.getAnnotationTypeIndex();
       
    69         }
       
    70         isRuntimeVisible = a.isRuntimeVisible();
       
    71         evs = copyValues(a.getElementValuePairs(), cpool, copyPoolEntries);
       
    72     }
       
    73 
       
    74     private List<ElementValuePairGen> copyValues(final ElementValuePair[] in, final ConstantPoolGen cpool,
       
    75                                                  final boolean copyPoolEntries) {
       
    76         final List<ElementValuePairGen> out = new ArrayList<>();
       
    77         for (final ElementValuePair nvp : in) {
       
    78             out.add(new ElementValuePairGen(nvp, cpool, copyPoolEntries));
       
    79         }
       
    80         return out;
       
    81     }
       
    82 
       
    83     private AnnotationEntryGen(final ConstantPoolGen cpool) {
       
    84         this.cpool = cpool;
       
    85     }
       
    86 
       
    87     /**
       
    88      * Retrieve an immutable version of this AnnotationGen
       
    89      */
       
    90     public AnnotationEntry getAnnotation() {
       
    91         final AnnotationEntry a = new AnnotationEntry(typeIndex, cpool.getConstantPool(),
       
    92                 isRuntimeVisible);
       
    93         for (final ElementValuePairGen element : evs) {
       
    94             a.addElementNameValuePair(element.getElementNameValuePair());
       
    95         }
       
    96         return a;
       
    97     }
       
    98 
       
    99     public AnnotationEntryGen(final ObjectType type,
       
   100                               final List<ElementValuePairGen> elements, final boolean vis,
       
   101                               final ConstantPoolGen cpool) {
       
   102         this.cpool = cpool;
       
   103         this.typeIndex = cpool.addUtf8(type.getSignature());
       
   104         evs = elements;
       
   105         isRuntimeVisible = vis;
       
   106     }
       
   107 
       
   108     public static AnnotationEntryGen read(final DataInput dis,
       
   109                                           final ConstantPoolGen cpool, final boolean b) throws IOException {
       
   110         final AnnotationEntryGen a = new AnnotationEntryGen(cpool);
       
   111         a.typeIndex = dis.readUnsignedShort();
       
   112         final int elemValuePairCount = dis.readUnsignedShort();
       
   113         for (int i = 0; i < elemValuePairCount; i++) {
       
   114             final int nidx = dis.readUnsignedShort();
       
   115             a.addElementNameValuePair(new ElementValuePairGen(nidx,
       
   116                     ElementValueGen.readElementValue(dis, cpool), cpool));
       
   117         }
       
   118         a.isRuntimeVisible(b);
       
   119         return a;
       
   120     }
       
   121 
       
   122     public void dump(final DataOutputStream dos) throws IOException {
       
   123         dos.writeShort(typeIndex); // u2 index of type name in cpool
       
   124         dos.writeShort(evs.size()); // u2 element_value pair count
       
   125         for (final ElementValuePairGen envp : evs) {
       
   126             envp.dump(dos);
       
   127         }
       
   128     }
       
   129 
       
   130     public void addElementNameValuePair(final ElementValuePairGen evp) {
       
   131         if (evs == null) {
       
   132             evs = new ArrayList<>();
       
   133         }
       
   134         evs.add(evp);
       
   135     }
       
   136 
       
   137     public int getTypeIndex() {
       
   138         return typeIndex;
       
   139     }
       
   140 
       
   141     public final String getTypeSignature() {
       
   142         // ConstantClass c = (ConstantClass)cpool.getConstant(typeIndex);
       
   143         final ConstantUtf8 utf8 = (ConstantUtf8) cpool
       
   144                 .getConstant(typeIndex/* c.getNameIndex() */);
       
   145         return utf8.getBytes();
       
   146     }
       
   147 
       
   148     public final String getTypeName() {
       
   149         return getTypeSignature();// BCELBUG: Should I use this instead?
       
   150         // Utility.signatureToString(getTypeSignature());
       
   151     }
       
   152 
       
   153     /**
       
   154      * Returns list of ElementNameValuePair objects
       
   155      */
       
   156     public List<ElementValuePairGen> getValues() {
       
   157         return evs;
       
   158     }
       
   159 
       
   160     @Override
       
   161     public String toString() {
       
   162         final StringBuilder s = new StringBuilder(32); // CHECKSTYLE IGNORE MagicNumber
       
   163         s.append("AnnotationGen:[").append(getTypeName()).append(" #").append(evs.size()).append(" {");
       
   164         for (int i = 0; i < evs.size(); i++) {
       
   165             s.append(evs.get(i));
       
   166             if (i + 1 < evs.size()) {
       
   167                 s.append(",");
       
   168             }
       
   169         }
       
   170         s.append("}]");
       
   171         return s.toString();
       
   172     }
       
   173 
       
   174     public String toShortString() {
       
   175         final StringBuilder s = new StringBuilder();
       
   176         s.append("@").append(getTypeName()).append("(");
       
   177         for (int i = 0; i < evs.size(); i++) {
       
   178             s.append(evs.get(i));
       
   179             if (i + 1 < evs.size()) {
       
   180                 s.append(",");
       
   181             }
       
   182         }
       
   183         s.append(")");
       
   184         return s.toString();
       
   185     }
       
   186 
       
   187     private void isRuntimeVisible(final boolean b) {
       
   188         isRuntimeVisible = b;
       
   189     }
       
   190 
       
   191     public boolean isRuntimeVisible() {
       
   192         return isRuntimeVisible;
       
   193     }
       
   194 
       
   195 
       
   196     /**
       
   197      * Converts a list of AnnotationGen objects into a set of attributes
       
   198      * that can be attached to the class file.
       
   199      *
       
   200      * @param cp  The constant pool gen where we can create the necessary name refs
       
   201      * @param annotationEntryGens An array of AnnotationGen objects
       
   202      */
       
   203     static Attribute[] getAnnotationAttributes(final ConstantPoolGen cp, final AnnotationEntryGen[] annotationEntryGens) {
       
   204         if (annotationEntryGens.length == 0) {
       
   205             return new Attribute[0];
       
   206         }
       
   207 
       
   208         try {
       
   209             int countVisible = 0;
       
   210             int countInvisible = 0;
       
   211 
       
   212             //  put the annotations in the right output stream
       
   213             for (final AnnotationEntryGen a : annotationEntryGens) {
       
   214                 if (a.isRuntimeVisible()) {
       
   215                     countVisible++;
       
   216                 } else {
       
   217                     countInvisible++;
       
   218                 }
       
   219             }
       
   220 
       
   221             final ByteArrayOutputStream rvaBytes = new ByteArrayOutputStream();
       
   222             final ByteArrayOutputStream riaBytes = new ByteArrayOutputStream();
       
   223             try (DataOutputStream rvaDos = new DataOutputStream(rvaBytes);
       
   224                     DataOutputStream riaDos = new DataOutputStream(riaBytes)) {
       
   225 
       
   226                 rvaDos.writeShort(countVisible);
       
   227                 riaDos.writeShort(countInvisible);
       
   228 
       
   229                 // put the annotations in the right output stream
       
   230                 for (final AnnotationEntryGen a : annotationEntryGens) {
       
   231                     if (a.isRuntimeVisible()) {
       
   232                         a.dump(rvaDos);
       
   233                     } else {
       
   234                         a.dump(riaDos);
       
   235                     }
       
   236                 }
       
   237             }
       
   238 
       
   239             final byte[] rvaData = rvaBytes.toByteArray();
       
   240             final byte[] riaData = riaBytes.toByteArray();
       
   241 
       
   242             int rvaIndex = -1;
       
   243             int riaIndex = -1;
       
   244 
       
   245             if (rvaData.length > 2) {
       
   246                 rvaIndex = cp.addUtf8("RuntimeVisibleAnnotations");
       
   247             }
       
   248             if (riaData.length > 2) {
       
   249                 riaIndex = cp.addUtf8("RuntimeInvisibleAnnotations");
       
   250             }
       
   251 
       
   252             final List<Attribute> newAttributes = new ArrayList<>();
       
   253             if (rvaData.length > 2) {
       
   254                 newAttributes.add(
       
   255                         new RuntimeVisibleAnnotations(rvaIndex, rvaData.length,
       
   256                             new DataInputStream(new ByteArrayInputStream(rvaData)), cp.getConstantPool()));
       
   257             }
       
   258             if (riaData.length > 2) {
       
   259                 newAttributes.add(
       
   260                         new RuntimeInvisibleAnnotations(riaIndex, riaData.length,
       
   261                             new DataInputStream(new ByteArrayInputStream(riaData)), cp.getConstantPool()));
       
   262             }
       
   263 
       
   264             return newAttributes.toArray(new Attribute[newAttributes.size()]);
       
   265         } catch (final IOException e) {
       
   266             System.err.println("IOException whilst processing annotations. " +
       
   267                     e.getMessage());
       
   268         }
       
   269         return null;
       
   270     }
       
   271 
       
   272 
       
   273     /**
       
   274      * Annotations against a class are stored in one of four attribute kinds:
       
   275      * - RuntimeVisibleParameterAnnotations
       
   276      * - RuntimeInvisibleParameterAnnotations
       
   277      */
       
   278     static Attribute[] getParameterAnnotationAttributes(
       
   279             final ConstantPoolGen cp,
       
   280             final List<AnnotationEntryGen>[] /*Array of lists, array size depends on #params */vec) {
       
   281         final int[] visCount = new int[vec.length];
       
   282         int totalVisCount = 0;
       
   283         final int[] invisCount = new int[vec.length];
       
   284         int totalInvisCount = 0;
       
   285         try {
       
   286             for (int i = 0; i < vec.length; i++) {
       
   287                 if (vec[i] != null) {
       
   288                     for (final AnnotationEntryGen element : vec[i]) {
       
   289                         if (element.isRuntimeVisible()) {
       
   290                             visCount[i]++;
       
   291                             totalVisCount++;
       
   292                         } else {
       
   293                             invisCount[i]++;
       
   294                             totalInvisCount++;
       
   295                         }
       
   296                     }
       
   297                 }
       
   298             }
       
   299             // Lets do the visible ones
       
   300             final ByteArrayOutputStream rvaBytes = new ByteArrayOutputStream();
       
   301             try (DataOutputStream rvaDos = new DataOutputStream(rvaBytes)) {
       
   302                 rvaDos.writeByte(vec.length); // First goes number of parameters
       
   303                 for (int i = 0; i < vec.length; i++) {
       
   304                     rvaDos.writeShort(visCount[i]);
       
   305                     if (visCount[i] > 0) {
       
   306                         for (final AnnotationEntryGen element : vec[i]) {
       
   307                             if (element.isRuntimeVisible()) {
       
   308                                 element.dump(rvaDos);
       
   309                             }
       
   310                         }
       
   311                     }
       
   312                 }
       
   313             }
       
   314             // Lets do the invisible ones
       
   315             final ByteArrayOutputStream riaBytes = new ByteArrayOutputStream();
       
   316             try (DataOutputStream riaDos = new DataOutputStream(riaBytes)) {
       
   317                 riaDos.writeByte(vec.length); // First goes number of parameters
       
   318                 for (int i = 0; i < vec.length; i++) {
       
   319                     riaDos.writeShort(invisCount[i]);
       
   320                     if (invisCount[i] > 0) {
       
   321                         for (final AnnotationEntryGen element : vec[i]) {
       
   322                             if (!element.isRuntimeVisible()) {
       
   323                                 element.dump(riaDos);
       
   324                             }
       
   325                         }
       
   326                     }
       
   327                 }
       
   328             }
       
   329             final byte[] rvaData = rvaBytes.toByteArray();
       
   330             final byte[] riaData = riaBytes.toByteArray();
       
   331             int rvaIndex = -1;
       
   332             int riaIndex = -1;
       
   333             if (totalVisCount > 0) {
       
   334                 rvaIndex = cp.addUtf8("RuntimeVisibleParameterAnnotations");
       
   335             }
       
   336             if (totalInvisCount > 0) {
       
   337                 riaIndex = cp.addUtf8("RuntimeInvisibleParameterAnnotations");
       
   338             }
       
   339             final List<Attribute> newAttributes = new ArrayList<>();
       
   340             if (totalVisCount > 0) {
       
   341                 newAttributes
       
   342                         .add(new RuntimeVisibleParameterAnnotations(rvaIndex,
       
   343                                 rvaData.length,
       
   344                                 new DataInputStream(new ByteArrayInputStream(rvaData)),
       
   345                                     cp.getConstantPool()));
       
   346             }
       
   347             if (totalInvisCount > 0) {
       
   348                 newAttributes
       
   349                         .add(new RuntimeInvisibleParameterAnnotations(riaIndex,
       
   350                                 riaData.length,
       
   351                                 new DataInputStream(new ByteArrayInputStream(riaData)),
       
   352                                     cp.getConstantPool()));
       
   353             }
       
   354             return newAttributes.toArray(new Attribute[newAttributes.size()]);
       
   355         } catch (final IOException e) {
       
   356             System.err.println("IOException whilst processing parameter annotations." +
       
   357                     e.getMessage());
       
   358         }
       
   359         return null;
       
   360     }
       
   361 
       
   362 }