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.classfile;
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.assertThrows;
25  import static org.junit.jupiter.api.Assertions.fail;
26  
27  import java.io.IOException;
28  
29  import org.apache.bcel.AbstractTest;
30  import org.apache.bcel.Const;
31  import org.apache.bcel.generic.ConstantPoolGen;
32  import org.apache.bcel.generic.InstructionHandle;
33  import org.apache.bcel.generic.MethodGen;
34  import org.apache.bcel.util.ClassPath;
35  import org.apache.bcel.util.ClassPathRepository;
36  import org.junit.jupiter.api.Test;
37  
38  final class ClassWithDoubleConstantPoolItem {
39      double d = 42; // here is the key; we need a double constant value
40  }
41  
42  final class ClassWithLongConstantPoolItem {
43      long l = 42; // here is the key; we need a double constant value
44  }
45  
46  class ConstantPoolTest extends AbstractTest {
47  
48      private static InstructionHandle[] getInstructionHandles(final JavaClass clazz, final ConstantPoolGen cp, final Method method) {
49          final MethodGen methodGen = new MethodGen(method, clazz.getClassName(), cp);
50          return methodGen.getInstructionList().getInstructionHandles();
51      }
52  
53      @Test
54      void testClassWithDoubleConstantPoolItem() throws ClassNotFoundException, IOException {
55          try (ClassPath cp = new ClassPath("target/test-classes/org/apache/bcel/classfile")) {
56              final ClassWithDoubleConstantPoolItem classWithDoubleConstantPoolItem = new ClassWithDoubleConstantPoolItem();
57              final JavaClass c = new ClassPathRepository(cp).loadClass(classWithDoubleConstantPoolItem.getClass());
58              final Field[] fields = c.getFields();
59              assertNotNull(fields);
60              assertEquals(1, fields.length);
61              assertEquals(ClassWithDoubleConstantPoolItem.class.getDeclaredFields()[0].getName(), fields[0].getName());
62              final ConstantPool pool = c.getConstantPool();
63              for (int i = 1; i < pool.getLength(); i++) {
64                  try {
65                      final Constant constant = pool.getConstant(i);
66                      if (constant instanceof ConstantDouble) {
67                          assertEquals(classWithDoubleConstantPoolItem.d, ((ConstantDouble) constant).getBytes());
68                          // Next constant pool entry will be invalid so skip it
69                          i++;
70                      }
71                  } catch (final Throwable t) {
72                      t.printStackTrace();
73                      fail();
74                  }
75              }
76          }
77      }
78  
79      @Test
80      void testClassWithLongConstantPoolItem() throws ClassNotFoundException, IOException {
81          try (ClassPath cp = new ClassPath("target/test-classes/org/apache/bcel/classfile")) {
82              final ClassWithLongConstantPoolItem classWithLongConstantPoolItem = new ClassWithLongConstantPoolItem();
83              final JavaClass c = new ClassPathRepository(cp).loadClass(classWithLongConstantPoolItem.getClass());
84              final Field[] fields = c.getFields();
85              assertNotNull(fields);
86              assertEquals(1, fields.length);
87              assertEquals(ClassWithLongConstantPoolItem.class.getDeclaredFields()[0].getName(), fields[0].getName());
88              final ConstantPool pool = c.getConstantPool();
89              for (int i = 1; i < pool.getLength(); i++) {
90                  try {
91                      final Constant constant = pool.getConstant(i);
92                      if (constant instanceof ConstantLong) {
93                          assertEquals(classWithLongConstantPoolItem.l, ((ConstantLong) constant).getBytes());
94                          // Next constant pool entry will be invalid so skip it
95                          i++;
96                      }
97                  } catch (final Throwable t) {
98                      t.printStackTrace();
99                      fail();
100                 }
101             }
102         }
103     }
104 
105     @Test
106     void testConstantToString() throws ClassNotFoundException {
107         final JavaClass clazz = getTestJavaClass(PACKAGE_BASE_NAME + ".data.SimpleClassWithDefaultConstructor");
108         final ConstantPoolGen cp = new ConstantPoolGen(clazz.getConstantPool());
109         final Method[] methods = clazz.getMethods();
110         for (final Method method : methods) {
111             if (method.getName().equals("<init>")) {
112                 for (final InstructionHandle instructionHandle : getInstructionHandles(clazz, cp, method)) {
113                     final String instruction = instructionHandle.getInstruction().toString(cp.getConstantPool());
114                     assertNotNull(instruction);
115                     switch (instructionHandle.getPosition()) {
116                         case 0:
117                             assertEquals("aload_0", instruction);
118                             break;
119                         case 1:
120                             assertEquals("invokespecial java/lang/Object/<init>()V", instruction);
121                             break;
122                         case 4:
123                             assertEquals("return", instruction);
124                             break;
125                         default:
126                             break;
127                     }
128                 }
129             }
130         }
131     }
132 
133     @Test
134     void testTooManyConstants() throws ClassNotFoundException {
135         final JavaClass clazz = getTestJavaClass(PACKAGE_BASE_NAME + ".data.SimpleClassWithDefaultConstructor");
136         final ConstantPoolGen cp = new ConstantPoolGen(clazz.getConstantPool());
137         int i = cp.getSize();
138         while (i < Const.MAX_CP_ENTRIES - 1) {
139             cp.addLong(i);
140             i = cp.getSize(); // i += 2
141         }
142         assertThrows(IllegalStateException.class, () -> cp.addLong(0));
143     }
144 }