diff -r 783d04ecccc3 -r b1f360639517 src/jdk.rmic/share/classes/sun/rmi/rmic/newrmic/jrmp/StubSkeletonWriter.java --- a/src/jdk.rmic/share/classes/sun/rmi/rmic/newrmic/jrmp/StubSkeletonWriter.java Fri Nov 03 09:56:02 2017 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1079 +0,0 @@ -/* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package sun.rmi.rmic.newrmic.jrmp; - -import com.sun.javadoc.ClassDoc; -import com.sun.javadoc.MethodDoc; -import com.sun.javadoc.Type; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import sun.rmi.rmic.newrmic.BatchEnvironment; -import sun.rmi.rmic.newrmic.IndentingWriter; - -import static sun.rmi.rmic.newrmic.Constants.*; -import static sun.rmi.rmic.newrmic.jrmp.Constants.*; - -/** - * Writes the source code for the stub class and (optionally) skeleton - * class for a particular remote implementation class. - * - * WARNING: The contents of this source file are not part of any - * supported API. Code that depends on them does so at its own risk: - * they are subject to change or removal without notice. - * - * @author Peter Jones - **/ -class StubSkeletonWriter { - - /** rmic environment for this object */ - private final BatchEnvironment env; - - /** the remote implementation class to generate code for */ - private final RemoteClass remoteClass; - - /** version of the JRMP stub protocol to generate code for */ - private final StubVersion version; - - /* - * binary names of the stub and skeleton classes to generate for - * the remote class - */ - private final String stubClassName; - private final String skeletonClassName; - - /* package name and simple names of the stub and skeleton classes */ - private final String packageName; - private final String stubClassSimpleName; - private final String skeletonClassSimpleName; - - /** remote methods of class, indexed by operation number */ - private final RemoteClass.Method[] remoteMethods; - - /** - * Names to use for the java.lang.reflect.Method static fields in - * the generated stub class corresponding to each remote method. - **/ - private final String[] methodFieldNames; - - /** - * Creates a StubSkeletonWriter instance for the specified remote - * implementation class. The generated code will implement the - * specified JRMP stub protocol version. - **/ - StubSkeletonWriter(BatchEnvironment env, - RemoteClass remoteClass, - StubVersion version) - { - this.env = env; - this.remoteClass = remoteClass; - this.version = version; - - stubClassName = Util.binaryNameOf(remoteClass.classDoc()) + "_Stub"; - skeletonClassName = - Util.binaryNameOf(remoteClass.classDoc()) + "_Skel"; - - int i = stubClassName.lastIndexOf('.'); - packageName = (i != -1 ? stubClassName.substring(0, i) : ""); - stubClassSimpleName = stubClassName.substring(i + 1); - skeletonClassSimpleName = skeletonClassName.substring(i + 1); - - remoteMethods = remoteClass.remoteMethods(); - methodFieldNames = nameMethodFields(remoteMethods); - } - - /** - * Returns the binary name of the stub class to generate for the - * remote implementation class. - **/ - String stubClassName() { - return stubClassName; - } - - /** - * Returns the binary name of the skeleton class to generate for - * the remote implementation class. - **/ - String skeletonClassName() { - return skeletonClassName; - } - - /** - * Writes the stub class for the remote class to a stream. - **/ - void writeStub(IndentingWriter p) throws IOException { - - /* - * Write boiler plate comment. - */ - p.pln("// Stub class generated by rmic, do not edit."); - p.pln("// Contents subject to change without notice."); - p.pln(); - - /* - * If remote implementation class was in a particular package, - * declare the stub class to be in the same package. - */ - if (!packageName.equals("")) { - p.pln("package " + packageName + ";"); - p.pln(); - } - - /* - * Declare the stub class; implement all remote interfaces. - */ - p.plnI("public final class " + stubClassSimpleName); - p.pln("extends " + REMOTE_STUB); - ClassDoc[] remoteInterfaces = remoteClass.remoteInterfaces(); - if (remoteInterfaces.length > 0) { - p.p("implements "); - for (int i = 0; i < remoteInterfaces.length; i++) { - if (i > 0) { - p.p(", "); - } - p.p(remoteInterfaces[i].qualifiedName()); - } - p.pln(); - } - p.pOlnI("{"); - - if (version == StubVersion.V1_1 || - version == StubVersion.VCOMPAT) - { - writeOperationsArray(p); - p.pln(); - writeInterfaceHash(p); - p.pln(); - } - - if (version == StubVersion.VCOMPAT || - version == StubVersion.V1_2) - { - p.pln("private static final long serialVersionUID = " + - STUB_SERIAL_VERSION_UID + ";"); - p.pln(); - - /* - * We only need to declare and initialize the static fields of - * Method objects for each remote method if there are any remote - * methods; otherwise, skip this code entirely, to avoid generating - * a try/catch block for a checked exception that cannot occur - * (see bugid 4125181). - */ - if (methodFieldNames.length > 0) { - if (version == StubVersion.VCOMPAT) { - p.pln("private static boolean useNewInvoke;"); - } - writeMethodFieldDeclarations(p); - p.pln(); - - /* - * Initialize java.lang.reflect.Method fields for each remote - * method in a static initializer. - */ - p.plnI("static {"); - p.plnI("try {"); - if (version == StubVersion.VCOMPAT) { - /* - * Fat stubs must determine whether the API required for - * the JDK 1.2 stub protocol is supported in the current - * runtime, so that it can use it if supported. This is - * determined by using the Reflection API to test if the - * new invoke method on RemoteRef exists, and setting the - * static boolean "useNewInvoke" to true if it does, or - * to false if a NoSuchMethodException is thrown. - */ - p.plnI(REMOTE_REF + ".class.getMethod(\"invoke\","); - p.plnI("new java.lang.Class[] {"); - p.pln(REMOTE + ".class,"); - p.pln("java.lang.reflect.Method.class,"); - p.pln("java.lang.Object[].class,"); - p.pln("long.class"); - p.pOln("});"); - p.pO(); - p.pln("useNewInvoke = true;"); - } - writeMethodFieldInitializers(p); - p.pOlnI("} catch (java.lang.NoSuchMethodException e) {"); - if (version == StubVersion.VCOMPAT) { - p.pln("useNewInvoke = false;"); - } else { - p.plnI("throw new java.lang.NoSuchMethodError("); - p.pln("\"stub class initialization failed\");"); - p.pO(); - } - p.pOln("}"); // end try/catch block - p.pOln("}"); // end static initializer - p.pln(); - } - } - - writeStubConstructors(p); - p.pln(); - - /* - * Write each stub method. - */ - if (remoteMethods.length > 0) { - p.pln("// methods from remote interfaces"); - for (int i = 0; i < remoteMethods.length; ++i) { - p.pln(); - writeStubMethod(p, i); - } - } - - p.pOln("}"); // end stub class - } - - /** - * Writes the constructors for the stub class. - **/ - private void writeStubConstructors(IndentingWriter p) - throws IOException - { - p.pln("// constructors"); - - /* - * Only stubs compatible with the JDK 1.1 stub protocol need - * a no-arg constructor; later versions use reflection to find - * the constructor that directly takes a RemoteRef argument. - */ - if (version == StubVersion.V1_1 || - version == StubVersion.VCOMPAT) - { - p.plnI("public " + stubClassSimpleName + "() {"); - p.pln("super();"); - p.pOln("}"); - } - - p.plnI("public " + stubClassSimpleName + "(" + REMOTE_REF + " ref) {"); - p.pln("super(ref);"); - p.pOln("}"); - } - - /** - * Writes the stub method for the remote method with the given - * operation number. - **/ - private void writeStubMethod(IndentingWriter p, int opnum) - throws IOException - { - RemoteClass.Method method = remoteMethods[opnum]; - MethodDoc methodDoc = method.methodDoc(); - String methodName = methodDoc.name(); - Type[] paramTypes = method.parameterTypes(); - String paramNames[] = nameParameters(paramTypes); - Type returnType = methodDoc.returnType(); - ClassDoc[] exceptions = method.exceptionTypes(); - - /* - * Declare stub method; throw exceptions declared in remote - * interface(s). - */ - p.pln("// implementation of " + - Util.getFriendlyUnqualifiedSignature(methodDoc)); - p.p("public " + returnType.toString() + " " + methodName + "("); - for (int i = 0; i < paramTypes.length; i++) { - if (i > 0) { - p.p(", "); - } - p.p(paramTypes[i].toString() + " " + paramNames[i]); - } - p.plnI(")"); - if (exceptions.length > 0) { - p.p("throws "); - for (int i = 0; i < exceptions.length; i++) { - if (i > 0) { - p.p(", "); - } - p.p(exceptions[i].qualifiedName()); - } - p.pln(); - } - p.pOlnI("{"); - - /* - * The RemoteRef.invoke methods throw Exception, but unless - * this stub method throws Exception as well, we must catch - * Exceptions thrown from the invocation. So we must catch - * Exception and rethrow something we can throw: - * UnexpectedException, which is a subclass of - * RemoteException. But for any subclasses of Exception that - * we can throw, like RemoteException, RuntimeException, and - * any of the exceptions declared by this stub method, we want - * them to pass through unmodified, so first we must catch any - * such exceptions and rethrow them directly. - * - * We have to be careful generating the rethrowing catch - * blocks here, because javac will flag an error if there are - * any unreachable catch blocks, i.e. if the catch of an - * exception class follows a previous catch of it or of one of - * its superclasses. The following method invocation takes - * care of these details. - */ - List catchList = computeUniqueCatchList(exceptions); - - /* - * If we need to catch any particular exceptions (i.e. this method - * does not declare java.lang.Exception), put the entire stub - * method in a try block. - */ - if (catchList.size() > 0) { - p.plnI("try {"); - } - - if (version == StubVersion.VCOMPAT) { - p.plnI("if (useNewInvoke) {"); - } - if (version == StubVersion.VCOMPAT || - version == StubVersion.V1_2) - { - if (!Util.isVoid(returnType)) { - p.p("Object $result = "); // REMIND: why $? - } - p.p("ref.invoke(this, " + methodFieldNames[opnum] + ", "); - if (paramTypes.length > 0) { - p.p("new java.lang.Object[] {"); - for (int i = 0; i < paramTypes.length; i++) { - if (i > 0) - p.p(", "); - p.p(wrapArgumentCode(paramTypes[i], paramNames[i])); - } - p.p("}"); - } else { - p.p("null"); - } - p.pln(", " + method.methodHash() + "L);"); - if (!Util.isVoid(returnType)) { - p.pln("return " + - unwrapArgumentCode(returnType, "$result") + ";"); - } - } - if (version == StubVersion.VCOMPAT) { - p.pOlnI("} else {"); - } - if (version == StubVersion.V1_1 || - version == StubVersion.VCOMPAT) - { - p.pln(REMOTE_CALL + " call = ref.newCall((" + REMOTE_OBJECT + - ") this, operations, " + opnum + ", interfaceHash);"); - - if (paramTypes.length > 0) { - p.plnI("try {"); - p.pln("java.io.ObjectOutput out = call.getOutputStream();"); - writeMarshalArguments(p, "out", paramTypes, paramNames); - p.pOlnI("} catch (java.io.IOException e) {"); - p.pln("throw new " + MARSHAL_EXCEPTION + - "(\"error marshalling arguments\", e);"); - p.pOln("}"); - } - - p.pln("ref.invoke(call);"); - - if (Util.isVoid(returnType)) { - p.pln("ref.done(call);"); - } else { - p.pln(returnType.toString() + " $result;"); - // REMIND: why $? - p.plnI("try {"); - p.pln("java.io.ObjectInput in = call.getInputStream();"); - boolean objectRead = - writeUnmarshalArgument(p, "in", returnType, "$result"); - p.pln(";"); - p.pOlnI("} catch (java.io.IOException e) {"); - p.pln("throw new " + UNMARSHAL_EXCEPTION + - "(\"error unmarshalling return\", e);"); - /* - * If any only if readObject has been invoked, we must catch - * ClassNotFoundException as well as IOException. - */ - if (objectRead) { - p.pOlnI("} catch (java.lang.ClassNotFoundException e) {"); - p.pln("throw new " + UNMARSHAL_EXCEPTION + - "(\"error unmarshalling return\", e);"); - } - p.pOlnI("} finally {"); - p.pln("ref.done(call);"); - p.pOln("}"); - p.pln("return $result;"); - } - } - if (version == StubVersion.VCOMPAT) { - p.pOln("}"); // end if/else (useNewInvoke) block - } - - /* - * If we need to catch any particular exceptions, finally write - * the catch blocks for them, rethrow any other Exceptions with an - * UnexpectedException, and end the try block. - */ - if (catchList.size() > 0) { - for (ClassDoc catchClass : catchList) { - p.pOlnI("} catch (" + catchClass.qualifiedName() + " e) {"); - p.pln("throw e;"); - } - p.pOlnI("} catch (java.lang.Exception e) {"); - p.pln("throw new " + UNEXPECTED_EXCEPTION + - "(\"undeclared checked exception\", e);"); - p.pOln("}"); // end try/catch block - } - - p.pOln("}"); // end stub method - } - - /** - * Computes the exceptions that need to be caught and rethrown in - * a stub method before wrapping Exceptions in - * UnexpectedExceptions, given the exceptions declared in the - * throws clause of the method. Returns a list containing the - * exception to catch. Each exception is guaranteed to be unique, - * i.e. not a subclass of any of the other exceptions in the list, - * so the catch blocks for these exceptions may be generated in - * any order relative to each other. - * - * RemoteException and RuntimeException are each automatically - * placed in the returned list (unless any of their superclasses - * are already present), since those exceptions should always be - * directly rethrown by a stub method. - * - * The returned list will be empty if java.lang.Exception or one - * of its superclasses is in the throws clause of the method, - * indicating that no exceptions need to be caught. - **/ - private List computeUniqueCatchList(ClassDoc[] exceptions) { - List uniqueList = new ArrayList(); - - uniqueList.add(env.docRuntimeException()); - uniqueList.add(env.docRemoteException()); // always catch/rethrow these - - /* For each exception declared by the stub method's throws clause: */ - nextException: - for (ClassDoc ex : exceptions) { - if (env.docException().subclassOf(ex)) { - /* - * If java.lang.Exception (or a superclass) was declared - * in the throws clause of this stub method, then we don't - * have to bother catching anything; clear the list and - * return. - */ - uniqueList.clear(); - break; - } else if (!ex.subclassOf(env.docException())) { - /* - * Ignore other Throwables that do not extend Exception, - * because they cannot be thrown by the invoke methods. - */ - continue; - } - /* - * Compare this exception against the current list of - * exceptions that need to be caught: - */ - for (Iterator i = uniqueList.iterator(); i.hasNext();) { - ClassDoc ex2 = i.next(); - if (ex.subclassOf(ex2)) { - /* - * If a superclass of this exception is already on - * the list to catch, then ignore this one and continue; - */ - continue nextException; - } else if (ex2.subclassOf(ex)) { - /* - * If a subclass of this exception is on the list - * to catch, then remove it; - */ - i.remove(); - } - } - /* This exception is unique: add it to the list to catch. */ - uniqueList.add(ex); - } - return uniqueList; - } - - /** - * Writes the skeleton for the remote class to a stream. - **/ - void writeSkeleton(IndentingWriter p) throws IOException { - if (version == StubVersion.V1_2) { - throw new AssertionError( - "should not generate skeleton for version " + version); - } - - /* - * Write boiler plate comment. - */ - p.pln("// Skeleton class generated by rmic, do not edit."); - p.pln("// Contents subject to change without notice."); - p.pln(); - - /* - * If remote implementation class was in a particular package, - * declare the skeleton class to be in the same package. - */ - if (!packageName.equals("")) { - p.pln("package " + packageName + ";"); - p.pln(); - } - - /* - * Declare the skeleton class. - */ - p.plnI("public final class " + skeletonClassSimpleName); - p.pln("implements " + SKELETON); - p.pOlnI("{"); - - writeOperationsArray(p); - p.pln(); - - writeInterfaceHash(p); - p.pln(); - - /* - * Define the getOperations() method. - */ - p.plnI("public " + OPERATION + "[] getOperations() {"); - p.pln("return (" + OPERATION + "[]) operations.clone();"); - p.pOln("}"); - p.pln(); - - /* - * Define the dispatch() method. - */ - p.plnI("public void dispatch(" + REMOTE + " obj, " + - REMOTE_CALL + " call, int opnum, long hash)"); - p.pln("throws java.lang.Exception"); - p.pOlnI("{"); - - if (version == StubVersion.VCOMPAT) { - p.plnI("if (opnum < 0) {"); - if (remoteMethods.length > 0) { - for (int opnum = 0; opnum < remoteMethods.length; opnum++) { - if (opnum > 0) - p.pO("} else "); - p.plnI("if (hash == " + - remoteMethods[opnum].methodHash() + "L) {"); - p.pln("opnum = " + opnum + ";"); - } - p.pOlnI("} else {"); - } - /* - * Skeleton throws UnmarshalException if it does not recognize - * the method hash; this is what UnicastServerRef.dispatch() - * would do. - */ - p.pln("throw new " + - UNMARSHAL_EXCEPTION + "(\"invalid method hash\");"); - if (remoteMethods.length > 0) { - p.pOln("}"); - } - /* - * Ignore the validation of the interface hash if the - * operation number was negative, since it is really a - * method hash instead. - */ - p.pOlnI("} else {"); - } - - p.plnI("if (hash != interfaceHash)"); - p.pln("throw new " + - SKELETON_MISMATCH_EXCEPTION + "(\"interface hash mismatch\");"); - p.pO(); - - if (version == StubVersion.VCOMPAT) { - p.pOln("}"); // end if/else (opnum < 0) block - } - p.pln(); - - /* - * Cast remote object reference to the remote implementation - * class, if it's not private. We don't use the binary name - * of the class like previous implementations did because that - * would not compile with javac (since 1.4.1). If the remote - * implementation class is private, then we can't cast to it - * like previous implementations did because that also would - * not compile with javac-- so instead, we'll have to try to - * cast to the remote interface for each remote method. - */ - if (!remoteClass.classDoc().isPrivate()) { - p.pln(remoteClass.classDoc().qualifiedName() + " server = (" + - remoteClass.classDoc().qualifiedName() + ") obj;"); - } - - /* - * Process call according to the operation number. - */ - p.plnI("switch (opnum) {"); - for (int opnum = 0; opnum < remoteMethods.length; opnum++) { - writeSkeletonDispatchCase(p, opnum); - } - p.pOlnI("default:"); - /* - * Skeleton throws UnmarshalException if it does not recognize - * the operation number; this is consistent with the case of an - * unrecognized method hash. - */ - p.pln("throw new " + UNMARSHAL_EXCEPTION + - "(\"invalid method number\");"); - p.pOln("}"); // end switch statement - - p.pOln("}"); // end dispatch() method - - p.pOln("}"); // end skeleton class - } - - /** - * Writes the case block for the skeleton's dispatch method for - * the remote method with the given "opnum". - **/ - private void writeSkeletonDispatchCase(IndentingWriter p, int opnum) - throws IOException - { - RemoteClass.Method method = remoteMethods[opnum]; - MethodDoc methodDoc = method.methodDoc(); - String methodName = methodDoc.name(); - Type paramTypes[] = method.parameterTypes(); - String paramNames[] = nameParameters(paramTypes); - Type returnType = methodDoc.returnType(); - - p.pOlnI("case " + opnum + ": // " + - Util.getFriendlyUnqualifiedSignature(methodDoc)); - /* - * Use nested block statement inside case to provide an independent - * namespace for local variables used to unmarshal parameters for - * this remote method. - */ - p.pOlnI("{"); - - if (paramTypes.length > 0) { - /* - * Declare local variables to hold arguments. - */ - for (int i = 0; i < paramTypes.length; i++) { - p.pln(paramTypes[i].toString() + " " + paramNames[i] + ";"); - } - - /* - * Unmarshal arguments from call stream. - */ - p.plnI("try {"); - p.pln("java.io.ObjectInput in = call.getInputStream();"); - boolean objectsRead = writeUnmarshalArguments(p, "in", - paramTypes, paramNames); - p.pOlnI("} catch (java.io.IOException e) {"); - p.pln("throw new " + UNMARSHAL_EXCEPTION + - "(\"error unmarshalling arguments\", e);"); - /* - * If any only if readObject has been invoked, we must catch - * ClassNotFoundException as well as IOException. - */ - if (objectsRead) { - p.pOlnI("} catch (java.lang.ClassNotFoundException e) {"); - p.pln("throw new " + UNMARSHAL_EXCEPTION + - "(\"error unmarshalling arguments\", e);"); - } - p.pOlnI("} finally {"); - p.pln("call.releaseInputStream();"); - p.pOln("}"); - } else { - p.pln("call.releaseInputStream();"); - } - - if (!Util.isVoid(returnType)) { - /* - * Declare variable to hold return type, if not void. - */ - p.p(returnType.toString() + " $result = "); - // REMIND: why $? - } - - /* - * Invoke the method on the server object. If the remote - * implementation class is private, then we don't have a - * reference cast to it, and so we try to cast to the remote - * object reference to the method's declaring interface here. - */ - String target = remoteClass.classDoc().isPrivate() ? - "((" + methodDoc.containingClass().qualifiedName() + ") obj)" : - "server"; - p.p(target + "." + methodName + "("); - for (int i = 0; i < paramNames.length; i++) { - if (i > 0) - p.p(", "); - p.p(paramNames[i]); - } - p.pln(");"); - - /* - * Always invoke getResultStream(true) on the call object to send - * the indication of a successful invocation to the caller. If - * the return type is not void, keep the result stream and marshal - * the return value. - */ - p.plnI("try {"); - if (!Util.isVoid(returnType)) { - p.p("java.io.ObjectOutput out = "); - } - p.pln("call.getResultStream(true);"); - if (!Util.isVoid(returnType)) { - writeMarshalArgument(p, "out", returnType, "$result"); - p.pln(";"); - } - p.pOlnI("} catch (java.io.IOException e) {"); - p.pln("throw new " + - MARSHAL_EXCEPTION + "(\"error marshalling return\", e);"); - p.pOln("}"); - - p.pln("break;"); // break from switch statement - - p.pOlnI("}"); // end nested block statement - p.pln(); - } - - /** - * Writes declaration and initializer for "operations" static array. - **/ - private void writeOperationsArray(IndentingWriter p) - throws IOException - { - p.plnI("private static final " + OPERATION + "[] operations = {"); - for (int i = 0; i < remoteMethods.length; i++) { - if (i > 0) - p.pln(","); - p.p("new " + OPERATION + "(\"" + - remoteMethods[i].operationString() + "\")"); - } - p.pln(); - p.pOln("};"); - } - - /** - * Writes declaration and initializer for "interfaceHash" static field. - **/ - private void writeInterfaceHash(IndentingWriter p) - throws IOException - { - p.pln("private static final long interfaceHash = " + - remoteClass.interfaceHash() + "L;"); - } - - /** - * Writes declaration for java.lang.reflect.Method static fields - * corresponding to each remote method in a stub. - **/ - private void writeMethodFieldDeclarations(IndentingWriter p) - throws IOException - { - for (String name : methodFieldNames) { - p.pln("private static java.lang.reflect.Method " + name + ";"); - } - } - - /** - * Writes code to initialize the static fields for each method - * using the Java Reflection API. - **/ - private void writeMethodFieldInitializers(IndentingWriter p) - throws IOException - { - for (int i = 0; i < methodFieldNames.length; i++) { - p.p(methodFieldNames[i] + " = "); - /* - * Look up the Method object in the somewhat arbitrary - * interface that we find in the Method object. - */ - RemoteClass.Method method = remoteMethods[i]; - MethodDoc methodDoc = method.methodDoc(); - String methodName = methodDoc.name(); - Type paramTypes[] = method.parameterTypes(); - - p.p(methodDoc.containingClass().qualifiedName() + ".class.getMethod(\"" + - methodName + "\", new java.lang.Class[] {"); - for (int j = 0; j < paramTypes.length; j++) { - if (j > 0) - p.p(", "); - p.p(paramTypes[j].toString() + ".class"); - } - p.pln("});"); - } - } - - - /* - * Following are a series of static utility methods useful during - * the code generation process: - */ - - /** - * Generates an array of names for fields correspondins to the - * given array of remote methods. Each name in the returned array - * is guaranteed to be unique. - * - * The name of a method is included in its corresponding field - * name to enhance readability of the generated code. - **/ - private static String[] nameMethodFields(RemoteClass.Method[] methods) { - String[] names = new String[methods.length]; - for (int i = 0; i < names.length; i++) { - names[i] = "$method_" + methods[i].methodDoc().name() + "_" + i; - } - return names; - } - - /** - * Generates an array of names for parameters corresponding to the - * given array of types for the parameters. Each name in the - * returned array is guaranteed to be unique. - * - * A representation of the type of a parameter is included in its - * corresponding parameter name to enhance the readability of the - * generated code. - **/ - private static String[] nameParameters(Type[] types) { - String[] names = new String[types.length]; - for (int i = 0; i < names.length; i++) { - names[i] = "$param_" + - generateNameFromType(types[i]) + "_" + (i + 1); - } - return names; - } - - /** - * Generates a readable string representing the given type - * suitable for embedding within a Java identifier. - **/ - private static String generateNameFromType(Type type) { - String name = type.typeName().replace('.', '$'); - int dimensions = type.dimension().length() / 2; - for (int i = 0; i < dimensions; i++) { - name = "arrayOf_" + name; - } - return name; - } - - /** - * Writes a snippet of Java code to marshal a value named "name" - * of type "type" to the java.io.ObjectOutput stream named - * "stream". - * - * Primitive types are marshalled with their corresponding methods - * in the java.io.DataOutput interface, and objects (including - * arrays) are marshalled using the writeObject method. - **/ - private static void writeMarshalArgument(IndentingWriter p, - String streamName, - Type type, String name) - throws IOException - { - if (type.dimension().length() > 0 || type.asClassDoc() != null) { - p.p(streamName + ".writeObject(" + name + ")"); - } else if (type.typeName().equals("boolean")) { - p.p(streamName + ".writeBoolean(" + name + ")"); - } else if (type.typeName().equals("byte")) { - p.p(streamName + ".writeByte(" + name + ")"); - } else if (type.typeName().equals("char")) { - p.p(streamName + ".writeChar(" + name + ")"); - } else if (type.typeName().equals("short")) { - p.p(streamName + ".writeShort(" + name + ")"); - } else if (type.typeName().equals("int")) { - p.p(streamName + ".writeInt(" + name + ")"); - } else if (type.typeName().equals("long")) { - p.p(streamName + ".writeLong(" + name + ")"); - } else if (type.typeName().equals("float")) { - p.p(streamName + ".writeFloat(" + name + ")"); - } else if (type.typeName().equals("double")) { - p.p(streamName + ".writeDouble(" + name + ")"); - } else { - throw new AssertionError(type); - } - } - - /** - * Writes Java statements to marshal a series of values in order - * as named in the "names" array, with types as specified in the - * "types" array, to the java.io.ObjectOutput stream named - * "stream". - **/ - private static void writeMarshalArguments(IndentingWriter p, - String streamName, - Type[] types, String[] names) - throws IOException - { - assert types.length == names.length; - - for (int i = 0; i < types.length; i++) { - writeMarshalArgument(p, streamName, types[i], names[i]); - p.pln(";"); - } - } - - /** - * Writes a snippet of Java code to unmarshal a value of type - * "type" from the java.io.ObjectInput stream named "stream" into - * a variable named "name" (if "name" is null, the value is - * unmarshalled and discarded). - * - * Primitive types are unmarshalled with their corresponding - * methods in the java.io.DataInput interface, and objects - * (including arrays) are unmarshalled using the readObject - * method. - * - * Returns true if code to invoke readObject was written, and - * false otherwise. - **/ - private static boolean writeUnmarshalArgument(IndentingWriter p, - String streamName, - Type type, String name) - throws IOException - { - boolean readObject = false; - - if (name != null) { - p.p(name + " = "); - } - - if (type.dimension().length() > 0 || type.asClassDoc() != null) { - p.p("(" + type.toString() + ") " + streamName + ".readObject()"); - readObject = true; - } else if (type.typeName().equals("boolean")) { - p.p(streamName + ".readBoolean()"); - } else if (type.typeName().equals("byte")) { - p.p(streamName + ".readByte()"); - } else if (type.typeName().equals("char")) { - p.p(streamName + ".readChar()"); - } else if (type.typeName().equals("short")) { - p.p(streamName + ".readShort()"); - } else if (type.typeName().equals("int")) { - p.p(streamName + ".readInt()"); - } else if (type.typeName().equals("long")) { - p.p(streamName + ".readLong()"); - } else if (type.typeName().equals("float")) { - p.p(streamName + ".readFloat()"); - } else if (type.typeName().equals("double")) { - p.p(streamName + ".readDouble()"); - } else { - throw new AssertionError(type); - } - - return readObject; - } - - /** - * Writes Java statements to unmarshal a series of values in order - * of types as in the "types" array from the java.io.ObjectInput - * stream named "stream" into variables as named in "names" (for - * any element of "names" that is null, the corresponding value is - * unmarshalled and discarded). - **/ - private static boolean writeUnmarshalArguments(IndentingWriter p, - String streamName, - Type[] types, - String[] names) - throws IOException - { - assert types.length == names.length; - - boolean readObject = false; - for (int i = 0; i < types.length; i++) { - if (writeUnmarshalArgument(p, streamName, types[i], names[i])) { - readObject = true; - } - p.pln(";"); - } - return readObject; - } - - /** - * Returns a snippet of Java code to wrap a value named "name" of - * type "type" into an object as appropriate for use by the Java - * Reflection API. - * - * For primitive types, an appropriate wrapper class is - * instantiated with the primitive value. For object types - * (including arrays), no wrapping is necessary, so the value is - * named directly. - **/ - private static String wrapArgumentCode(Type type, String name) { - if (type.dimension().length() > 0 || type.asClassDoc() != null) { - return name; - } else if (type.typeName().equals("boolean")) { - return ("(" + name + - " ? java.lang.Boolean.TRUE : java.lang.Boolean.FALSE)"); - } else if (type.typeName().equals("byte")) { - return "new java.lang.Byte(" + name + ")"; - } else if (type.typeName().equals("char")) { - return "new java.lang.Character(" + name + ")"; - } else if (type.typeName().equals("short")) { - return "new java.lang.Short(" + name + ")"; - } else if (type.typeName().equals("int")) { - return "new java.lang.Integer(" + name + ")"; - } else if (type.typeName().equals("long")) { - return "new java.lang.Long(" + name + ")"; - } else if (type.typeName().equals("float")) { - return "new java.lang.Float(" + name + ")"; - } else if (type.typeName().equals("double")) { - return "new java.lang.Double(" + name + ")"; - } else { - throw new AssertionError(type); - } - } - - /** - * Returns a snippet of Java code to unwrap a value named "name" - * into a value of type "type", as appropriate for the Java - * Reflection API. - * - * For primitive types, the value is assumed to be of the - * corresponding wrapper class, and a method is called on the - * wrapper to retrieve the primitive value. For object types - * (include arrays), no unwrapping is necessary; the value is - * simply cast to the expected real object type. - **/ - private static String unwrapArgumentCode(Type type, String name) { - if (type.dimension().length() > 0 || type.asClassDoc() != null) { - return "((" + type.toString() + ") " + name + ")"; - } else if (type.typeName().equals("boolean")) { - return "((java.lang.Boolean) " + name + ").booleanValue()"; - } else if (type.typeName().equals("byte")) { - return "((java.lang.Byte) " + name + ").byteValue()"; - } else if (type.typeName().equals("char")) { - return "((java.lang.Character) " + name + ").charValue()"; - } else if (type.typeName().equals("short")) { - return "((java.lang.Short) " + name + ").shortValue()"; - } else if (type.typeName().equals("int")) { - return "((java.lang.Integer) " + name + ").intValue()"; - } else if (type.typeName().equals("long")) { - return "((java.lang.Long) " + name + ").longValue()"; - } else if (type.typeName().equals("float")) { - return "((java.lang.Float) " + name + ").floatValue()"; - } else if (type.typeName().equals("double")) { - return "((java.lang.Double) " + name + ").doubleValue()"; - } else { - throw new AssertionError(type); - } - } -}