View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   https://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  
20  package org.apache.bcel.generic;
21  
22  import static org.junit.jupiter.api.Assertions.assertEquals;
23  import static org.junit.jupiter.api.Assertions.assertNotNull;
24  import static org.junit.jupiter.api.Assertions.assertNull;
25  import static org.junit.jupiter.api.Assertions.assertTrue;
26  
27  import java.io.File;
28  import java.io.IOException;
29  
30  import org.apache.bcel.AbstractTest;
31  import org.apache.bcel.Const;
32  import org.apache.bcel.classfile.AnnotationEntry;
33  import org.apache.bcel.classfile.ElementValuePair;
34  import org.apache.bcel.classfile.Field;
35  import org.apache.bcel.classfile.JavaClass;
36  import org.apache.bcel.util.SyntheticRepository;
37  import org.junit.jupiter.api.Test;
38  
39  class FieldAnnotationsTest extends AbstractTest {
40      // helper methods
41      public void checkAnnotatedField(final JavaClass clazz, final String fieldname, final String AnnotationEntryName, final String AnnotationEntryElementName,
42          final String AnnotationEntryElementValue) {
43          final Field[] fields = clazz.getFields();
44          for (final Field f : fields) {
45              final AnnotationEntry[] fieldAnnotationEntrys = f.getAnnotationEntries();
46              if (f.getName().equals(fieldname)) {
47                  checkAnnotationEntry(fieldAnnotationEntrys[0], AnnotationEntryName, AnnotationEntryElementName, AnnotationEntryElementValue);
48                  assertNotNull(f.getAttribute(Const.ATTR_RUNTIME_VISIBLE_ANNOTATIONS));
49                  assertNull(f.getAttribute(Const.ATTR_RUNTIME_INVISIBLE_ANNOTATIONS));
50              }
51          }
52      }
53  
54      private void checkAnnotationEntry(final AnnotationEntry a, final String name, final String elementname, final String elementvalue) {
55          assertEquals(name, a.getAnnotationType(), "Wrong AnnotationEntry name");
56          assertEquals(1, a.getElementValuePairs().length, "Wrong number of AnnotationEntry elements");
57          final ElementValuePair envp = a.getElementValuePairs()[0];
58          assertEquals(envp.getNameString(), elementname, "Wrong element name");
59          assertEquals(envp.getValue().stringifyValue(), elementvalue, "Wrong element value");
60      }
61  
62      /**
63       * Check field AnnotationEntrys are retrievable.
64       */
65      @Test
66      void testFieldAnnotationEntrys() throws ClassNotFoundException {
67          final JavaClass clazz = getTestJavaClass(PACKAGE_BASE_NAME + ".data.AnnotatedFields");
68          // TODO L...;?
69          checkAnnotatedField(clazz, "i", "L" + PACKAGE_BASE_SIG + "/data/SimpleAnnotation;", "id", "1");
70          checkAnnotatedField(clazz, "s", "L" + PACKAGE_BASE_SIG + "/data/SimpleAnnotation;", "id", "2");
71      }
72  
73      /**
74       * Check field AnnotationEntrys (de)serialize ok.
75       */
76      @Test
77      void testFieldAnnotationEntrysReadWrite() throws ClassNotFoundException, IOException {
78          final JavaClass clazz = getTestJavaClass(PACKAGE_BASE_NAME + ".data.AnnotatedFields");
79          checkAnnotatedField(clazz, "i", "L" + PACKAGE_BASE_SIG + "/data/SimpleAnnotation;", "id", "1");
80          checkAnnotatedField(clazz, "s", "L" + PACKAGE_BASE_SIG + "/data/SimpleAnnotation;", "id", "2");
81          // Write it out
82          final File tfile = createTestdataFile("AnnotatedFields.class");
83          clazz.dump(tfile);
84          final SyntheticRepository repos2 = createRepos(".");
85          repos2.loadClass("AnnotatedFields");
86          checkAnnotatedField(clazz, "i", "L" + PACKAGE_BASE_SIG + "/data/SimpleAnnotation;", "id", "1");
87          checkAnnotatedField(clazz, "s", "L" + PACKAGE_BASE_SIG + "/data/SimpleAnnotation;", "id", "2");
88          assertTrue(tfile.delete());
89      }
90  
91      /**
92       * Check we can load in a class, modify its field AnnotationEntrys, save it, reload it and everything is correct.
93       */
94      @Test
95      void testFieldAnnotationModification() throws ClassNotFoundException {
96          final boolean dbg = false;
97          final JavaClass clazz = getTestJavaClass(PACKAGE_BASE_NAME + ".data.AnnotatedFields");
98          final ClassGen clg = new ClassGen(clazz);
99          Field f = clg.getFields()[0];
100         if (dbg) {
101             System.err.println("Field in freshly constructed class is: " + f);
102         }
103         assertEquals("[@Lorg/apache/bcel/data/SimpleAnnotation;(id=1)]", dumpAnnotationEntries(f.getAnnotationEntries()));
104         if (dbg) {
105             System.err.println("AnnotationEntrys on field are: " + dumpAnnotationEntries(f.getAnnotationEntries()));
106         }
107         final AnnotationEntryGen fruitBasedAnnotationEntry = createFruitAnnotationEntry(clg.getConstantPool(), "Tomato", false);
108         final FieldGen fg = new FieldGen(f, clg.getConstantPool());
109         if (dbg) {
110             System.err.println("Adding AnnotationEntry to the field");
111         }
112         fg.addAnnotationEntry(fruitBasedAnnotationEntry);
113         if (dbg) {
114             System.err.println("FieldGen (mutable field) is " + fg);
115         }
116         if (dbg) {
117             System.err.println("with AnnotationEntrys: " + dumpAnnotationEntries(fg.getAnnotationEntries()));
118         }
119         if (dbg) {
120             System.err.println("Replacing original field with new field that has extra AnnotationEntry");
121         }
122         clg.removeField(f);
123         clg.addField(fg.getField());
124         f = clg.getFields()[1]; // there are two fields in the class, removing
125                                 // and readding has changed the order
126         // so this time index [1] is the 'int i' field
127         if (dbg) {
128             System.err.println("Field now looks like this: " + f);
129         }
130         if (dbg) {
131             System.err.println("With AnnotationEntrys: " + dumpAnnotationEntries(f.getAnnotationEntries()));
132         }
133         assertEquals(2, f.getAnnotationEntries().length, "Wrong number of AnnotationEntries");
134     }
135 }