
com.tangosol.dev.packager.ConstantPoolEntry Maven / Gradle / Ivy
/*
* Copyright (c) 2000, 2020, Oracle and/or its affiliates.
*
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
package com.tangosol.dev.packager;
import com.tangosol.dev.component.ComponentClassLoader;
import com.tangosol.dev.component.ComponentException;
import com.tangosol.util.Base;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.util.Hashtable;
/**
* This class is used to read and resolve references in the constants
* section of a Java class file for automatically determining the things
* that a class uses or depends on.
*
* TODO use the assembler
*/
public abstract class ConstantPoolEntry
extends Base
{
/**
* Return the object denoted by the constant reference.
*/
public Object getReferencedObject()
{
return(referencedObject);
}
/**
* Return an array of ConstantPoolEntry that represents the constants
* referenced in the class-file of the specified Java class in the context
* of the specified ClassLoader.
* Note that some elements of the array may be null, since long and
* double values occupy two slots each.
*/
public static ConstantPoolEntry[] getClassConstants(String javaClassName, ClassLoader classLoader)
throws IOException
{
// [gg] somehow a signature comes in!
if (javaClassName.startsWith("L") && javaClassName.endsWith(";"))
{
javaClassName = javaClassName.substring(1, javaClassName.length() - 1);
}
///
/// N.B. Resource paths used with ClassLoaders should not start with
/// a leading slash as they would with Class.getResource().
/// The reason for this is that Class.getResource() will prepend
/// the class's package name to the front of a resource with a
/// relative pathname, but leave an absolute pathname (one with a
/// leading slash) alone. ClassLoader.getResource() does no such
/// processing.
///
InputStream in = null;
if (classLoader instanceof ComponentClassLoader)
{
try
{
byte[] ab = ((ComponentClassLoader) classLoader).loadClassData(javaClassName);
if (ab != null)
{
in = new ByteArrayInputStream(ab);
}
}
catch (ComponentException e)
{
throw new IOException(e.toString());
}
}
else
{
String resourcePath = javaClassName.replace('.', '/') + ".class";
in = classLoader.getResourceAsStream(resourcePath);
}
if (in == null)
{
throw new IOException("Cannot find class: " + javaClassName);
}
DataInputStream dstream = new DataInputStream(in);
// Read the magic number and verify it.
int magicNumber = dstream.readInt();
if (magicNumber != 0xCafeBabe)
{
throw new RuntimeException(javaClassName + ": Bad class-file magic number: " + Integer.toString(magicNumber, 16));
}
// read the minor and major version numbers
int minorVersion = dstream.readUnsignedShort();
int majorVersion = dstream.readUnsignedShort();
// read the constant pool
int constantPoolCount = dstream.readUnsignedShort();
ConstantPoolEntry constantPool[] = new ConstantPoolEntry[constantPoolCount];
constantPool[0] = null;
for (int i = 1; i < constantPoolCount; i++)
{
try
{
byte tag = (byte)dstream.readUnsignedByte();
constantPool[i] = ConstantPoolEntry.decode(tag, dstream, constantPool);
if (tag == CONSTANT_LONG || tag == CONSTANT_DOUBLE)
{
// All 8-byte constants (longs and doubles) use 2 slots in the
// constant pool, so skip the next slot in these cases.
i++;
constantPool[i] = null;
}
}
catch (IOException e)
{
out(javaClassName + ": constantPool[" + i + "]: " + e.getMessage());
out(e);
}
}
// Run through the constant pool to resolve things as required.
for (int i=1; i 1)
{
args += ", ";
}
args += arg;
}
args += ")";
return(nameAndTypeString(strRdr, "") + name + args);
}
case ')':
// only happens during a argument list parse
return(null);
default:
throw new IOException();
}
}
/**
* Parse the JVM signature and return number of words represented by
* the type read.
*/
int parse(StringReader strRdr)
throws IOException
{
int byteVal = strRdr.read();
switch (byteVal)
{
case 'B': // byte
case 'C': // char
case 'I': // int
case 'F': // float
case 'S': // short
case 'Z': // boolean
return(1);
case 'D': // double
case 'J': // long
return(2);
case 'V': // void
return(0);
case '[': // array
parse(strRdr); // read and discard element type
return(1);
case 'L':
{ // class name terminated by semicolon
int c = strRdr.read();
while ((c != -1) && (c != ';'))
{
c = strRdr.read();
}
return(1);
}
case '(':
{
int arg;
while ((arg = parse(strRdr)) != 0)
{
// nothing more needs to be done
}
// return the number of words in the result type
return(parse(strRdr));
}
case ')':
// only happens during a argument-list parse
return(0);
default:
throw new IOException();
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy