com.tangosol.dev.packager.ConstantPoolEntry Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of coherence Show documentation
Show all versions of coherence Show documentation
Oracle Coherence Community Edition
/*
* Copyright (c) 2000, 2021, 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();
}
}
}
}