Reconstructing a Class
Home ] Up ] [ Reconstructing a Class ] Inspecting a Class Instance ] Instantiating an Object ] Creating an Array ] Calling a Method ] An Example ]

 

 

Here's an example of how we can reconstruct a class using reflection. This program is a modification of the eariler program that used just the class Class.

First, for purposes of exposition, I've added another class which adds additional features to be reconstructed:

package reflection;

/* package private */ class Company
    implements HirerFirer
{
    public Company()
    {
    }
    
    public Company(String name, int maxEmps)
    {
        m_name = name;
        m_employees = new Employee[maxEmps];
    }
    
    public void init(String name, int maxEmps)
    {
        m_name = name;
        m_employees = new Employee[maxEmps];
    }
    
    public void hire(Employee emp)
    {
        m_employees[m_lastIndex++] = emp;
          // Will throw an exception if index out of bounds
        m_empCount++;
    }
    
    public void fire(Employee emp)
    {
        // Search for emp, and if found remove reference
        for (int i = 0; i < m_lastIndex; i++)
        {
            if (m_employees[i] == emp)
            {
                m_employees[i] = null;
                if (i == m_lastIndex)
                    m_lastIndex--;
                m_empCount--;
                return;
            }
        }
    }
    
    public Employee[] getEmployees()
    {
        return m_employees;
    }
    
    public void setEmployees(Employee[] emps)
    {
        m_employees = emps;
    }
    
    //// Data ////
    private String      m_name;
    private Employee[]  m_employees;
    private int         m_empCount = 0;
    private int         m_lastIndex = 0;
}

So here's the example program that reconstructs a class using reflection:

package reflection;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

public class ClassTestClass2
{
    public static void main(String[] args)
    {
        Class c;
        try
        {
            c = Class.forName("java.lang.String");
            printInfo(c);
        }
        catch(ClassNotFoundException e)
        {
            System.err.println("Class java.lang.String not found!");
        }
        c = int.class;
        printInfo(c);
        c = Double[].class;
        printInfo(c);
        c = int[].class;
        printInfo(c);
        short[] shortArray = new short[] {5, 10, 15};
        c = shortArray.getClass();
        printInfo(c);
        c = Person.class;
        printInfo(c);
        c = Employee.class;
        printInfo(c);
        c = Manager.class;
        printInfo(c);
        c = Hirer.class;
        printInfo(c);
        c = HirerFirer.class;
        printInfo(c);
        c = Company.class;
        printInfo(c);
        c = ClassTestClass2.class;
        printInfo(c);
    }
    
    private static void printInfo(Class c)
    {
        System.out.println("---- toString(): " + 
                           c.toString() + " ----");
        if (c.isPrimitive())
            printPrimitiveInfo(c);
        else if (c.isArray())
            printArrayInfo(c);
        else if (c.isInterface())
            printInterfaceInfo(c);
        else
            printClassInfo(c);
    }
    
    private static void printPrimitiveInfo(Class c)
    {
        String typeName = c.getName();
        System.out.println("Type " + typeName);
    }
    
    private static void printArrayInfo(Class c)
    {
        Class component = c.getComponentType();
        System.out.println("Array of " + component.getName());
    }
    
    private static String[] getPackageAndName(String name)
    {
        int index = name.lastIndexOf('.');
        String packageName = null;
        if (index != -1)
        {
            packageName = name.substring(0, index);
            name = name.substring(index+1, name.length());
        }
        
        return new String[] { packageName, name };
    }
    
    private static void printClassInfo(Class c)
    {
        String[] names = getPackageAndName(c.getName());
        String packageName = names[0];
        String className = names[1];

        if (packageName != null)
            System.out.println("package " + packageName + ";");
        
        int mods = c.getModifiers();
        System.out.println(Modifier.toString(mods) + 
                           " class " + className);

        Class superClass = c.getSuperclass();
        if (superClass != null)
            System.out.println(INDENT + INDENT + 
                               "extends " + superClass.getName());

        Class[] interfaces = c.getInterfaces();
        if ((interfaces != null) && (interfaces.length > 0))
        {
            System.out.print(INDENT + INDENT + "implements ");
            for (int i = 0; i < interfaces.length; i++)
            {
                if (i > 0)
                    System.out.print(", ");
                System.out.print(interfaces[i].getName());
            }
            System.out.println();
        }

        System.out.println("{");
        printMembers(c);
        System.out.println("}");
    }

