/*
 * Javassist, a Java-bytecode translator toolkit.
 * Copyright (C) 1999- Shigeru Chiba. All Rights Reserved.
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License.  Alternatively, the contents of this file may be used under
 * the terms of the GNU Lesser General Public License Version 2.1 or later,
 * or the Apache License Version 2.0.
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 */

package javassist.tools.rmi;

import java.lang.reflect.Method;
import java.util.Hashtable;
import java.util.Map;

import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtConstructor;
import javassist.CtField;
import javassist.CtMethod;
import javassist.CtMethod.ConstParameter;
import javassist.CtNewConstructor;
import javassist.CtNewMethod;
import javassist.Modifier;
import javassist.NotFoundException;
import javassist.Translator;

A stub-code generator. It is used for producing a proxy class.

The proxy class for class A is as follows:

public class A implements Proxy, Serializable {
  private ObjectImporter importer;
  private int objectId;
  public int _getObjectId() { return objectId; }
  public A(ObjectImporter oi, int id) {
    importer = oi; objectId = id;
  }
  ... the same methods that the original class A declares ...
}

Instances of the proxy class is created by an ObjectImporter object.

/** * A stub-code generator. It is used for producing a proxy class. * * <p>The proxy class for class A is as follows: * * <pre>public class A implements Proxy, Serializable { * private ObjectImporter importer; * private int objectId; * public int _getObjectId() { return objectId; } * public A(ObjectImporter oi, int id) { * importer = oi; objectId = id; * } * * ... the same methods that the original class A declares ... * }</pre> * * <p>Instances of the proxy class is created by an * <code>ObjectImporter</code> object. */
public class StubGenerator implements Translator { private static final String fieldImporter = "importer"; private static final String fieldObjectId = "objectId"; private static final String accessorObjectId = "_getObjectId"; private static final String sampleClass = "javassist.tools.rmi.Sample"; private ClassPool classPool; private Map<String,CtClass> proxyClasses; private CtMethod forwardMethod; private CtMethod forwardStaticMethod; private CtClass[] proxyConstructorParamTypes; private CtClass[] interfacesForProxy; private CtClass[] exceptionForProxy;
Constructs a stub-code generator.
/** * Constructs a stub-code generator. */
public StubGenerator() { proxyClasses = new Hashtable<String,CtClass>(); }
Initializes the object. This is a method declared in javassist.Translator.
See Also:
  • start.start(ClassPool)
/** * Initializes the object. * This is a method declared in javassist.Translator. * * @see javassist.Translator#start(ClassPool) */
@Override public void start(ClassPool pool) throws NotFoundException { classPool = pool; CtClass c = pool.get(sampleClass); forwardMethod = c.getDeclaredMethod("forward"); forwardStaticMethod = c.getDeclaredMethod("forwardStatic"); proxyConstructorParamTypes = pool.get(new String[] { "javassist.tools.rmi.ObjectImporter", "int" }); interfacesForProxy = pool.get(new String[] { "java.io.Serializable", "javassist.tools.rmi.Proxy" }); exceptionForProxy = new CtClass[] { pool.get("javassist.tools.rmi.RemoteException") }; }
Does nothing. This is a method declared in javassist.Translator.
See Also:
  • onLoad.onLoad(ClassPool, String)
/** * Does nothing. * This is a method declared in javassist.Translator. * @see javassist.Translator#onLoad(ClassPool,String) */
@Override public void onLoad(ClassPool pool, String classname) {}
Returns true if the specified class is a proxy class recorded by makeProxyClass().
Params:
  • name – a fully-qualified class name
/** * Returns <code>true</code> if the specified class is a proxy class * recorded by <code>makeProxyClass()</code>. * * @param name a fully-qualified class name */
public boolean isProxyClass(String name) { return proxyClasses.get(name) != null; }
Makes a proxy class. The produced class is substituted for the original class.
Params:
  • clazz – the class referenced through the proxy class.
Returns: false if the proxy class has been already produced.
/** * Makes a proxy class. The produced class is substituted * for the original class. * * @param clazz the class referenced * through the proxy class. * @return <code>false</code> if the proxy class * has been already produced. */
public synchronized boolean makeProxyClass(Class<?> clazz) throws CannotCompileException, NotFoundException { String classname = clazz.getName(); if (proxyClasses.get(classname) != null) return false; CtClass ctclazz = produceProxyClass(classPool.get(classname), clazz); proxyClasses.put(classname, ctclazz); modifySuperclass(ctclazz); return true; } private CtClass produceProxyClass(CtClass orgclass, Class<?> orgRtClass) throws CannotCompileException, NotFoundException { int modify = orgclass.getModifiers(); if (Modifier.isAbstract(modify) || Modifier.isNative(modify) || !Modifier.isPublic(modify)) throw new CannotCompileException(orgclass.getName() + " must be public, non-native, and non-abstract."); CtClass proxy = classPool.makeClass(orgclass.getName(), orgclass.getSuperclass()); proxy.setInterfaces(interfacesForProxy); CtField f = new CtField(classPool.get("javassist.tools.rmi.ObjectImporter"), fieldImporter, proxy); f.setModifiers(Modifier.PRIVATE); proxy.addField(f, CtField.Initializer.byParameter(0)); f = new CtField(CtClass.intType, fieldObjectId, proxy); f.setModifiers(Modifier.PRIVATE); proxy.addField(f, CtField.Initializer.byParameter(1)); proxy.addMethod(CtNewMethod.getter(accessorObjectId, f)); proxy.addConstructor(CtNewConstructor.defaultConstructor(proxy)); CtConstructor cons = CtNewConstructor.skeleton(proxyConstructorParamTypes, null, proxy); proxy.addConstructor(cons); try { addMethods(proxy, orgRtClass.getMethods()); return proxy; } catch (SecurityException e) { throw new CannotCompileException(e); } } private CtClass toCtClass(Class<?> rtclass) throws NotFoundException { String name; if (!rtclass.isArray()) name = rtclass.getName(); else { StringBuffer sbuf = new StringBuffer(); do { sbuf.append("[]"); rtclass = rtclass.getComponentType(); } while(rtclass.isArray()); sbuf.insert(0, rtclass.getName()); name = sbuf.toString(); } return classPool.get(name); } private CtClass[] toCtClass(Class<?>[] rtclasses) throws NotFoundException { int n = rtclasses.length; CtClass[] ctclasses = new CtClass[n]; for (int i = 0; i < n; ++i) ctclasses[i] = toCtClass(rtclasses[i]); return ctclasses; } /* ms must not be an array of CtMethod. To invoke a method ms[i] * on a server, a client must send i to the server. */ private void addMethods(CtClass proxy, Method[] ms) throws CannotCompileException, NotFoundException { CtMethod wmethod; for (int i = 0; i < ms.length; ++i) { Method m = ms[i]; int mod = m.getModifiers(); if (m.getDeclaringClass() != Object.class && !Modifier.isFinal(mod)) if (Modifier.isPublic(mod)) { CtMethod body; if (Modifier.isStatic(mod)) body = forwardStaticMethod; else body = forwardMethod; wmethod = CtNewMethod.wrapped(toCtClass(m.getReturnType()), m.getName(), toCtClass(m.getParameterTypes()), exceptionForProxy, body, ConstParameter.integer(i), proxy); wmethod.setModifiers(mod); proxy.addMethod(wmethod); } else if (!Modifier.isProtected(mod) && !Modifier.isPrivate(mod)) // if package method throw new CannotCompileException( "the methods must be public, protected, or private."); } }
Adds a default constructor to the super classes.
/** * Adds a default constructor to the super classes. */
private void modifySuperclass(CtClass orgclass) throws CannotCompileException, NotFoundException { CtClass superclazz; for (;; orgclass = superclazz) { superclazz = orgclass.getSuperclass(); if (superclazz == null) break; try { superclazz.getDeclaredConstructor(null); break; // the constructor with no arguments is found. } catch (NotFoundException e) { } superclazz.addConstructor( CtNewConstructor.defaultConstructor(superclazz)); } } }