/*
 *  Licensed to the Apache Software Foundation (ASF) under one or more
 *  contributor license agreements.  See the NOTICE file distributed with
 *  this work for additional information regarding copyright ownership.
 *  The ASF licenses this file to You under the Apache License, Version 2.0
 *  (the "License"); you may not use this file except in compliance with
 *  the License.  You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 */
package org.apache.tools.ant.taskdefs.optional.depend.constantpool;

import java.io.DataInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

The constant pool of a Java class. The constant pool is a collection of constants used in a Java class file. It stores strings, constant values, class names, method names, field names etc.
See Also:
/** * The constant pool of a Java class. The constant pool is a collection of * constants used in a Java class file. It stores strings, constant values, * class names, method names, field names etc. * * @see <a href="https://docs.oracle.com/javase/specs/index.html">The Java Virtual * Machine Specification</a> */
public class ConstantPool {
The entries in the constant pool.
/** The entries in the constant pool. */
private final List<ConstantPoolEntry> entries = new ArrayList<>();
A Hashtable of UTF8 entries - used to get constant pool indexes of the UTF8 values quickly
/** * A Hashtable of UTF8 entries - used to get constant pool indexes of * the UTF8 values quickly */
private final Map<String, Integer> utf8Indexes = new HashMap<>();
Initialise the constant pool.
/** Initialise the constant pool. */
public ConstantPool() { // The zero index is never present in the constant pool itself so // we add a null entry for it entries.add(null); }
Read the constant pool from a class input stream.
Params:
  • classStream – the DataInputStream of a class file.
Throws:
  • IOException – if there is a problem reading the constant pool from the stream
/** * Read the constant pool from a class input stream. * * @param classStream the DataInputStream of a class file. * @exception IOException if there is a problem reading the constant pool * from the stream */
public void read(DataInputStream classStream) throws IOException { int numEntries = classStream.readUnsignedShort(); for (int i = 1; i < numEntries;) { ConstantPoolEntry nextEntry = ConstantPoolEntry.readEntry(classStream); i += nextEntry.getNumEntries(); addEntry(nextEntry); } }
Get the size of the constant pool.
Returns:the size of the constant pool
/** * Get the size of the constant pool. * * @return the size of the constant pool */
public int size() { return entries.size(); }
Add an entry to the constant pool.
Params:
  • entry – the new entry to be added to the constant pool.
Returns:the index into the constant pool at which the entry is stored.
/** * Add an entry to the constant pool. * * @param entry the new entry to be added to the constant pool. * @return the index into the constant pool at which the entry is * stored. */
public int addEntry(ConstantPoolEntry entry) { int index = entries.size(); entries.add(entry); int numSlots = entry.getNumEntries(); // add null entries for any additional slots required. for (int j = 0; j < numSlots - 1; ++j) { entries.add(null); } if (entry instanceof Utf8CPInfo) { Utf8CPInfo utf8Info = (Utf8CPInfo) entry; utf8Indexes.put(utf8Info.getValue(), index); } return index; }
Resolve the entries in the constant pool. Resolution of the constant pool involves transforming indexes to other constant pool entries into the actual data for that entry.
/** * Resolve the entries in the constant pool. Resolution of the constant * pool involves transforming indexes to other constant pool entries * into the actual data for that entry. */
public void resolve() { for (ConstantPoolEntry poolInfo : entries) { if (poolInfo != null && !poolInfo.isResolved()) { poolInfo.resolve(this); } } }
Get an constant pool entry at a particular index.
Params:
  • index – the index into the constant pool.
Returns:the constant pool entry at that index.
/** * Get an constant pool entry at a particular index. * * @param index the index into the constant pool. * @return the constant pool entry at that index. */
public ConstantPoolEntry getEntry(int index) { return entries.get(index); }
Get the index of a given UTF8 constant pool entry.
Params:
  • value – the string value of the UTF8 entry.
Returns:the index at which the given string occurs in the constant pool or -1 if the value does not occur.
/** * Get the index of a given UTF8 constant pool entry. * * @param value the string value of the UTF8 entry. * @return the index at which the given string occurs in the constant * pool or -1 if the value does not occur. */
public int getUTF8Entry(String value) { int index = -1; Integer indexInteger = utf8Indexes.get(value); if (indexInteger != null) { index = indexInteger; } return index; }
Get the index of a given CONSTANT_CLASS entry in the constant pool.
Params:
  • className – the name of the class for which the class entry index is required.
Returns:the index at which the given class entry occurs in the constant pool or -1 if the value does not occur.
/** * Get the index of a given CONSTANT_CLASS entry in the constant pool. * * @param className the name of the class for which the class entry * index is required. * @return the index at which the given class entry occurs in the * constant pool or -1 if the value does not occur. */
public int getClassEntry(String className) { int index = -1; final int size = entries.size(); for (int i = 0; i < size && index == -1; ++i) { Object element = entries.get(i); if (element instanceof ClassCPInfo) { ClassCPInfo classinfo = (ClassCPInfo) element; if (classinfo.getClassName().equals(className)) { index = i; } } } return index; }
Get the index of a given constant value entry in the constant pool.
Params:
  • constantValue – the constant value for which the index is required.
Returns:the index at which the given value entry occurs in the constant pool or -1 if the value does not occur.
/** * Get the index of a given constant value entry in the constant pool. * * @param constantValue the constant value for which the index is * required. * @return the index at which the given value entry occurs in the * constant pool or -1 if the value does not occur. */
public int getConstantEntry(Object constantValue) { int index = -1; final int size = entries.size(); for (int i = 0; i < size && index == -1; ++i) { Object element = entries.get(i); if (element instanceof ConstantCPInfo) { ConstantCPInfo constantEntry = (ConstantCPInfo) element; if (constantEntry.getValue().equals(constantValue)) { index = i; } } } return index; }
Get the index of a given CONSTANT_METHODREF entry in the constant pool.
Params:
  • methodClassName – the name of the class which contains the method being referenced.
  • methodName – the name of the method being referenced.
  • methodType – the type descriptor of the method being referenced.
Returns:the index at which the given method ref entry occurs in the constant pool or -1 if the value does not occur.
/** * Get the index of a given CONSTANT_METHODREF entry in the constant * pool. * * @param methodClassName the name of the class which contains the * method being referenced. * @param methodName the name of the method being referenced. * @param methodType the type descriptor of the method being referenced. * @return the index at which the given method ref entry occurs in the * constant pool or -1 if the value does not occur. */
public int getMethodRefEntry(String methodClassName, String methodName, String methodType) { int index = -1; final int size = entries.size(); for (int i = 0; i < size && index == -1; ++i) { Object element = entries.get(i); if (element instanceof MethodRefCPInfo) { MethodRefCPInfo methodRefEntry = (MethodRefCPInfo) element; if (methodRefEntry.getMethodClassName().equals(methodClassName) && methodRefEntry.getMethodName().equals(methodName) && methodRefEntry.getMethodType().equals(methodType)) { index = i; } } } return index; }
Get the index of a given CONSTANT_INTERFACEMETHODREF entry in the constant pool.
Params:
  • interfaceMethodClassName – the name of the interface which contains the method being referenced.
  • interfaceMethodName – the name of the method being referenced.
  • interfaceMethodType – the type descriptor of the method being referenced.
Returns:the index at which the given method ref entry occurs in the constant pool or -1 if the value does not occur.
/** * Get the index of a given CONSTANT_INTERFACEMETHODREF entry in the * constant pool. * * @param interfaceMethodClassName the name of the interface which * contains the method being referenced. * @param interfaceMethodName the name of the method being referenced. * @param interfaceMethodType the type descriptor of the method being * referenced. * @return the index at which the given method ref entry occurs in the * constant pool or -1 if the value does not occur. */
public int getInterfaceMethodRefEntry(String interfaceMethodClassName, String interfaceMethodName, String interfaceMethodType) { int index = -1; final int size = entries.size(); for (int i = 0; i < size && index == -1; ++i) { Object element = entries.get(i); if (element instanceof InterfaceMethodRefCPInfo) { InterfaceMethodRefCPInfo interfaceMethodRefEntry = (InterfaceMethodRefCPInfo) element; if (interfaceMethodRefEntry.getInterfaceMethodClassName().equals( interfaceMethodClassName) && interfaceMethodRefEntry.getInterfaceMethodName().equals( interfaceMethodName) && interfaceMethodRefEntry.getInterfaceMethodType().equals( interfaceMethodType)) { index = i; } } } return index; }
Get the index of a given CONSTANT_FIELDREF entry in the constant pool.
Params:
  • fieldClassName – the name of the class which contains the field being referenced.
  • fieldName – the name of the field being referenced.
  • fieldType – the type descriptor of the field being referenced.
Returns:the index at which the given field ref entry occurs in the constant pool or -1 if the value does not occur.
/** * Get the index of a given CONSTANT_FIELDREF entry in the constant * pool. * * @param fieldClassName the name of the class which contains the field * being referenced. * @param fieldName the name of the field being referenced. * @param fieldType the type descriptor of the field being referenced. * @return the index at which the given field ref entry occurs in the * constant pool or -1 if the value does not occur. */
public int getFieldRefEntry(String fieldClassName, String fieldName, String fieldType) { int index = -1; final int size = entries.size(); for (int i = 0; i < size && index == -1; ++i) { Object element = entries.get(i); if (element instanceof FieldRefCPInfo) { FieldRefCPInfo fieldRefEntry = (FieldRefCPInfo) element; if (fieldRefEntry.getFieldClassName().equals(fieldClassName) && fieldRefEntry.getFieldName().equals(fieldName) && fieldRefEntry.getFieldType().equals(fieldType)) { index = i; } } } return index; }
Get the index of a given CONSTANT_NAMEANDTYPE entry in the constant pool.
Params:
  • name – the name
  • type – the type
Returns:the index at which the given NameAndType entry occurs in the constant pool or -1 if the value does not occur.
/** * Get the index of a given CONSTANT_NAMEANDTYPE entry in the constant * pool. * * @param name the name * @param type the type * @return the index at which the given NameAndType entry occurs in the * constant pool or -1 if the value does not occur. */
public int getNameAndTypeEntry(String name, String type) { int index = -1; final int size = entries.size(); for (int i = 0; i < size && index == -1; ++i) { Object element = entries.get(i); if (element instanceof NameAndTypeCPInfo) { NameAndTypeCPInfo nameAndTypeEntry = (NameAndTypeCPInfo) element; if (nameAndTypeEntry.getName().equals(name) && nameAndTypeEntry.getType().equals(type)) { index = i; } } } return index; }
Dump the constant pool to a string.
Returns:the constant pool entries as strings
/** * Dump the constant pool to a string. * * @return the constant pool entries as strings */
@Override public String toString() { return IntStream.range(0, entries.size()) .mapToObj(i -> String.format("[%d] = %s", i, getEntry(i))) .collect(Collectors.joining("\n", "\n", "\n")); } }