    private static void printInterfaceInfo(Class c)
    {
        String[] names = getPackageAndName(c.getName());
        String packageName = names[0];
        String className = names[1];

        if (packageName != null)
            System.out.println("package " + packageName + ";");
        
        int mods = c.getModifiers();
        System.out.println(Modifier.toString(mods) + 
                           " interface " + className);

        Class[] interfaces = c.getInterfaces();
        if ((interfaces != null) && (interfaces.length > 0))
        {
            System.out.print(INDENT + INDENT + "extends ");
            for (int i = 0; i < interfaces.length; i++)
            {
                if (i > 0)
                    System.out.print(", ");
                System.out.print(interfaces[i].getName());
            }
            System.out.println();
        }

        System.out.println("{");
        printMembers(c);
        System.out.println("}");
    }
    
    private static void printMembers(Class c)
    {
        printConstructors(c);
        printMethods(c);
        printFields(c);
    }
    
    private static void printConstructors(Class c)
    {
        Constructor[] constructors = c.getDeclaredConstructors();
        for (int i = 0; i < constructors.length; i++)
        {
            if (i == 0)
                System.out.println(INDENT + "// Constructors");
            Constructor con = constructors[i];
            
            // Strip off package name from constructor name
            String[] names = getPackageAndName(con.getName());
            String conName = names[1];
            int mods = con.getModifiers();
            System.out.print(INDENT + Modifier.toString(mods));
            System.out.print(" " + conName);
            
            Class[] params = con.getParameterTypes();
            printParams(params);
            if (c.isInterface())
                System.out.println(";");
            else
            {
                System.out.println(" { " + 
                                   UNKNOWN_IMPLEMENTATION + 
                                   " }");
            }
        }
    }

    private static void printMethods(Class c)
    {
        Method[] methods = c.getDeclaredMethods();
        for (int i = 0; i < methods.length; i++)
        {
            if (i == 0)
                System.out.println(INDENT + "// Methods");
            Method method = methods[i];
            int mods = method.getModifiers();
            System.out.print(INDENT + Modifier.toString(mods));
            Class retType = method.getReturnType();
            System.out.print(" " + getArrayType(retType) + " " +
                             method.getName() );
            
            Class[] params = method.getParameterTypes();
            printParams(params);
            if (c.isInterface())
                System.out.println(";");
            else
                System.out.println(" { " + 
                                   UNKNOWN_IMPLEMENTATION + 
                                   " }");
        }
    }
    
    private static void printParams(Class[] params)
    {
        System.out.print("(");
        for (int i = 0; i < params.length; i++)
        {
            if (i > 0)
                System.out.print(", ");
            System.out.print(getArrayType(params[i]) + 
                             " p" + (i+1));
        }
        System.out.print(")");
    }
    
    private static void printFields(Class c)
    {
        Field[] fields = c.getDeclaredFields();
        for (int i = 0; i < fields.length; i++)
        {
            if (i == 0)
                System.out.println(INDENT + "// Fields");
            Field field = fields[i];
            int mods = field.getModifiers();
            System.out.print(INDENT + Modifier.toString(mods));
            Class type = field.getType();
            System.out.println(" " + getArrayType(type) + 
                               " " + field.getName() + ";");
        }
    }
    
    private static String getArrayType(Class c)
    {
        if (!c.isArray())
            return c.getName();
        else
        {
            // Use recursion to construct proper string
            String type = getArrayType(c.getComponentType());
            return type + "[]";
        }
    }
    
    private static final String UNKNOWN_IMPLEMENTATION = "/* ??? */";
    private static final String INDENT = "  ";
}

The program isn't quite complete, since it does not handle the following features:

  • Full throws specifications for constructors and methods
  • Nested and inner classes

Adding support for these features (and others?) is left as an exercise for the reader.

The above program produces the following output:

---- toString(): class java.lang.String ----
package java.lang;
public final synchronized class String
    extends java.lang.Object
    implements java.io.Serializable
{
  // Constructors
  public String() { /* ??? */ }
  public String(java.lang.String p1) { /* ??? */ }
  public String(char[] p1) { /* ??? */ }
  public String(char[] p1, int p2, int p3) { /* ??? */ }
  public String(byte[] p1, int p2, int p3, int p4) { /* ??? */ }
  public String(byte[] p1, int p2) { /* ??? */ }
  private String(byte[] p1, int p2, int p3, sun.io.ByteToCharConverter p4) { /* ??? */ }
  public String(byte[] p1, int p2, int p3, java.lang.String p4) { /* ??? */ }
  public String(byte[] p1, java.lang.String p2) { /* ??? */ }
  public String(byte[] p1, int p2, int p3) { /* ??? */ }
  public String(byte[] p1) { /* ??? */ }
  public String(java.lang.StringBuffer p1) { /* ??? */ }
  private String(int p1, int p2, char[] p3) { /* ??? */ }
  // Methods
  public int length() { /* ??? */ }
  public char charAt(int p1) { /* ??? */ }
  public void getChars(int p1, int p2, char[] p3, int p4) { /* ??? */ }
  public void getBytes(int p1, int p2, byte[] p3, int p4) { /* ??? */ }
  private byte[] getBytes(sun.io.CharToByteConverter p1) { /* ??? */ }
  public byte[] getBytes(java.lang.String p1) { /* ??? */ }
  public byte[] getBytes() { /* ??? */ }
  public boolean equals(java.lang.Object p1) { /* ??? */ }
  public boolean equalsIgnoreCase(java.lang.String p1) { /* ??? */ }
  public int compareTo(java.lang.String p1) { /* ??? */ }
  public boolean regionMatches(int p1, java.lang.String p2, int p3, int p4) { /* ??? */ }
  public boolean regionMatches(boolean p1, int p2, java.lang.String p3, int p4, int p5) { /* ??? */ }
  public boolean startsWith(java.lang.String p1, int p2) { /* ??? */ }
  public boolean startsWith(java.lang.String p1) { /* ??? */ }
  public boolean endsWith(java.lang.String p1) { /* ??? */ }
  public int hashCode() { /* ??? */ }
  public int indexOf(int p1) { /* ??? */ }
  public int indexOf(int p1, int p2) { /* ??? */ }
  public int lastIndexOf(int p1) { /* ??? */ }
  public int lastIndexOf(int p1, int p2) { /* ??? */ }
  public int indexOf(java.lang.String p1) { /* ??? */ }
  public int indexOf(java.lang.String p1, int p2) { /* ??? */ }
  public int lastIndexOf(java.lang.String p1) { /* ??? */ }
  public int lastIndexOf(java.lang.String p1, int p2) { /* ??? */ }
  public java.lang.String substring(int p1) { /* ??? */ }
  public java.lang.String substring(int p1, int p2) { /* ??? */ }
  public java.lang.String concat(java.lang.String p1) { /* ??? */ }
  public java.lang.String replace(char p1, char p2) { /* ??? */ }
  public java.lang.String toLowerCase(java.util.Locale p1) { /* ??? */ }
  public java.lang.String toLowerCase() { /* ??? */ }
  public java.lang.String toUpperCase(java.util.Locale p1) { /* ??? */ }
  public java.lang.String toUpperCase() { /* ??? */ }
  public java.lang.String trim() { /* ??? */ }
  public java.lang.String toString() { /* ??? */ }
  public char[] toCharArray() { /* ??? */ }
  public static java.lang.String valueOf(java.lang.Object p1) { /* ??? */ }
  public static java.lang.String valueOf(char[] p1) { /* ??? */ }
  public static java.lang.String valueOf(char[] p1, int p2, int p3) { /* ??? */ }
  public static java.lang.String copyValueOf(char[] p1, int p2, int p3) { /* ??? */ }
  public static java.lang.String copyValueOf(char[] p1) { /* ??? */ }
  public static java.lang.String valueOf(boolean p1) { /* ??? */ }
  public static java.lang.String valueOf(char p1) { /* ??? */ }
  public static java.lang.String valueOf(int p1) { /* ??? */ }
  public static java.lang.String valueOf(long p1) { /* ??? */ }
  public static java.lang.String valueOf(float p1) { /* ??? */ }
  public static java.lang.String valueOf(double p1) { /* ??? */ }
  public native java.lang.String intern() { /* ??? */ }
   int utfLength() { /* ??? */ }
  // Fields
  private char[] value;
  private int offset;
  private int count;
  private static final long serialVersionUID;
}
---- toString(): int ----
Type int
---- toString(): class [Ljava.lang.Double; ----
Array of java.lang.Double
---- toString(): class [I ----
Array of int
---- toString(): class [S ----
Array of short
---- toString(): class reflection.Person ----
package reflection;
public synchronized class Person
    extends java.lang.Object
{
  // Constructors
  public Person() { /* ??? */ }
  public Person(java.lang.String p1, int p2) { /* ??? */ }
  // Methods
  public int getAge() { /* ??? */ }
  public java.lang.String getName() { /* ??? */ }
  public void init(java.lang.String p1, int p2) { /* ??? */ }
  // Fields
  private java.lang.String m_name;
  private int m_age;
}
---- toString(): class reflection.Employee ----
package reflection;
public synchronized class Employee
    extends reflection.Person
{
  // Constructors
  public Employee() { /* ??? */ }
  public Employee(java.lang.String p1, int p2, double p3, long p4) { /* ??? */ }
  // Methods
  public long getId() { /* ??? */ }
  public double getSalary() { /* ??? */ }
  public void init(java.lang.String p1, int p2, double p3, long p4) { /* ??? */ }
  // Fields
  private double m_salary;
  private long m_id;
}
---- toString(): class reflection.Manager ----
package reflection;
public synchronized class Manager
    extends reflection.Employee
    implements reflection.Hirer, reflection.Firer
{
  // Constructors
  public Manager() { /* ??? */ }
  public Manager(java.lang.String p1, int p2, double p3, long p4) { /* ??? */ }
  // Methods
  public void fire(reflection.Employee p1) { /* ??? */ }
  public void hire(reflection.Employee p1) { /* ??? */ }
}
---- toString(): interface reflection.Hirer ----
package reflection;
public abstract interface interface Hirer
{
  // Methods
  public abstract void hire(reflection.Employee p1);
}
---- toString(): interface reflection.HirerFirer ----
package reflection;
public interface interface HirerFirer
    extends reflection.Hirer, reflection.Firer
{
}
---- toString(): class reflection.Company ----
package reflection;
synchronized class Company
    extends java.lang.Object
    implements reflection.HirerFirer
{
  // Constructors
  public Company() { /* ??? */ }
  public Company(java.lang.String p1, int p2) { /* ??? */ }
  // Methods
  public void fire(reflection.Employee p1) { /* ??? */ }
  public reflection.Employee[] getEmployees() { /* ??? */ }
  public void hire(reflection.Employee p1) { /* ??? */ }
  public void init(java.lang.String p1, int p2) { /* ??? */ }
  public void setEmployees(reflection.Employee[] p1) { /* ??? */ }
  // Fields
  private java.lang.String m_name;
  private reflection.Employee[] m_employees;
  private int m_empCount;
  private int m_lastIndex;
}
---- toString(): class reflection.ClassTestClass2 ----
package reflection;
public synchronized class ClassTestClass2
    extends java.lang.Object
{
  // Constructors
  public ClassTestClass2() { /* ??? */ }
  // Methods
  private static java.lang.String getArrayType(java.lang.Class p1) { /* ??? */ }
  private static java.lang.String[] getPackageAndName(java.lang.String p1) { /* ??? */ }
  public static void main(java.lang.String[] p1) { /* ??? */ }
  private static void printArrayInfo(java.lang.Class p1) { /* ??? */ }
  private static void printClassInfo(java.lang.Class p1) { /* ??? */ }
  private static void printConstructors(java.lang.Class p1) { /* ??? */ }
  private static void printFields(java.lang.Class p1) { /* ??? */ }
  private static void printInfo(java.lang.Class p1) { /* ??? */ }
  private static void printInterfaceInfo(java.lang.Class p1) { /* ??? */ }
  private static void printMembers(java.lang.Class p1) { /* ??? */ }
  private static void printMethods(java.lang.Class p1) { /* ??? */ }
  private static void printParams(java.lang.Class[] p1) { /* ??? */ }
  private static void printPrimitiveInfo(java.lang.Class p1) { /* ??? */ }
  static java.lang.Class class$(java.lang.String p1) { /* ??? */ }
  // Fields
  private static final java.lang.String UNKNOWN_IMPLEMENTATION;
  private static final java.lang.String INDENT;
  static java.lang.Class array$Ljava$lang$Double;
  static java.lang.Class array$I;
  static java.lang.Class class$reflection$Person;
  static java.lang.Class class$reflection$Employee;
  static java.lang.Class class$reflection$Manager;
  static java.lang.Class class$reflection$Hirer;
  static java.lang.Class class$reflection$HirerFirer;
  static java.lang.Class class$reflection$Company;
  static java.lang.Class class$reflection$ClassTestClass2;
}

(Note, in particular, the output for the class ClassTestClass2 itself is a little strange; it appears to have some extra static fields with strange names.)

 

The page was last updated February 19, 2008