You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

StubGenerator.java 8.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. /*
  2. * Javassist, a Java-bytecode translator toolkit.
  3. * Copyright (C) 1999-2005 Shigeru Chiba. All Rights Reserved.
  4. *
  5. * The contents of this file are subject to the Mozilla Public License Version
  6. * 1.1 (the "License"); you may not use this file except in compliance with
  7. * the License. Alternatively, the contents of this file may be used under
  8. * the terms of the GNU Lesser General Public License Version 2.1 or later.
  9. *
  10. * Software distributed under the License is distributed on an "AS IS" basis,
  11. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  12. * for the specific language governing rights and limitations under the
  13. * License.
  14. */
  15. package javassist.tools.rmi;
  16. import javassist.*;
  17. import java.lang.reflect.Method;
  18. import java.util.Hashtable;
  19. import javassist.CtMethod.ConstParameter;
  20. /**
  21. * A stub-code generator. It is used for producing a proxy class.
  22. *
  23. * <p>The proxy class for class A is as follows:
  24. *
  25. * <ul><pre>public class A implements Proxy, Serializable {
  26. * private ObjectImporter importer;
  27. * private int objectId;
  28. * public int _getObjectId() { return objectId; }
  29. * public A(ObjectImporter oi, int id) {
  30. * importer = oi; objectId = id;
  31. * }
  32. *
  33. * ... the same methods that the original class A declares ...
  34. * }</pre></ul>
  35. *
  36. * <p>Instances of the proxy class is created by an
  37. * <code>ObjectImporter</code> object.
  38. */
  39. public class StubGenerator implements Translator {
  40. private static final String fieldImporter = "importer";
  41. private static final String fieldObjectId = "objectId";
  42. private static final String accessorObjectId = "_getObjectId";
  43. private static final String sampleClass = "javassist.tools.rmi.Sample";
  44. private ClassPool classPool;
  45. private Hashtable proxyClasses;
  46. private CtMethod forwardMethod;
  47. private CtMethod forwardStaticMethod;
  48. private CtClass[] proxyConstructorParamTypes;
  49. private CtClass[] interfacesForProxy;
  50. private CtClass[] exceptionForProxy;
  51. /**
  52. * Constructs a stub-code generator.
  53. */
  54. public StubGenerator() {
  55. proxyClasses = new Hashtable();
  56. }
  57. /**
  58. * Initializes the object.
  59. * This is a method declared in javassist.Translator.
  60. *
  61. * @see javassist.Translator#start(ClassPool)
  62. */
  63. public void start(ClassPool pool) throws NotFoundException {
  64. classPool = pool;
  65. CtClass c = pool.get(sampleClass);
  66. forwardMethod = c.getDeclaredMethod("forward");
  67. forwardStaticMethod = c.getDeclaredMethod("forwardStatic");
  68. proxyConstructorParamTypes
  69. = pool.get(new String[] { "javassist.tools.rmi.ObjectImporter",
  70. "int" });
  71. interfacesForProxy
  72. = pool.get(new String[] { "java.io.Serializable",
  73. "javassist.tools.rmi.Proxy" });
  74. exceptionForProxy
  75. = new CtClass[] { pool.get("javassist.tools.rmi.RemoteException") };
  76. }
  77. /**
  78. * Does nothing.
  79. * This is a method declared in javassist.Translator.
  80. * @see javassist.Translator#onLoad(ClassPool,String)
  81. */
  82. public void onLoad(ClassPool pool, String classname) {}
  83. /**
  84. * Returns <code>true</code> if the specified class is a proxy class
  85. * recorded by <code>makeProxyClass()</code>.
  86. *
  87. * @param name a fully-qualified class name
  88. */
  89. public boolean isProxyClass(String name) {
  90. return proxyClasses.get(name) != null;
  91. }
  92. /**
  93. * Makes a proxy class. The produced class is substituted
  94. * for the original class.
  95. *
  96. * @param clazz the class referenced
  97. * through the proxy class.
  98. * @return <code>false</code> if the proxy class
  99. * has been already produced.
  100. */
  101. public synchronized boolean makeProxyClass(Class clazz)
  102. throws CannotCompileException, NotFoundException
  103. {
  104. String classname = clazz.getName();
  105. if (proxyClasses.get(classname) != null)
  106. return false;
  107. else {
  108. CtClass ctclazz = produceProxyClass(classPool.get(classname),
  109. clazz);
  110. proxyClasses.put(classname, ctclazz);
  111. modifySuperclass(ctclazz);
  112. return true;
  113. }
  114. }
  115. private CtClass produceProxyClass(CtClass orgclass, Class orgRtClass)
  116. throws CannotCompileException, NotFoundException
  117. {
  118. int modify = orgclass.getModifiers();
  119. if (Modifier.isAbstract(modify) || Modifier.isNative(modify)
  120. || !Modifier.isPublic(modify))
  121. throw new CannotCompileException(orgclass.getName()
  122. + " must be public, non-native, and non-abstract.");
  123. CtClass proxy = classPool.makeClass(orgclass.getName(),
  124. orgclass.getSuperclass());
  125. proxy.setInterfaces(interfacesForProxy);
  126. CtField f
  127. = new CtField(classPool.get("javassist.tools.rmi.ObjectImporter"),
  128. fieldImporter, proxy);
  129. f.setModifiers(Modifier.PRIVATE);
  130. proxy.addField(f, CtField.Initializer.byParameter(0));
  131. f = new CtField(CtClass.intType, fieldObjectId, proxy);
  132. f.setModifiers(Modifier.PRIVATE);
  133. proxy.addField(f, CtField.Initializer.byParameter(1));
  134. proxy.addMethod(CtNewMethod.getter(accessorObjectId, f));
  135. proxy.addConstructor(CtNewConstructor.defaultConstructor(proxy));
  136. CtConstructor cons
  137. = CtNewConstructor.skeleton(proxyConstructorParamTypes,
  138. null, proxy);
  139. proxy.addConstructor(cons);
  140. try {
  141. addMethods(proxy, orgRtClass.getMethods());
  142. return proxy;
  143. }
  144. catch (SecurityException e) {
  145. throw new CannotCompileException(e);
  146. }
  147. }
  148. private CtClass toCtClass(Class rtclass) throws NotFoundException {
  149. String name;
  150. if (!rtclass.isArray())
  151. name = rtclass.getName();
  152. else {
  153. StringBuffer sbuf = new StringBuffer();
  154. do {
  155. sbuf.append("[]");
  156. rtclass = rtclass.getComponentType();
  157. } while(rtclass.isArray());
  158. sbuf.insert(0, rtclass.getName());
  159. name = sbuf.toString();
  160. }
  161. return classPool.get(name);
  162. }
  163. private CtClass[] toCtClass(Class[] rtclasses) throws NotFoundException {
  164. int n = rtclasses.length;
  165. CtClass[] ctclasses = new CtClass[n];
  166. for (int i = 0; i < n; ++i)
  167. ctclasses[i] = toCtClass(rtclasses[i]);
  168. return ctclasses;
  169. }
  170. /* ms must not be an array of CtMethod. To invoke a method ms[i]
  171. * on a server, a client must send i to the server.
  172. */
  173. private void addMethods(CtClass proxy, Method[] ms)
  174. throws CannotCompileException, NotFoundException
  175. {
  176. CtMethod wmethod;
  177. for (int i = 0; i < ms.length; ++i) {
  178. Method m = ms[i];
  179. int mod = m.getModifiers();
  180. if (m.getDeclaringClass() != Object.class
  181. && !Modifier.isFinal(mod))
  182. if (Modifier.isPublic(mod)) {
  183. CtMethod body;
  184. if (Modifier.isStatic(mod))
  185. body = forwardStaticMethod;
  186. else
  187. body = forwardMethod;
  188. wmethod
  189. = CtNewMethod.wrapped(toCtClass(m.getReturnType()),
  190. m.getName(),
  191. toCtClass(m.getParameterTypes()),
  192. exceptionForProxy,
  193. body,
  194. ConstParameter.integer(i),
  195. proxy);
  196. wmethod.setModifiers(mod);
  197. proxy.addMethod(wmethod);
  198. }
  199. else if (!Modifier.isProtected(mod)
  200. && !Modifier.isPrivate(mod))
  201. // if package method
  202. throw new CannotCompileException(
  203. "the methods must be public, protected, or private.");
  204. }
  205. }
  206. /**
  207. * Adds a default constructor to the super classes.
  208. */
  209. private void modifySuperclass(CtClass orgclass)
  210. throws CannotCompileException, NotFoundException
  211. {
  212. CtClass superclazz;
  213. for (;; orgclass = superclazz) {
  214. superclazz = orgclass.getSuperclass();
  215. if (superclazz == null)
  216. break;
  217. try {
  218. superclazz.getDeclaredConstructor(null);
  219. break; // the constructor with no arguments is found.
  220. }
  221. catch (NotFoundException e) {
  222. }
  223. superclazz.addConstructor(
  224. CtNewConstructor.defaultConstructor(superclazz));
  225. }
  226. }
  227. }