All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.tangosol.dev.packager.ConstantPoolEntry Maven / Gradle / Ivy

There is a newer version: 24.09
Show newest version
/*
 * 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();
                }
            }
        }
    }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy