• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements.  See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License.  You may obtain a copy of the License at
8  *
9  *   http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 package org.apache.bcel.generic;
19 
20 import java.io.ByteArrayInputStream;
21 import java.io.ByteArrayOutputStream;
22 import java.io.DataInputStream;
23 import java.io.DataOutputStream;
24 import java.io.IOException;
25 import java.util.ArrayList;
26 import java.util.List;
27 
28 import org.apache.bcel.AbstractTestCase;
29 import org.apache.bcel.Const;
30 import org.apache.bcel.classfile.Annotations;
31 import org.apache.bcel.classfile.Attribute;
32 import org.apache.bcel.classfile.RuntimeInvisibleAnnotations;
33 import org.apache.bcel.classfile.RuntimeVisibleAnnotations;
34 
35 public class AnnotationGenTestCase extends AbstractTestCase
36 {
createClassGen(final String classname)37     private ClassGen createClassGen(final String classname)
38     {
39         return new ClassGen(classname, "java.lang.Object", "<generated>",
40                 Const.ACC_PUBLIC | Const.ACC_SUPER, null);
41     }
42 
43     /**
44      * Programmatically construct an mutable annotation (AnnotationGen) object.
45      */
testConstructMutableAnnotation()46     public void testConstructMutableAnnotation()
47     {
48         // Create the containing class
49         final ClassGen cg = createClassGen("HelloWorld");
50         final ConstantPoolGen cp = cg.getConstantPool();
51         // Create the simple primitive value '4' of type 'int'
52         final SimpleElementValueGen evg = new SimpleElementValueGen(
53                 ElementValueGen.PRIMITIVE_INT, cp, 4);
54         // Give it a name, call it 'id'
55         final ElementValuePairGen nvGen = new ElementValuePairGen("id", evg,
56                 cp);
57         // Check it looks right
58         assertTrue(
59                 "Should include string 'id=4' but says: " + nvGen.toString(),
60                 nvGen.toString().contains("id=4"));
61         final ObjectType t = new ObjectType("SimpleAnnotation");
62         final List<ElementValuePairGen> elements = new ArrayList<>();
63         elements.add(nvGen);
64         // Build an annotation of type 'SimpleAnnotation' with 'id=4' as the
65         // only value :)
66         final AnnotationEntryGen a = new AnnotationEntryGen(t, elements, true, cp);
67         // Check we can save and load it ok
68         checkSerialize(a, cp);
69     }
70 
testVisibleInvisibleAnnotationGen()71     public void testVisibleInvisibleAnnotationGen()
72     {
73         // Create the containing class
74         final ClassGen cg = createClassGen("HelloWorld");
75         final ConstantPoolGen cp = cg.getConstantPool();
76         // Create the simple primitive value '4' of type 'int'
77         final SimpleElementValueGen evg = new SimpleElementValueGen(
78                 ElementValueGen.PRIMITIVE_INT, cp, 4);
79         // Give it a name, call it 'id'
80         final ElementValuePairGen nvGen = new ElementValuePairGen("id", evg,
81                 cp);
82         // Check it looks right
83         assertTrue(
84                 "Should include string 'id=4' but says: " + nvGen.toString(),
85                 nvGen.toString().contains("id=4"));
86         final ObjectType t = new ObjectType("SimpleAnnotation");
87         final List<ElementValuePairGen> elements = new ArrayList<>();
88         elements.add(nvGen);
89         // Build a RV annotation of type 'SimpleAnnotation' with 'id=4' as the
90         // only value :)
91         final AnnotationEntryGen a = new AnnotationEntryGen(t, elements, true, cp);
92         final List<AnnotationEntryGen> v = new ArrayList<>();
93         v.add(a);
94         final Attribute[] attributes = AnnotationEntryGen.getAnnotationAttributes(cp, v.toArray(new AnnotationEntryGen[0]));
95         boolean foundRV = false;
96         for (final Attribute attribute : attributes) {
97             if (attribute instanceof RuntimeVisibleAnnotations)
98             {
99                 assertTrue(((Annotations) attribute).isRuntimeVisible());
100                 foundRV = true;
101             }
102         }
103         assertTrue("Should have seen a RuntimeVisibleAnnotation", foundRV);
104         // Build a RIV annotation of type 'SimpleAnnotation' with 'id=4' as the
105         // only value :)
106         final AnnotationEntryGen a2 = new AnnotationEntryGen(t, elements, false, cp);
107         final List<AnnotationEntryGen> v2 = new ArrayList<>();
108         v2.add(a2);
109         final Attribute[] attributes2 = AnnotationEntryGen.getAnnotationAttributes(cp, v2.toArray(new AnnotationEntryGen[0]));
110         boolean foundRIV = false;
111         for (final Attribute attribute : attributes2) {
112             if (attribute instanceof RuntimeInvisibleAnnotations)
113             {
114                 assertFalse(((Annotations) attribute).isRuntimeVisible());
115                 foundRIV = true;
116             }
117         }
118         assertTrue("Should have seen a RuntimeInvisibleAnnotation", foundRIV);
119     }
120 
checkSerialize(final AnnotationEntryGen a, final ConstantPoolGen cpg)121     private void checkSerialize(final AnnotationEntryGen a, final ConstantPoolGen cpg)
122     {
123         try
124         {
125             final String beforeName = a.getTypeName();
126             final ByteArrayOutputStream baos = new ByteArrayOutputStream();
127             try (DataOutputStream dos = new DataOutputStream(baos)) {
128                 a.dump(dos);
129                 dos.flush();
130             }
131             final byte[] bs = baos.toByteArray();
132             final ByteArrayInputStream bais = new ByteArrayInputStream(bs);
133             AnnotationEntryGen annAfter;
134             try (DataInputStream dis = new DataInputStream(bais)) {
135                 annAfter = AnnotationEntryGen.read(dis, cpg, a.isRuntimeVisible());
136             }
137             final String afterName = annAfter.getTypeName();
138             if (!beforeName.equals(afterName))
139             {
140                 fail("Deserialization failed: before type='" + beforeName
141                         + "' after type='" + afterName + "'");
142             }
143             if (a.getValues().size() != annAfter.getValues().size())
144             {
145                 fail("Different numbers of element name value pairs?? "
146                         + a.getValues().size() + "!="
147                         + annAfter.getValues().size());
148             }
149             for (int i = 0; i < a.getValues().size(); i++)
150             {
151                 final ElementValuePairGen beforeElement = a.getValues().get(i);
152                 final ElementValuePairGen afterElement = annAfter.getValues().get(i);
153                 if (!beforeElement.getNameString().equals(
154                         afterElement.getNameString()))
155                 {
156                     fail("Different names?? " + beforeElement.getNameString()
157                             + "!=" + afterElement.getNameString());
158                 }
159             }
160         }
161         catch (final IOException ioe)
162         {
163             fail("Unexpected exception whilst checking serialization: " + ioe);
164         }
165     }
166 }
167