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