0N/A/*
2362N/A * Copyright (c) 1997, 2007, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/A/*****************************************************************************/
0N/A/* Copyright (c) IBM Corporation 1998 */
0N/A/* */
0N/A/* (C) Copyright IBM Corp. 1998 */
0N/A/* */
0N/A/*****************************************************************************/
0N/A
0N/Apackage sun.rmi.rmic;
0N/A
0N/Aimport java.io.File;
0N/Aimport java.io.FileOutputStream;
0N/Aimport java.io.OutputStreamWriter;
0N/Aimport java.io.IOException;
0N/Aimport java.util.Enumeration;
0N/Aimport java.util.Hashtable;
0N/Aimport java.util.Vector;
0N/Aimport sun.tools.java.Type;
0N/Aimport sun.tools.java.Identifier;
0N/Aimport sun.tools.java.ClassDefinition;
0N/Aimport sun.tools.java.ClassDeclaration;
0N/Aimport sun.tools.java.ClassNotFound;
0N/Aimport sun.tools.java.ClassFile;
0N/Aimport sun.tools.java.MemberDefinition;
0N/Aimport com.sun.corba.se.impl.util.Utility;
0N/A
0N/A/**
0N/A * A Generator object will generate the Java source code of the stub
0N/A * and skeleton classes for an RMI remote implementation class, using
0N/A * a particular stub protocol version.
0N/A *
0N/A * WARNING: The contents of this source file are not part of any
0N/A * supported API. Code that depends on them does so at its own risk:
0N/A * they are subject to change or removal without notice.
0N/A *
0N/A * @author Peter Jones, Bryan Atsatt
0N/A */
0N/Apublic class RMIGenerator implements RMIConstants, Generator {
0N/A
5561N/A private static final Hashtable<String, Integer> versionOptions = new Hashtable<>();
0N/A static {
0N/A versionOptions.put("-v1.1", new Integer(STUB_VERSION_1_1));
0N/A versionOptions.put("-vcompat", new Integer(STUB_VERSION_FAT));
0N/A versionOptions.put("-v1.2", new Integer(STUB_VERSION_1_2));
0N/A }
0N/A
0N/A /**
0N/A * Default constructor for Main to use.
0N/A */
0N/A public RMIGenerator() {
0N/A version = STUB_VERSION_1_2; // default is -v1.2 (see 4638155)
0N/A }
0N/A
0N/A /**
0N/A * Examine and consume command line arguments.
0N/A * @param argv The command line arguments. Ignore null
0N/A * and unknown arguments. Set each consumed argument to null.
0N/A * @param error Report any errors using the main.error() methods.
0N/A * @return true if no errors, false otherwise.
0N/A */
0N/A public boolean parseArgs(String argv[], Main main) {
0N/A String explicitVersion = null;
0N/A for (int i = 0; i < argv.length; i++) {
0N/A if (argv[i] != null) {
0N/A String arg = argv[i].toLowerCase();
0N/A if (versionOptions.containsKey(arg)) {
0N/A if (explicitVersion != null &&
0N/A !explicitVersion.equals(arg))
0N/A {
0N/A main.error("rmic.cannot.use.both",
0N/A explicitVersion, arg);
0N/A return false;
0N/A }
0N/A explicitVersion = arg;
5561N/A version = versionOptions.get(arg);
0N/A argv[i] = null;
0N/A }
0N/A }
0N/A }
0N/A return true;
0N/A }
0N/A
0N/A /**
0N/A * Generate the source files for the stub and/or skeleton classes
0N/A * needed by RMI for the given remote implementation class.
0N/A *
0N/A * @param env compiler environment
0N/A * @param cdef definition of remote implementation class
0N/A * to generate stubs and/or skeletons for
0N/A * @param destDir directory for the root of the package hierarchy
0N/A * for generated files
0N/A */
0N/A public void generate(BatchEnvironment env, ClassDefinition cdef, File destDir) {
0N/A RemoteClass remoteClass = RemoteClass.forClass(env, cdef);
0N/A if (remoteClass == null) // exit if an error occurred
0N/A return;
0N/A
0N/A RMIGenerator gen;
0N/A try {
0N/A gen = new RMIGenerator(env, cdef, destDir, remoteClass, version);
0N/A } catch (ClassNotFound e) {
0N/A env.error(0, "rmic.class.not.found", e.name);
0N/A return;
0N/A }
0N/A gen.generate();
0N/A }
0N/A
0N/A private void generate() {
0N/A env.addGeneratedFile(stubFile);
0N/A
0N/A try {
0N/A IndentingWriter out = new IndentingWriter(
0N/A new OutputStreamWriter(new FileOutputStream(stubFile)));
0N/A writeStub(out);
0N/A out.close();
0N/A if (env.verbose()) {
0N/A env.output(Main.getText("rmic.wrote", stubFile.getPath()));
0N/A }
0N/A env.parseFile(new ClassFile(stubFile));
0N/A } catch (IOException e) {
0N/A env.error(0, "cant.write", stubFile.toString());
0N/A return;
0N/A }
0N/A
0N/A if (version == STUB_VERSION_1_1 ||
0N/A version == STUB_VERSION_FAT)
0N/A {
0N/A env.addGeneratedFile(skeletonFile);
0N/A
0N/A try {
0N/A IndentingWriter out = new IndentingWriter(
0N/A new OutputStreamWriter(
0N/A new FileOutputStream(skeletonFile)));
0N/A writeSkeleton(out);
0N/A out.close();
0N/A if (env.verbose()) {
0N/A env.output(Main.getText("rmic.wrote",
0N/A skeletonFile.getPath()));
0N/A }
0N/A env.parseFile(new ClassFile(skeletonFile));
0N/A } catch (IOException e) {
0N/A env.error(0, "cant.write", stubFile.toString());
0N/A return;
0N/A }
0N/A } else {
0N/A /*
0N/A * For bugid 4135136: if skeleton files are not being generated
0N/A * for this compilation run, delete old skeleton source or class
0N/A * files for this remote implementation class that were
0N/A * (presumably) left over from previous runs, to avoid user
0N/A * confusion from extraneous or inconsistent generated files.
0N/A */
0N/A
0N/A File outputDir = Util.getOutputDirectoryFor(remoteClassName,destDir,env);
0N/A File skeletonClassFile = new File(outputDir,skeletonClassName.getName().toString() + ".class");
0N/A
0N/A skeletonFile.delete(); // ignore failures (no big deal)
0N/A skeletonClassFile.delete();
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Return the File object that should be used as the source file
0N/A * for the given Java class, using the supplied destination
0N/A * directory for the top of the package hierarchy.
0N/A */
0N/A protected static File sourceFileForClass(Identifier className,
0N/A Identifier outputClassName,
0N/A File destDir,
0N/A BatchEnvironment env)
0N/A {
0N/A File packageDir = Util.getOutputDirectoryFor(className,destDir,env);
0N/A String outputName = Names.mangleClass(outputClassName).getName().toString();
0N/A
0N/A // Is there any existing _Tie equivalent leftover from a
0N/A // previous invocation of rmic -iiop? Only do this once per
0N/A // class by looking for skeleton generation...
0N/A
0N/A if (outputName.endsWith("_Skel")) {
0N/A String classNameStr = className.getName().toString();
0N/A File temp = new File(packageDir, Utility.tieName(classNameStr) + ".class");
0N/A if (temp.exists()) {
0N/A
0N/A // Found a tie. Is IIOP generation also being done?
0N/A
0N/A if (!env.getMain().iiopGeneration) {
0N/A
0N/A // No, so write a warning...
0N/A
0N/A env.error(0,"warn.rmic.tie.found",
0N/A classNameStr,
0N/A temp.getAbsolutePath());
0N/A }
0N/A }
0N/A }
0N/A
0N/A String outputFileName = outputName + ".java";
0N/A return new File(packageDir, outputFileName);
0N/A }
0N/A
0N/A
0N/A /** rmic environment for this object */
0N/A private BatchEnvironment env;
0N/A
0N/A /** the remote class that this instance is generating code for */
0N/A private RemoteClass remoteClass;
0N/A
0N/A /** version of the stub protocol to use in code generation */
0N/A private int version;
0N/A
0N/A /** remote methods for remote class, indexed by operation number */
0N/A private RemoteClass.Method[] remoteMethods;
0N/A
0N/A /**
0N/A * Names for the remote class and the stub and skeleton classes
0N/A * to be generated for it.
0N/A */
0N/A private Identifier remoteClassName;
0N/A private Identifier stubClassName;
0N/A private Identifier skeletonClassName;
0N/A
0N/A private ClassDefinition cdef;
0N/A private File destDir;
0N/A private File stubFile;
0N/A private File skeletonFile;
0N/A
0N/A /**
0N/A * Names to use for the java.lang.reflect.Method static fields
0N/A * corresponding to each remote method.
0N/A */
0N/A private String[] methodFieldNames;
0N/A
0N/A /** cached definition for certain exception classes in this environment */
0N/A private ClassDefinition defException;
0N/A private ClassDefinition defRemoteException;
0N/A private ClassDefinition defRuntimeException;
0N/A
0N/A /**
0N/A * Create a new stub/skeleton Generator object for the given
0N/A * remote implementation class to generate code according to
0N/A * the given stub protocol version.
0N/A */
0N/A private RMIGenerator(BatchEnvironment env, ClassDefinition cdef,
0N/A File destDir, RemoteClass remoteClass, int version)
0N/A throws ClassNotFound
0N/A {
0N/A this.destDir = destDir;
0N/A this.cdef = cdef;
0N/A this.env = env;
0N/A this.remoteClass = remoteClass;
0N/A this.version = version;
0N/A
0N/A remoteMethods = remoteClass.getRemoteMethods();
0N/A
0N/A remoteClassName = remoteClass.getName();
0N/A stubClassName = Names.stubFor(remoteClassName);
0N/A skeletonClassName = Names.skeletonFor(remoteClassName);
0N/A
0N/A methodFieldNames = nameMethodFields(remoteMethods);
0N/A
0N/A stubFile = sourceFileForClass(remoteClassName,stubClassName, destDir , env);
0N/A skeletonFile = sourceFileForClass(remoteClassName,skeletonClassName, destDir, env);
0N/A
0N/A /*
0N/A * Initialize cached definitions for exception classes used
0N/A * in the generation process.
0N/A */
0N/A defException =
0N/A env.getClassDeclaration(idJavaLangException).
0N/A getClassDefinition(env);
0N/A defRemoteException =
0N/A env.getClassDeclaration(idRemoteException).
0N/A getClassDefinition(env);
0N/A defRuntimeException =
0N/A env.getClassDeclaration(idJavaLangRuntimeException).
0N/A getClassDefinition(env);
0N/A }
0N/A
0N/A /**
0N/A * Write the stub for the remote class to a stream.
0N/A */
0N/A private void writeStub(IndentingWriter p) throws IOException {
0N/A
0N/A /*
0N/A * Write boiler plate comment.
0N/A */
0N/A p.pln("// Stub class generated by rmic, do not edit.");
0N/A p.pln("// Contents subject to change without notice.");
0N/A p.pln();
0N/A
0N/A /*
0N/A * If remote implementation class was in a particular package,
0N/A * declare the stub class to be in the same package.
0N/A */
0N/A if (remoteClassName.isQualified()) {
0N/A p.pln("package " + remoteClassName.getQualifier() + ";");
0N/A p.pln();
0N/A }
0N/A
0N/A /*
0N/A * Declare the stub class; implement all remote interfaces.
0N/A */
0N/A p.plnI("public final class " +
0N/A Names.mangleClass(stubClassName.getName()));
0N/A p.pln("extends " + idRemoteStub);
0N/A ClassDefinition[] remoteInterfaces = remoteClass.getRemoteInterfaces();
0N/A if (remoteInterfaces.length > 0) {
0N/A p.p("implements ");
0N/A for (int i = 0; i < remoteInterfaces.length; i++) {
0N/A if (i > 0)
0N/A p.p(", ");
0N/A p.p(remoteInterfaces[i].getName().toString());
0N/A }
0N/A p.pln();
0N/A }
0N/A p.pOlnI("{");
0N/A
0N/A if (version == STUB_VERSION_1_1 ||
0N/A version == STUB_VERSION_FAT)
0N/A {
0N/A writeOperationsArray(p);
0N/A p.pln();
0N/A writeInterfaceHash(p);
0N/A p.pln();
0N/A }
0N/A
0N/A if (version == STUB_VERSION_FAT ||
0N/A version == STUB_VERSION_1_2)
0N/A {
0N/A p.pln("private static final long serialVersionUID = " +
0N/A STUB_SERIAL_VERSION_UID + ";");
0N/A p.pln();
0N/A
0N/A /*
0N/A * We only need to declare and initialize the static fields of
0N/A * Method objects for each remote method if there are any remote
0N/A * methods; otherwise, skip this code entirely, to avoid generating
0N/A * a try/catch block for a checked exception that cannot occur
0N/A * (see bugid 4125181).
0N/A */
0N/A if (methodFieldNames.length > 0) {
0N/A if (version == STUB_VERSION_FAT) {
0N/A p.pln("private static boolean useNewInvoke;");
0N/A }
0N/A writeMethodFieldDeclarations(p);
0N/A p.pln();
0N/A
0N/A /*
0N/A * Initialize java.lang.reflect.Method fields for each remote
0N/A * method in a static initializer.
0N/A */
0N/A p.plnI("static {");
0N/A p.plnI("try {");
0N/A if (version == STUB_VERSION_FAT) {
0N/A /*
0N/A * Fat stubs must determine whether the API required for
0N/A * the JDK 1.2 stub protocol is supported in the current
0N/A * runtime, so that it can use it if supported. This is
0N/A * determined by using the Reflection API to test if the
0N/A * new invoke method on RemoteRef exists, and setting the
0N/A * static boolean "useNewInvoke" to true if it does, or
0N/A * to false if a NoSuchMethodException is thrown.
0N/A */
0N/A p.plnI(idRemoteRef + ".class.getMethod(\"invoke\",");
0N/A p.plnI("new java.lang.Class[] {");
0N/A p.pln(idRemote + ".class,");
0N/A p.pln("java.lang.reflect.Method.class,");
0N/A p.pln("java.lang.Object[].class,");
0N/A p.pln("long.class");
0N/A p.pOln("});");
0N/A p.pO();
0N/A p.pln("useNewInvoke = true;");
0N/A }
0N/A writeMethodFieldInitializers(p);
0N/A p.pOlnI("} catch (java.lang.NoSuchMethodException e) {");
0N/A if (version == STUB_VERSION_FAT) {
0N/A p.pln("useNewInvoke = false;");
0N/A } else {
0N/A /*
0N/A * REMIND: By throwing an Error here, the application will
0N/A * get the NoSuchMethodError directly when the stub class
0N/A * is initialized. If we throw a RuntimeException
0N/A * instead, the application would get an
0N/A * ExceptionInInitializerError. Would that be more
0N/A * appropriate, and if so, which RuntimeException should
0N/A * be thrown?
0N/A */
0N/A p.plnI("throw new java.lang.NoSuchMethodError(");
0N/A p.pln("\"stub class initialization failed\");");
0N/A p.pO();
0N/A }
0N/A p.pOln("}"); // end try/catch block
0N/A p.pOln("}"); // end static initializer
0N/A p.pln();
0N/A }
0N/A }
0N/A
0N/A writeStubConstructors(p);
0N/A p.pln();
0N/A
0N/A /*
0N/A * Write each stub method.
0N/A */
0N/A if (remoteMethods.length > 0) {
0N/A p.pln("// methods from remote interfaces");
0N/A for (int i = 0; i < remoteMethods.length; ++i) {
0N/A p.pln();
0N/A writeStubMethod(p, i);
0N/A }
0N/A }
0N/A
0N/A p.pOln("}"); // end stub class
0N/A }
0N/A
0N/A /**
0N/A * Write the constructors for the stub class.
0N/A */
0N/A private void writeStubConstructors(IndentingWriter p)
0N/A throws IOException
0N/A {
0N/A p.pln("// constructors");
0N/A
0N/A /*
0N/A * Only stubs compatible with the JDK 1.1 stub protocol need
0N/A * a no-arg constructor; later versions use reflection to find
0N/A * the constructor that directly takes a RemoteRef argument.
0N/A */
0N/A if (version == STUB_VERSION_1_1 ||
0N/A version == STUB_VERSION_FAT)
0N/A {
0N/A p.plnI("public " + Names.mangleClass(stubClassName.getName()) +
0N/A "() {");
0N/A p.pln("super();");
0N/A p.pOln("}");
0N/A }
0N/A
0N/A p.plnI("public " + Names.mangleClass(stubClassName.getName()) +
0N/A "(" + idRemoteRef + " ref) {");
0N/A p.pln("super(ref);");
0N/A p.pOln("}");
0N/A }
0N/A
0N/A /**
0N/A * Write the stub method for the remote method with the given "opnum".
0N/A */
0N/A private void writeStubMethod(IndentingWriter p, int opnum)
0N/A throws IOException
0N/A {
0N/A RemoteClass.Method method = remoteMethods[opnum];
0N/A Identifier methodName = method.getName();
0N/A Type methodType = method.getType();
0N/A Type paramTypes[] = methodType.getArgumentTypes();
0N/A String paramNames[] = nameParameters(paramTypes);
0N/A Type returnType = methodType.getReturnType();
0N/A ClassDeclaration[] exceptions = method.getExceptions();
0N/A
0N/A /*
0N/A * Declare stub method; throw exceptions declared in remote
0N/A * interface(s).
0N/A */
0N/A p.pln("// implementation of " +
0N/A methodType.typeString(methodName.toString(), true, false));
0N/A p.p("public " + returnType + " " + methodName + "(");
0N/A for (int i = 0; i < paramTypes.length; i++) {
0N/A if (i > 0)
0N/A p.p(", ");
0N/A p.p(paramTypes[i] + " " + paramNames[i]);
0N/A }
0N/A p.plnI(")");
0N/A if (exceptions.length > 0) {
0N/A p.p("throws ");
0N/A for (int i = 0; i < exceptions.length; i++) {
0N/A if (i > 0)
0N/A p.p(", ");
0N/A p.p(exceptions[i].getName().toString());
0N/A }
0N/A p.pln();
0N/A }
0N/A p.pOlnI("{");
0N/A
0N/A /*
0N/A * The RemoteRef.invoke methods throw Exception, but unless this
0N/A * stub method throws Exception as well, we must catch Exceptions
0N/A * thrown from the invocation. So we must catch Exception and
0N/A * rethrow something we can throw: UnexpectedException, which is a
0N/A * subclass of RemoteException. But for any subclasses of Exception
0N/A * that we can throw, like RemoteException, RuntimeException, and
0N/A * any of the exceptions declared by this stub method, we want them
0N/A * to pass through unharmed, so first we must catch any such
0N/A * exceptions and rethrow it directly.
0N/A *
0N/A * We have to be careful generating the rethrowing catch blocks
0N/A * here, because javac will flag an error if there are any
0N/A * unreachable catch blocks, i.e. if the catch of an exception class
0N/A * follows a previous catch of it or of one of its superclasses.
0N/A * The following method invocation takes care of these details.
0N/A */
5561N/A Vector<ClassDefinition> catchList = computeUniqueCatchList(exceptions);
0N/A
0N/A /*
0N/A * If we need to catch any particular exceptions (i.e. this method
0N/A * does not declare java.lang.Exception), put the entire stub
0N/A * method in a try block.
0N/A */
0N/A if (catchList.size() > 0) {
0N/A p.plnI("try {");
0N/A }
0N/A
0N/A if (version == STUB_VERSION_FAT) {
0N/A p.plnI("if (useNewInvoke) {");
0N/A }
0N/A if (version == STUB_VERSION_FAT ||
0N/A version == STUB_VERSION_1_2)
0N/A {
0N/A if (!returnType.isType(TC_VOID)) {
0N/A p.p("Object $result = "); // REMIND: why $?
0N/A }
0N/A p.p("ref.invoke(this, " + methodFieldNames[opnum] + ", ");
0N/A if (paramTypes.length > 0) {
0N/A p.p("new java.lang.Object[] {");
0N/A for (int i = 0; i < paramTypes.length; i++) {
0N/A if (i > 0)
0N/A p.p(", ");
0N/A p.p(wrapArgumentCode(paramTypes[i], paramNames[i]));
0N/A }
0N/A p.p("}");
0N/A } else {
0N/A p.p("null");
0N/A }
0N/A p.pln(", " + method.getMethodHash() + "L);");
0N/A if (!returnType.isType(TC_VOID)) {
0N/A p.pln("return " +
0N/A unwrapArgumentCode(returnType, "$result") + ";");
0N/A }
0N/A }
0N/A if (version == STUB_VERSION_FAT) {
0N/A p.pOlnI("} else {");
0N/A }
0N/A if (version == STUB_VERSION_1_1 ||
0N/A version == STUB_VERSION_FAT)
0N/A {
0N/A p.pln(idRemoteCall + " call = ref.newCall((" + idRemoteObject +
0N/A ") this, operations, " + opnum + ", interfaceHash);");
0N/A
0N/A if (paramTypes.length > 0) {
0N/A p.plnI("try {");
0N/A p.pln("java.io.ObjectOutput out = call.getOutputStream();");
0N/A writeMarshalArguments(p, "out", paramTypes, paramNames);
0N/A p.pOlnI("} catch (java.io.IOException e) {");
0N/A p.pln("throw new " + idMarshalException +
0N/A "(\"error marshalling arguments\", e);");
0N/A p.pOln("}");
0N/A }
0N/A
0N/A p.pln("ref.invoke(call);");
0N/A
0N/A if (returnType.isType(TC_VOID)) {
0N/A p.pln("ref.done(call);");
0N/A } else {
0N/A p.pln(returnType + " $result;"); // REMIND: why $?
0N/A p.plnI("try {");
0N/A p.pln("java.io.ObjectInput in = call.getInputStream();");
0N/A boolean objectRead =
0N/A writeUnmarshalArgument(p, "in", returnType, "$result");
0N/A p.pln(";");
0N/A p.pOlnI("} catch (java.io.IOException e) {");
0N/A p.pln("throw new " + idUnmarshalException +
0N/A "(\"error unmarshalling return\", e);");
0N/A /*
0N/A * If any only if readObject has been invoked, we must catch
0N/A * ClassNotFoundException as well as IOException.
0N/A */
0N/A if (objectRead) {
0N/A p.pOlnI("} catch (java.lang.ClassNotFoundException e) {");
0N/A p.pln("throw new " + idUnmarshalException +
0N/A "(\"error unmarshalling return\", e);");
0N/A }
0N/A p.pOlnI("} finally {");
0N/A p.pln("ref.done(call);");
0N/A p.pOln("}");
0N/A p.pln("return $result;");
0N/A }
0N/A }
0N/A if (version == STUB_VERSION_FAT) {
0N/A p.pOln("}"); // end if/else (useNewInvoke) block
0N/A }
0N/A
0N/A /*
0N/A * If we need to catch any particular exceptions, finally write
0N/A * the catch blocks for them, rethrow any other Exceptions with an
0N/A * UnexpectedException, and end the try block.
0N/A */
0N/A if (catchList.size() > 0) {
5561N/A for (Enumeration<ClassDefinition> enumeration = catchList.elements();
0N/A enumeration.hasMoreElements();)
0N/A {
5561N/A ClassDefinition def = enumeration.nextElement();
0N/A p.pOlnI("} catch (" + def.getName() + " e) {");
0N/A p.pln("throw e;");
0N/A }
0N/A p.pOlnI("} catch (java.lang.Exception e) {");
0N/A p.pln("throw new " + idUnexpectedException +
0N/A "(\"undeclared checked exception\", e);");
0N/A p.pOln("}"); // end try/catch block
0N/A }
0N/A
0N/A p.pOln("}"); // end stub method
0N/A }
0N/A
0N/A /**
0N/A * Compute the exceptions which need to be caught and rethrown in a
0N/A * stub method before wrapping Exceptions in UnexpectedExceptions,
0N/A * given the exceptions declared in the throws clause of the method.
0N/A * Returns a Vector containing ClassDefinition objects for each
0N/A * exception to catch. Each exception is guaranteed to be unique,
0N/A * i.e. not a subclass of any of the other exceptions in the Vector,
0N/A * so the catch blocks for these exceptions may be generated in any
0N/A * order relative to each other.
0N/A *
0N/A * RemoteException and RuntimeException are each automatically placed
0N/A * in the returned Vector (if none of their superclasses are already
0N/A * present), since those exceptions should always be directly rethrown
0N/A * by a stub method.
0N/A *
0N/A * The returned Vector will be empty if java.lang.Exception or one
0N/A * of its superclasses is in the throws clause of the method, indicating
0N/A * that no exceptions need to be caught.
0N/A */
5561N/A private Vector<ClassDefinition> computeUniqueCatchList(ClassDeclaration[] exceptions) {
5561N/A Vector<ClassDefinition> uniqueList = new Vector<>(); // unique exceptions to catch
0N/A
0N/A uniqueList.addElement(defRuntimeException);
0N/A uniqueList.addElement(defRemoteException);
0N/A
0N/A /* For each exception declared by the stub method's throws clause: */
0N/A nextException:
0N/A for (int i = 0; i < exceptions.length; i++) {
0N/A ClassDeclaration decl = exceptions[i];
0N/A try {
0N/A if (defException.subClassOf(env, decl)) {
0N/A /*
0N/A * (If java.lang.Exception (or a superclass) was declared
0N/A * in the throws clause of this stub method, then we don't
0N/A * have to bother catching anything; clear the list and
0N/A * return.)
0N/A */
0N/A uniqueList.clear();
0N/A break;
0N/A } else if (!defException.superClassOf(env, decl)) {
0N/A /*
0N/A * Ignore other Throwables that do not extend Exception,
0N/A * since they do not need to be caught anyway.
0N/A */
0N/A continue;
0N/A }
0N/A /*
0N/A * Compare this exception against the current list of
0N/A * exceptions that need to be caught:
0N/A */
0N/A for (int j = 0; j < uniqueList.size();) {
5561N/A ClassDefinition def = uniqueList.elementAt(j);
0N/A if (def.superClassOf(env, decl)) {
0N/A /*
0N/A * If a superclass of this exception is already on
0N/A * the list to catch, then ignore and continue;
0N/A */
0N/A continue nextException;
0N/A } else if (def.subClassOf(env, decl)) {
0N/A /*
0N/A * If a subclass of this exception is on the list
0N/A * to catch, then remove it.
0N/A */
0N/A uniqueList.removeElementAt(j);
0N/A } else {
0N/A j++; // else continue comparing
0N/A }
0N/A }
0N/A /* This exception is unique: add it to the list to catch. */
0N/A uniqueList.addElement(decl.getClassDefinition(env));
0N/A } catch (ClassNotFound e) {
0N/A env.error(0, "class.not.found", e.name, decl.getName());
0N/A /*
0N/A * REMIND: We do not exit from this exceptional condition,
0N/A * generating questionable code and likely letting the
0N/A * compiler report a resulting error later.
0N/A */
0N/A }
0N/A }
0N/A return uniqueList;
0N/A }
0N/A
0N/A /**
0N/A * Write the skeleton for the remote class to a stream.
0N/A */
0N/A private void writeSkeleton(IndentingWriter p) throws IOException {
0N/A if (version == STUB_VERSION_1_2) {
0N/A throw new Error("should not generate skeleton for version");
0N/A }
0N/A
0N/A /*
0N/A * Write boiler plate comment.
0N/A */
0N/A p.pln("// Skeleton class generated by rmic, do not edit.");
0N/A p.pln("// Contents subject to change without notice.");
0N/A p.pln();
0N/A
0N/A /*
0N/A * If remote implementation class was in a particular package,
0N/A * declare the skeleton class to be in the same package.
0N/A */
0N/A if (remoteClassName.isQualified()) {
0N/A p.pln("package " + remoteClassName.getQualifier() + ";");
0N/A p.pln();
0N/A }
0N/A
0N/A /*
0N/A * Declare the skeleton class.
0N/A */
0N/A p.plnI("public final class " +
0N/A Names.mangleClass(skeletonClassName.getName()));
0N/A p.pln("implements " + idSkeleton);
0N/A p.pOlnI("{");
0N/A
0N/A writeOperationsArray(p);
0N/A p.pln();
0N/A
0N/A writeInterfaceHash(p);
0N/A p.pln();
0N/A
0N/A /*
0N/A * Define the getOperations() method.
0N/A */
0N/A p.plnI("public " + idOperation + "[] getOperations() {");
0N/A p.pln("return (" + idOperation + "[]) operations.clone();");
0N/A p.pOln("}");
0N/A p.pln();
0N/A
0N/A /*
0N/A * Define the dispatch() method.
0N/A */
0N/A p.plnI("public void dispatch(" + idRemote + " obj, " +
0N/A idRemoteCall + " call, int opnum, long hash)");
0N/A p.pln("throws java.lang.Exception");
0N/A p.pOlnI("{");
0N/A
0N/A if (version == STUB_VERSION_FAT) {
0N/A p.plnI("if (opnum < 0) {");
0N/A if (remoteMethods.length > 0) {
0N/A for (int opnum = 0; opnum < remoteMethods.length; opnum++) {
0N/A if (opnum > 0)
0N/A p.pO("} else ");
0N/A p.plnI("if (hash == " +
0N/A remoteMethods[opnum].getMethodHash() + "L) {");
0N/A p.pln("opnum = " + opnum + ";");
0N/A }
0N/A p.pOlnI("} else {");
0N/A }
0N/A /*
0N/A * Skeleton throws UnmarshalException if it does not recognize
0N/A * the method hash; this is what UnicastServerRef.dispatch()
0N/A * would do.
0N/A */
0N/A p.pln("throw new " +
0N/A idUnmarshalException + "(\"invalid method hash\");");
0N/A if (remoteMethods.length > 0) {
0N/A p.pOln("}");
0N/A }
0N/A /*
0N/A * Ignore the validation of the interface hash if the
0N/A * operation number was negative, since it is really a
0N/A * method hash instead.
0N/A */
0N/A p.pOlnI("} else {");
0N/A }
0N/A
0N/A p.plnI("if (hash != interfaceHash)");
0N/A p.pln("throw new " +
0N/A idSkeletonMismatchException + "(\"interface hash mismatch\");");
0N/A p.pO();
0N/A
0N/A if (version == STUB_VERSION_FAT) {
0N/A p.pOln("}"); // end if/else (opnum < 0) block
0N/A }
0N/A p.pln();
0N/A
0N/A /*
0N/A * Cast remote object instance to our specific implementation class.
0N/A */
0N/A p.pln(remoteClassName + " server = (" + remoteClassName + ") obj;");
0N/A
0N/A /*
0N/A * Process call according to the operation number.
0N/A */
0N/A p.plnI("switch (opnum) {");
0N/A for (int opnum = 0; opnum < remoteMethods.length; opnum++) {
0N/A writeSkeletonDispatchCase(p, opnum);
0N/A }
0N/A p.pOlnI("default:");
0N/A /*
0N/A * Skeleton throws UnmarshalException if it does not recognize
0N/A * the operation number; this is consistent with the case of an
0N/A * unrecognized method hash.
0N/A */
0N/A p.pln("throw new " + idUnmarshalException +
0N/A "(\"invalid method number\");");
0N/A p.pOln("}"); // end switch statement
0N/A
0N/A p.pOln("}"); // end dispatch() method
0N/A
0N/A p.pOln("}"); // end skeleton class
0N/A }
0N/A
0N/A /**
0N/A * Write the case block for the skeleton's dispatch method for
0N/A * the remote method with the given "opnum".
0N/A */
0N/A private void writeSkeletonDispatchCase(IndentingWriter p, int opnum)
0N/A throws IOException
0N/A {
0N/A RemoteClass.Method method = remoteMethods[opnum];
0N/A Identifier methodName = method.getName();
0N/A Type methodType = method.getType();
0N/A Type paramTypes[] = methodType.getArgumentTypes();
0N/A String paramNames[] = nameParameters(paramTypes);
0N/A Type returnType = methodType.getReturnType();
0N/A
0N/A p.pOlnI("case " + opnum + ": // " +
0N/A methodType.typeString(methodName.toString(), true, false));
0N/A /*
0N/A * Use nested block statement inside case to provide an independent
0N/A * namespace for local variables used to unmarshal parameters for
0N/A * this remote method.
0N/A */
0N/A p.pOlnI("{");
0N/A
0N/A if (paramTypes.length > 0) {
0N/A /*
0N/A * Declare local variables to hold arguments.
0N/A */
0N/A for (int i = 0; i < paramTypes.length; i++) {
0N/A p.pln(paramTypes[i] + " " + paramNames[i] + ";");
0N/A }
0N/A
0N/A /*
0N/A * Unmarshal arguments from call stream.
0N/A */
0N/A p.plnI("try {");
0N/A p.pln("java.io.ObjectInput in = call.getInputStream();");
0N/A boolean objectsRead = writeUnmarshalArguments(p, "in",
0N/A paramTypes, paramNames);
0N/A p.pOlnI("} catch (java.io.IOException e) {");
0N/A p.pln("throw new " + idUnmarshalException +
0N/A "(\"error unmarshalling arguments\", e);");
0N/A /*
0N/A * If any only if readObject has been invoked, we must catch
0N/A * ClassNotFoundException as well as IOException.
0N/A */
0N/A if (objectsRead) {
0N/A p.pOlnI("} catch (java.lang.ClassNotFoundException e) {");
0N/A p.pln("throw new " + idUnmarshalException +
0N/A "(\"error unmarshalling arguments\", e);");
0N/A }
0N/A p.pOlnI("} finally {");
0N/A p.pln("call.releaseInputStream();");
0N/A p.pOln("}");
0N/A } else {
0N/A p.pln("call.releaseInputStream();");
0N/A }
0N/A
0N/A if (!returnType.isType(TC_VOID)) {
0N/A /*
0N/A * Declare variable to hold return type, if not void.
0N/A */
0N/A p.p(returnType + " $result = "); // REMIND: why $?
0N/A }
0N/A
0N/A /*
0N/A * Invoke the method on the server object.
0N/A */
0N/A p.p("server." + methodName + "(");
0N/A for (int i = 0; i < paramNames.length; i++) {
0N/A if (i > 0)
0N/A p.p(", ");
0N/A p.p(paramNames[i]);
0N/A }
0N/A p.pln(");");
0N/A
0N/A /*
0N/A * Always invoke getResultStream(true) on the call object to send
0N/A * the indication of a successful invocation to the caller. If
0N/A * the return type is not void, keep the result stream and marshal
0N/A * the return value.
0N/A */
0N/A p.plnI("try {");
0N/A if (!returnType.isType(TC_VOID)) {
0N/A p.p("java.io.ObjectOutput out = ");
0N/A }
0N/A p.pln("call.getResultStream(true);");
0N/A if (!returnType.isType(TC_VOID)) {
0N/A writeMarshalArgument(p, "out", returnType, "$result");
0N/A p.pln(";");
0N/A }
0N/A p.pOlnI("} catch (java.io.IOException e) {");
0N/A p.pln("throw new " +
0N/A idMarshalException + "(\"error marshalling return\", e);");
0N/A p.pOln("}");
0N/A
0N/A p.pln("break;"); // break from switch statement
0N/A
0N/A p.pOlnI("}"); // end nested block statement
0N/A p.pln();
0N/A }
0N/A
0N/A /**
0N/A * Write declaration and initializer for "operations" static array.
0N/A */
0N/A private void writeOperationsArray(IndentingWriter p)
0N/A throws IOException
0N/A {
0N/A p.plnI("private static final " + idOperation + "[] operations = {");
0N/A for (int i = 0; i < remoteMethods.length; i++) {
0N/A if (i > 0)
0N/A p.pln(",");
0N/A p.p("new " + idOperation + "(\"" +
0N/A remoteMethods[i].getOperationString() + "\")");
0N/A }
0N/A p.pln();
0N/A p.pOln("};");
0N/A }
0N/A
0N/A /**
0N/A * Write declaration and initializer for "interfaceHash" static field.
0N/A */
0N/A private void writeInterfaceHash(IndentingWriter p)
0N/A throws IOException
0N/A {
0N/A p.pln("private static final long interfaceHash = " +
0N/A remoteClass.getInterfaceHash() + "L;");
0N/A }
0N/A
0N/A /**
0N/A * Write declaration for java.lang.reflect.Method static fields
0N/A * corresponding to each remote method in a stub.
0N/A */
0N/A private void writeMethodFieldDeclarations(IndentingWriter p)
0N/A throws IOException
0N/A {
0N/A for (int i = 0; i < methodFieldNames.length; i++) {
0N/A p.pln("private static java.lang.reflect.Method " +
0N/A methodFieldNames[i] + ";");
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Write code to initialize the static fields for each method
0N/A * using the Java Reflection API.
0N/A */
0N/A private void writeMethodFieldInitializers(IndentingWriter p)
0N/A throws IOException
0N/A {
0N/A for (int i = 0; i < methodFieldNames.length; i++) {
0N/A p.p(methodFieldNames[i] + " = ");
0N/A /*
0N/A * Here we look up the Method object in the arbitrary interface
0N/A * that we find in the RemoteClass.Method object.
0N/A * REMIND: Is this arbitrary choice OK?
0N/A * REMIND: Should this access be part of RemoteClass.Method's
0N/A * abstraction?
0N/A */
0N/A RemoteClass.Method method = remoteMethods[i];
0N/A MemberDefinition def = method.getMemberDefinition();
0N/A Identifier methodName = method.getName();
0N/A Type methodType = method.getType();
0N/A Type paramTypes[] = methodType.getArgumentTypes();
0N/A
0N/A p.p(def.getClassDefinition().getName() + ".class.getMethod(\"" +
0N/A methodName + "\", new java.lang.Class[] {");
0N/A for (int j = 0; j < paramTypes.length; j++) {
0N/A if (j > 0)
0N/A p.p(", ");
0N/A p.p(paramTypes[j] + ".class");
0N/A }
0N/A p.pln("});");
0N/A }
0N/A }
0N/A
0N/A
0N/A /*
0N/A * Following are a series of static utility methods useful during
0N/A * the code generation process:
0N/A */
0N/A
0N/A /**
0N/A * Generate an array of names for fields that correspond to the given
0N/A * array of remote methods. Each name in the returned array is
0N/A * guaranteed to be unique.
0N/A *
0N/A * The name of a method is included in its corresponding field name
0N/A * to enhance readability of the generated code.
0N/A */
0N/A private static String[] nameMethodFields(RemoteClass.Method[] methods) {
0N/A String[] names = new String[methods.length];
0N/A for (int i = 0; i < names.length; i++) {
0N/A names[i] = "$method_" + methods[i].getName() + "_" + i;
0N/A }
0N/A return names;
0N/A }
0N/A
0N/A /**
0N/A * Generate an array of names for parameters corresponding to the
0N/A * given array of types for the parameters. Each name in the returned
0N/A * array is guaranteed to be unique.
0N/A *
0N/A * A representation of the type of a parameter is included in its
0N/A * corresponding field name to enhance the readability of the generated
0N/A * code.
0N/A */
0N/A private static String[] nameParameters(Type[] types) {
0N/A String[] names = new String[types.length];
0N/A for (int i = 0; i < names.length; i++) {
0N/A names[i] = "$param_" +
0N/A generateNameFromType(types[i]) + "_" + (i + 1);
0N/A }
0N/A return names;
0N/A }
0N/A
0N/A /**
0N/A * Generate a readable string representing the given type suitable
0N/A * for embedding within a Java identifier.
0N/A */
0N/A private static String generateNameFromType(Type type) {
0N/A int typeCode = type.getTypeCode();
0N/A switch (typeCode) {
0N/A case TC_BOOLEAN:
0N/A case TC_BYTE:
0N/A case TC_CHAR:
0N/A case TC_SHORT:
0N/A case TC_INT:
0N/A case TC_LONG:
0N/A case TC_FLOAT:
0N/A case TC_DOUBLE:
0N/A return type.toString();
0N/A case TC_ARRAY:
0N/A return "arrayOf_" + generateNameFromType(type.getElementType());
0N/A case TC_CLASS:
0N/A return Names.mangleClass(type.getClassName().getName()).toString();
0N/A default:
0N/A throw new Error("unexpected type code: " + typeCode);
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Write a snippet of Java code to marshal a value named "name" of
0N/A * type "type" to the java.io.ObjectOutput stream named "stream".
0N/A *
0N/A * Primitive types are marshalled with their corresponding methods
0N/A * in the java.io.DataOutput interface, and objects (including arrays)
0N/A * are marshalled using the writeObject method.
0N/A */
0N/A private static void writeMarshalArgument(IndentingWriter p,
0N/A String streamName,
0N/A Type type, String name)
0N/A throws IOException
0N/A {
0N/A int typeCode = type.getTypeCode();
0N/A switch (typeCode) {
0N/A case TC_BOOLEAN:
0N/A p.p(streamName + ".writeBoolean(" + name + ")");
0N/A break;
0N/A case TC_BYTE:
0N/A p.p(streamName + ".writeByte(" + name + ")");
0N/A break;
0N/A case TC_CHAR:
0N/A p.p(streamName + ".writeChar(" + name + ")");
0N/A break;
0N/A case TC_SHORT:
0N/A p.p(streamName + ".writeShort(" + name + ")");
0N/A break;
0N/A case TC_INT:
0N/A p.p(streamName + ".writeInt(" + name + ")");
0N/A break;
0N/A case TC_LONG:
0N/A p.p(streamName + ".writeLong(" + name + ")");
0N/A break;
0N/A case TC_FLOAT:
0N/A p.p(streamName + ".writeFloat(" + name + ")");
0N/A break;
0N/A case TC_DOUBLE:
0N/A p.p(streamName + ".writeDouble(" + name + ")");
0N/A break;
0N/A case TC_ARRAY:
0N/A case TC_CLASS:
0N/A p.p(streamName + ".writeObject(" + name + ")");
0N/A break;
0N/A default:
0N/A throw new Error("unexpected type code: " + typeCode);
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Write Java statements to marshal a series of values in order as
0N/A * named in the "names" array, with types as specified in the "types"
0N/A * array", to the java.io.ObjectOutput stream named "stream".
0N/A */
0N/A private static void writeMarshalArguments(IndentingWriter p,
0N/A String streamName,
0N/A Type[] types, String[] names)
0N/A throws IOException
0N/A {
0N/A if (types.length != names.length) {
0N/A throw new Error("paramter type and name arrays different sizes");
0N/A }
0N/A
0N/A for (int i = 0; i < types.length; i++) {
0N/A writeMarshalArgument(p, streamName, types[i], names[i]);
0N/A p.pln(";");
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Write a snippet of Java code to unmarshal a value of type "type"
0N/A * from the java.io.ObjectInput stream named "stream" into a variable
0N/A * named "name" (if "name" is null, the value in unmarshalled and
0N/A * discarded).
0N/A *
0N/A * Primitive types are unmarshalled with their corresponding methods
0N/A * in the java.io.DataInput interface, and objects (including arrays)
0N/A * are unmarshalled using the readObject method.
0N/A */
0N/A private static boolean writeUnmarshalArgument(IndentingWriter p,
0N/A String streamName,
0N/A Type type, String name)
0N/A throws IOException
0N/A {
0N/A boolean readObject = false;
0N/A
0N/A if (name != null) {
0N/A p.p(name + " = ");
0N/A }
0N/A
0N/A int typeCode = type.getTypeCode();
0N/A switch (type.getTypeCode()) {
0N/A case TC_BOOLEAN:
0N/A p.p(streamName + ".readBoolean()");
0N/A break;
0N/A case TC_BYTE:
0N/A p.p(streamName + ".readByte()");
0N/A break;
0N/A case TC_CHAR:
0N/A p.p(streamName + ".readChar()");
0N/A break;
0N/A case TC_SHORT:
0N/A p.p(streamName + ".readShort()");
0N/A break;
0N/A case TC_INT:
0N/A p.p(streamName + ".readInt()");
0N/A break;
0N/A case TC_LONG:
0N/A p.p(streamName + ".readLong()");
0N/A break;
0N/A case TC_FLOAT:
0N/A p.p(streamName + ".readFloat()");
0N/A break;
0N/A case TC_DOUBLE:
0N/A p.p(streamName + ".readDouble()");
0N/A break;
0N/A case TC_ARRAY:
0N/A case TC_CLASS:
0N/A p.p("(" + type + ") " + streamName + ".readObject()");
0N/A readObject = true;
0N/A break;
0N/A default:
0N/A throw new Error("unexpected type code: " + typeCode);
0N/A }
0N/A return readObject;
0N/A }
0N/A
0N/A /**
0N/A * Write Java statements to unmarshal a series of values in order of
0N/A * types as in the "types" array from the java.io.ObjectInput stream
0N/A * named "stream" into variables as named in "names" (for any element
0N/A * of "names" that is null, the corresponding value is unmarshalled
0N/A * and discarded).
0N/A */
0N/A private static boolean writeUnmarshalArguments(IndentingWriter p,
0N/A String streamName,
0N/A Type[] types,
0N/A String[] names)
0N/A throws IOException
0N/A {
0N/A if (types.length != names.length) {
0N/A throw new Error("paramter type and name arrays different sizes");
0N/A }
0N/A
0N/A boolean readObject = false;
0N/A for (int i = 0; i < types.length; i++) {
0N/A if (writeUnmarshalArgument(p, streamName, types[i], names[i])) {
0N/A readObject = true;
0N/A }
0N/A p.pln(";");
0N/A }
0N/A return readObject;
0N/A }
0N/A
0N/A /**
0N/A * Return a snippet of Java code to wrap a value named "name" of
0N/A * type "type" into an object as appropriate for use by the
0N/A * Java Reflection API.
0N/A *
0N/A * For primitive types, an appropriate wrapper class instantiated
0N/A * with the primitive value. For object types (including arrays),
0N/A * no wrapping is necessary, so the value is named directly.
0N/A */
0N/A private static String wrapArgumentCode(Type type, String name) {
0N/A int typeCode = type.getTypeCode();
0N/A switch (typeCode) {
0N/A case TC_BOOLEAN:
0N/A return ("(" + name +
0N/A " ? java.lang.Boolean.TRUE : java.lang.Boolean.FALSE)");
0N/A case TC_BYTE:
0N/A return "new java.lang.Byte(" + name + ")";
0N/A case TC_CHAR:
0N/A return "new java.lang.Character(" + name + ")";
0N/A case TC_SHORT:
0N/A return "new java.lang.Short(" + name + ")";
0N/A case TC_INT:
0N/A return "new java.lang.Integer(" + name + ")";
0N/A case TC_LONG:
0N/A return "new java.lang.Long(" + name + ")";
0N/A case TC_FLOAT:
0N/A return "new java.lang.Float(" + name + ")";
0N/A case TC_DOUBLE:
0N/A return "new java.lang.Double(" + name + ")";
0N/A case TC_ARRAY:
0N/A case TC_CLASS:
0N/A return name;
0N/A default:
0N/A throw new Error("unexpected type code: " + typeCode);
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Return a snippet of Java code to unwrap a value named "name" into
0N/A * a value of type "type", as appropriate for the Java Reflection API.
0N/A *
0N/A * For primitive types, the value is assumed to be of the corresponding
0N/A * wrapper type, and a method is called on the wrapper type to retrieve
0N/A * the primitive value. For object types (include arrays), no
0N/A * unwrapping is necessary; the value is simply cast to the expected
0N/A * real object type.
0N/A */
0N/A private static String unwrapArgumentCode(Type type, String name) {
0N/A int typeCode = type.getTypeCode();
0N/A switch (typeCode) {
0N/A case TC_BOOLEAN:
0N/A return "((java.lang.Boolean) " + name + ").booleanValue()";
0N/A case TC_BYTE:
0N/A return "((java.lang.Byte) " + name + ").byteValue()";
0N/A case TC_CHAR:
0N/A return "((java.lang.Character) " + name + ").charValue()";
0N/A case TC_SHORT:
0N/A return "((java.lang.Short) " + name + ").shortValue()";
0N/A case TC_INT:
0N/A return "((java.lang.Integer) " + name + ").intValue()";
0N/A case TC_LONG:
0N/A return "((java.lang.Long) " + name + ").longValue()";
0N/A case TC_FLOAT:
0N/A return "((java.lang.Float) " + name + ").floatValue()";
0N/A case TC_DOUBLE:
0N/A return "((java.lang.Double) " + name + ").doubleValue()";
0N/A case TC_ARRAY:
0N/A case TC_CLASS:
0N/A return "((" + type + ") " + name + ")";
0N/A default:
0N/A throw new Error("unexpected type code: " + typeCode);
0N/A }
0N/A }
0N/A}