/* * Copyright (c) 1997, 2008, 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; import java.util.Vector;import java.util.Hashtable;import java.util.Enumeration;import java.io.IOException;import java.io.ByteArrayOutputStream;import java.io.DataOutputStream;import java.security.MessageDigest;import java.security.DigestOutputStream;import java.security.NoSuchAlgorithmException;import sun.tools.java.Type;import sun.tools.java.ClassDefinition;import sun.tools.java.ClassDeclaration;import sun.tools.java.MemberDefinition;import sun.tools.java.Identifier;import sun.tools.java.ClassNotFound; /** * A RemoteClass object encapsulates RMI-specific information about * a remote implementation class, i.e. a class that implements * one or more remote interfaces. * * 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 */public class RemoteClass implements sun.rmi.rmic.RMIConstants { /** * Create a RemoteClass object representing the remote meta-information * of the given class. * * Returns true if successful. If the class is not a properly formed * remote implementation class or if some other error occurs, the * return value will be null, and errors will have been reported to * the supplied BatchEnvironment. */ public static RemoteClass forClass(BatchEnvironment env, ClassDefinition implClassDef) { RemoteClass rc = new RemoteClass(env, implClassDef); if (rc.initialize()) { return rc; } else { return null; } } /** * Return the ClassDefinition for this class. */ public ClassDefinition getClassDefinition() { return implClassDef; } /** * Return the name of the class represented by this object. */ public Identifier getName() { return implClassDef.getName(); } /** * Return an array of ClassDefinitions representing all of the remote * interfaces implemented by this class. * * A remote interface is any interface that extends Remote, * directly or indirectly. The remote interfaces of a class * are the interfaces directly listed in either the class's * "implements" clause, or the "implements" clause of any * of its superclasses, that are remote interfaces. * * The order of the array returned is arbitrary, and some elements * may be superfluous (i.e., superinterfaces of other interfaces * in the array). */ public ClassDefinition[] getRemoteInterfaces() { return remoteInterfaces.clone(); } /** * Return an array of RemoteClass.Method objects representing all of * the remote methods implemented by this class, i.e. all of the * methods in the class's remote interfaces. * * The methods in the array are ordered according to the comparision * of the strings consisting of their method name followed by their * type signature, so each method's index in the array corresponds * to its "operation number" in the JDK 1.1 version of the * stub/skeleton protocol. */ public Method[] getRemoteMethods() { return remoteMethods.clone(); } /** * Return the "interface hash" used to match a stub/skeleton pair for * this class in the JDK 1.1 version of the stub/skeleton protocol. */ public long getInterfaceHash() { return interfaceHash; } /** * Return string representation of this object, consisting of * the string "remote class " followed by the class name. */ public String toString() { return "remote class " + implClassDef.getName().toString(); } /** rmic environment for this object */ private BatchEnvironment env; /** the remote implementation class this object corresponds to */ private ClassDefinition implClassDef; /** remote interfaces implemented by this class */ private ClassDefinition[] remoteInterfaces; /** all the remote methods of this class */ private Method[] remoteMethods; /** stub/skeleton "interface hash" for this class */ private long interfaceHash; /** cached definition for certain classes used in this environment */ private ClassDefinition defRemote; private ClassDefinition defException; private ClassDefinition defRemoteException; /** * Create a RemoteClass instance for the given class. The resulting * object is not yet initialized. */ private RemoteClass(BatchEnvironment env, ClassDefinition implClassDef) { this.env = env; this.implClassDef = implClassDef; } /** * Validate that the remote implementation class is properly formed * and fill in the data structures required by the public interface. */ private boolean initialize() { /* * Verify that the "impl" is really a class, not an interface. */ if (implClassDef.isInterface()) { env.error(0, "rmic.cant.make.stubs.for.interface", implClassDef.getName()); return false; } /* * Initialize cached definitions for the Remote interface and * the RemoteException class. */ try { defRemote = env.getClassDeclaration(idRemote).getClassDefinition(env); defException = env.getClassDeclaration(idJavaLangException). getClassDefinition(env); defRemoteException = env.getClassDeclaration(idRemoteException). getClassDefinition(env); } catch (ClassNotFound e) { env.error(0, "rmic.class.not.found", e.name); return false; } /* * Here we find all of the remote interfaces of our remote * implementation class. For each class up the superclass * chain, add each directly-implemented interface that * somehow extends Remote to a list. */ Vector<ClassDefinition> remotesImplemented = // list of remote interfaces found new Vector<ClassDefinition>(); for (ClassDefinition classDef = implClassDef; classDef != null;) { try { ClassDeclaration[] interfaces = classDef.getInterfaces(); for (int i = 0; i < interfaces.length; i++) { ClassDefinition interfaceDef = interfaces[i].getClassDefinition(env); /* * Add interface to the list if it extends Remote and * it is not already there. */ if (!remotesImplemented.contains(interfaceDef) && defRemote.implementedBy(env, interfaces[i])) { remotesImplemented.addElement(interfaceDef); /***** <DEBUG> */ if (env.verbose()) { System.out.println("[found remote interface: " + interfaceDef.getName() + "]"); /***** </DEBUG> */ } } } /* * Verify that the candidate remote implementation class * implements at least one remote interface directly. */ if (classDef == implClassDef && remotesImplemented.isEmpty()) { if (defRemote.implementedBy(env, implClassDef.getClassDeclaration())) { /* * This error message is used if the class does * implement a remote interface through one of * its superclasses, but not directly. */ env.error(0, "rmic.must.implement.remote.directly", implClassDef.getName()); } else { /* * This error message is used if the class never * implements a remote interface. */ env.error(0, "rmic.must.implement.remote", implClassDef.getName()); } return false; } /* * Get definition for next superclass. */ classDef = (classDef.getSuperClass() != null ? classDef.getSuperClass().getClassDefinition(env) : null); } catch (ClassNotFound e) { env.error(0, "class.not.found", e.name, classDef.getName()); return false; } } /* * The "remotesImplemented" vector now contains all of the remote * interfaces directly implemented by the remote class or by any * of its superclasses. * * At this point, we could optimize the list by removing superfluous * entries, i.e. any interfaces that are implemented by some other * interface in the list anyway. * * This should be correct; would it be worthwhile? * * for (int i = 0; i < remotesImplemented.size();) { * ClassDefinition interfaceDef = * (ClassDefinition) remotesImplemented.elementAt(i); * boolean isOtherwiseImplemented = false; * for (int j = 0; j < remotesImplemented.size; j++) { * if (j != i && * interfaceDef.implementedBy(env, (ClassDefinition) * remotesImplemented.elementAt(j). * getClassDeclaration())) * { * isOtherwiseImplemented = true; * break; * } * } * if (isOtherwiseImplemented) { * remotesImplemented.removeElementAt(i); * } else { * ++i; * } * } */ /* * Now we collect the methods from all of the remote interfaces * into a hashtable. */ Hashtable<String, Method> methods = new Hashtable<String, Method>(); boolean errors = false; for (Enumeration<ClassDefinition> enumeration = remotesImplemented.elements(); enumeration.hasMoreElements();) { ClassDefinition interfaceDef = enumeration.nextElement(); if (!collectRemoteMethods(interfaceDef, methods)) errors = true; } if (errors) return false; /* * Convert vector of remote interfaces to an array * (order is not important for this array). */ remoteInterfaces = new ClassDefinition[remotesImplemented.size()]; remotesImplemented.copyInto(remoteInterfaces); /* * Sort table of remote methods into an array. The elements are * sorted in ascending order of the string of the method's name * and type signature, so that each elements index is equal to * its operation number of the JDK 1.1 version of the stub/skeleton * protocol. */ String[] orderedKeys = new String[methods.size()]; int count = 0; for (Enumeration<Method> enumeration = methods.elements(); enumeration.hasMoreElements();) { Method m = enumeration.nextElement(); String key = m.getNameAndDescriptor(); int i; for (i = count; i > 0; --i) { if (key.compareTo(orderedKeys[i - 1]) >= 0) { break; } orderedKeys[i] = orderedKeys[i - 1]; } orderedKeys[i] = key; ++count; } remoteMethods = new Method[methods.size()]; for (int i = 0; i < remoteMethods.length; i++) { remoteMethods[i] = methods.get(orderedKeys[i]); /***** <DEBUG> */ if (env.verbose()) { System.out.print("[found remote method <" + i + ">: " + remoteMethods[i].getOperationString()); ClassDeclaration[] exceptions = remoteMethods[i].getExceptions(); if (exceptions.length > 0) System.out.print(" throws "); for (int j = 0; j < exceptions.length; j++) { if (j > 0) System.out.print(", "); System.out.print(exceptions[j].getName()); } System.out.println("]"); } /***** </DEBUG> */ } /** * Finally, pre-compute the interface hash to be used by * stubs/skeletons for this remote class. */ interfaceHash = computeInterfaceHash(); return true; } /** * Collect and validate all methods from given interface and all of * its superinterfaces as remote methods. Remote methods are added * to the supplied hashtable. Returns true if successful, * or false if an error occurred. */ private boolean collectRemoteMethods(ClassDefinition interfaceDef, Hashtable<String, Method> table) { if (!interfaceDef.isInterface()) { throw new Error( "expected interface, not class: " + interfaceDef.getName()); } /* * rmic used to enforce that a remote interface could not extend * a non-remote interface, i.e. an interface that did not itself * extend from Remote. The current version of rmic does not have * this restriction, so the following code is now commented out. * * Verify that this interface extends Remote, since all interfaces * extended by a remote interface must implement Remote. * * try { * if (!defRemote.implementedBy(env, * interfaceDef.getClassDeclaration())) * { * env.error(0, "rmic.can.mix.remote.nonremote", * interfaceDef.getName()); * return false; * } * } catch (ClassNotFound e) { * env.error(0, "class.not.found", e.name, * interfaceDef.getName()); * return false; * } */ boolean errors = false; /* * Search interface's members for methods. */ nextMember: for (MemberDefinition member = interfaceDef.getFirstMember(); member != null; member = member.getNextMember()) { if (member.isMethod() && !member.isConstructor() && !member.isInitializer()) { /* * Verify that each method throws RemoteException. */ ClassDeclaration[] exceptions = member.getExceptions(env); boolean hasRemoteException = false; for (int i = 0; i < exceptions.length; i++) { /* * rmic used to enforce that a remote method had to * explicitly list RemoteException in its "throws" * clause; i.e., just throwing Exception was not * acceptable. The current version of rmic does not * have this restriction, so the following code is * now commented out. Instead, the method is * considered valid if RemoteException is a subclass * of any of the methods declared exceptions. * * if (exceptions[i].getName().equals( * idRemoteException)) * { * hasRemoteException = true; * break; * } */ try { if (defRemoteException.subClassOf( env, exceptions[i])) { hasRemoteException = true; break; } } catch (ClassNotFound e) { env.error(0, "class.not.found", e.name, interfaceDef.getName()); continue nextMember; } } /* * If this method did not throw RemoteException as required, * generate the error but continue, so that multiple such * errors can be reported. */ if (!hasRemoteException) { env.error(0, "rmic.must.throw.remoteexception", interfaceDef.getName(), member.toString()); errors = true; continue nextMember; } /* * Verify that the implementation of this method throws only * java.lang.Exception or its subclasses (fix bugid 4092486). * JRMP does not support remote methods throwing * java.lang.Throwable or other subclasses. */ try { MemberDefinition implMethod = implClassDef.findMethod( env, member.getName(), member.getType()); if (implMethod != null) { // should not be null exceptions = implMethod.getExceptions(env); for (int i = 0; i < exceptions.length; i++) { if (!defException.superClassOf( env, exceptions[i])) { env.error(0, "rmic.must.only.throw.exception", implMethod.toString(), exceptions[i].getName());Lines 1–500 of 876. Load more
/* * Copyright (c) 1997, 2008, 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; import java.util.Vector; import java.util.Hashtable; import java.util.Enumeration; import java.io.IOException; import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; import java.security.MessageDigest; import java.security.DigestOutputStream; import java.security.NoSuchAlgorithmException; import sun.tools.java.Type; import sun.tools.java.ClassDefinition; import sun.tools.java.ClassDeclaration; import sun.tools.java.MemberDefinition; import sun.tools.java.Identifier; import sun.tools.java.ClassNotFound; /** * A RemoteClass object encapsulates RMI-specific information about * a remote implementation class, i.e. a class that implements * one or more remote interfaces. * * 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 */ public class RemoteClass implements sun.rmi.rmic.RMIConstants { /** * Create a RemoteClass object representing the remote meta-information * of the given class. * * Returns true if successful. If the class is not a properly formed * remote implementation class or if some other error occurs, the * return value will be null, and errors will have been reported to * the supplied BatchEnvironment. */ public static RemoteClass forClass(BatchEnvironment env, ClassDefinition implClassDef) { RemoteClass rc = new RemoteClass(env, implClassDef); if (rc.initialize()) { return rc; } else { return null; } } /** * Return the ClassDefinition for this class. */ public ClassDefinition getClassDefinition() { return implClassDef; } /** * Return the name of the class represented by this object. */ public Identifier getName() { return implClassDef.getName(); } /** * Return an array of ClassDefinitions representing all of the remote * interfaces implemented by this class. * * A remote interface is any interface that extends Remote, * directly or indirectly. The remote interfaces of a class * are the interfaces directly listed in either the class's * "implements" clause, or the "implements" clause of any * of its superclasses, that are remote interfaces. * * The order of the array returned is arbitrary, and some elements * may be superfluous (i.e., superinterfaces of other interfaces * in the array). */ public ClassDefinition[] getRemoteInterfaces() { return remoteInterfaces.clone(); } /** * Return an array of RemoteClass.Method objects representing all of * the remote methods implemented by this class, i.e. all of the * methods in the class's remote interfaces. * * The methods in the array are ordered according to the comparision * of the strings consisting of their method name followed by their * type signature, so each method's index in the array corresponds * to its "operation number" in the JDK 1.1 version of the * stub/skeleton protocol. */ public Method[] getRemoteMethods() { return remoteMethods.clone(); } /** * Return the "interface hash" used to match a stub/skeleton pair for * this class in the JDK 1.1 version of the stub/skeleton protocol. */ public long getInterfaceHash() { return interfaceHash; } /** * Return string representation of this object, consisting of * the string "remote class " followed by the class name. */ public String toString() { return "remote class " + implClassDef.getName().toString(); } /** rmic environment for this object */ private BatchEnvironment env; /** the remote implementation class this object corresponds to */ private ClassDefinition implClassDef; /** remote interfaces implemented by this class */ private ClassDefinition[] remoteInterfaces; /** all the remote methods of this class */ private Method[] remoteMethods; /** stub/skeleton "interface hash" for this class */ private long interfaceHash; /** cached definition for certain classes used in this environment */ private ClassDefinition defRemote; private ClassDefinition defException; private ClassDefinition defRemoteException; /** * Create a RemoteClass instance for the given class. The resulting * object is not yet initialized. */ private RemoteClass(BatchEnvironment env, ClassDefinition implClassDef) { this.env = env; this.implClassDef = implClassDef; } /** * Validate that the remote implementation class is properly formed * and fill in the data structures required by the public interface. */ private boolean initialize() { /* * Verify that the "impl" is really a class, not an interface. */ if (implClassDef.isInterface()) { env.error(0, "rmic.cant.make.stubs.for.interface", implClassDef.getName()); return false; } /* * Initialize cached definitions for the Remote interface and * the RemoteException class. */ try { defRemote = env.getClassDeclaration(idRemote).getClassDefinition(env); defException = env.getClassDeclaration(idJavaLangException). getClassDefinition(env); defRemoteException = env.getClassDeclaration(idRemoteException). getClassDefinition(env); } catch (ClassNotFound e) { env.error(0, "rmic.class.not.found", e.name); return false; } /* * Here we find all of the remote interfaces of our remote * implementation class. For each class up the superclass * chain, add each directly-implemented interface that * somehow extends Remote to a list. */ Vector<ClassDefinition> remotesImplemented = // list of remote interfaces found new Vector<ClassDefinition>(); for (ClassDefinition classDef = implClassDef; classDef != null;) { try { ClassDeclaration[] interfaces = classDef.getInterfaces(); for (int i = 0; i < interfaces.length; i++) { ClassDefinition interfaceDef = interfaces[i].getClassDefinition(env); /* * Add interface to the list if it extends Remote and * it is not already there. */ if (!remotesImplemented.contains(interfaceDef) && defRemote.implementedBy(env, interfaces[i])) { remotesImplemented.addElement(interfaceDef); /***** <DEBUG> */ if (env.verbose()) { System.out.println("[found remote interface: " + interfaceDef.getName() + "]"); /***** </DEBUG> */ } } } /* * Verify that the candidate remote implementation class * implements at least one remote interface directly. */ if (classDef == implClassDef && remotesImplemented.isEmpty()) { if (defRemote.implementedBy(env, implClassDef.getClassDeclaration())) { /* * This error message is used if the class does * implement a remote interface through one of * its superclasses, but not directly. */ env.error(0, "rmic.must.implement.remote.directly", implClassDef.getName()); } else { /* * This error message is used if the class never * implements a remote interface. */ env.error(0, "rmic.must.implement.remote", implClassDef.getName()); } return false; } /* * Get definition for next superclass. */ classDef = (classDef.getSuperClass() != null ? classDef.getSuperClass().getClassDefinition(env) : null); } catch (ClassNotFound e) { env.error(0, "class.not.found", e.name, classDef.getName()); return false; } } /* * The "remotesImplemented" vector now contains all of the remote * interfaces directly implemented by the remote class or by any * of its superclasses. * * At this point, we could optimize the list by removing superfluous * entries, i.e. any interfaces that are implemented by some other * interface in the list anyway. * * This should be correct; would it be worthwhile? * * for (int i = 0; i < remotesImplemented.size();) { * ClassDefinition interfaceDef = * (ClassDefinition) remotesImplemented.elementAt(i); * boolean isOtherwiseImplemented = false; * for (int j = 0; j < remotesImplemented.size; j++) { * if (j != i && * interfaceDef.implementedBy(env, (ClassDefinition) * remotesImplemented.elementAt(j). * getClassDeclaration())) * { * isOtherwiseImplemented = true; * break; * } * } * if (isOtherwiseImplemented) { * remotesImplemented.removeElementAt(i); * } else { * ++i; * } * } */ /* * Now we collect the methods from all of the remote interfaces * into a hashtable. */ Hashtable<String, Method> methods = new Hashtable<String, Method>(); boolean errors = false; for (Enumeration<ClassDefinition> enumeration = remotesImplemented.elements(); enumeration.hasMoreElements();) { ClassDefinition interfaceDef = enumeration.nextElement(); if (!collectRemoteMethods(interfaceDef, methods)) errors = true; } if (errors) return false; /* * Convert vector of remote interfaces to an array * (order is not important for this array). */ remoteInterfaces = new ClassDefinition[remotesImplemented.size()]; remotesImplemented.copyInto(remoteInterfaces); /* * Sort table of remote methods into an array. The elements are * sorted in ascending order of the string of the method's name * and type signature, so that each elements index is equal to * its operation number of the JDK 1.1 version of the stub/skeleton * protocol. */ String[] orderedKeys = new String[methods.size()]; int count = 0; for (Enumeration<Method> enumeration = methods.elements(); enumeration.hasMoreElements();) { Method m = enumeration.nextElement(); String key = m.getNameAndDescriptor(); int i; for (i = count; i > 0; --i) { if (key.compareTo(orderedKeys[i - 1]) >= 0) { break; } orderedKeys[i] = orderedKeys[i - 1]; } orderedKeys[i] = key; ++count; } remoteMethods = new Method[methods.size()]; for (int i = 0; i < remoteMethods.length; i++) { remoteMethods[i] = methods.get(orderedKeys[i]); /***** <DEBUG> */ if (env.verbose()) { System.out.print("[found remote method <" + i + ">: " + remoteMethods[i].getOperationString()); ClassDeclaration[] exceptions = remoteMethods[i].getExceptions(); if (exceptions.length > 0) System.out.print(" throws "); for (int j = 0; j < exceptions.length; j++) { if (j > 0) System.out.print(", "); System.out.print(exceptions[j].getName()); } System.out.println("]"); } /***** </DEBUG> */ } /** * Finally, pre-compute the interface hash to be used by * stubs/skeletons for this remote class. */ interfaceHash = computeInterfaceHash(); return true; } /** * Collect and validate all methods from given interface and all of * its superinterfaces as remote methods. Remote methods are added * to the supplied hashtable. Returns true if successful, * or false if an error occurred. */ private boolean collectRemoteMethods(ClassDefinition interfaceDef, Hashtable<String, Method> table) { if (!interfaceDef.isInterface()) { throw new Error( "expected interface, not class: " + interfaceDef.getName()); } /* * rmic used to enforce that a remote interface could not extend * a non-remote interface, i.e. an interface that did not itself * extend from Remote. The current version of rmic does not have * this restriction, so the following code is now commented out. * * Verify that this interface extends Remote, since all interfaces * extended by a remote interface must implement Remote. * * try { * if (!defRemote.implementedBy(env, * interfaceDef.getClassDeclaration())) * { * env.error(0, "rmic.can.mix.remote.nonremote", * interfaceDef.getName()); * return false; * } * } catch (ClassNotFound e) { * env.error(0, "class.not.found", e.name, * interfaceDef.getName()); * return false; * } */ boolean errors = false; /* * Search interface's members for methods. */ nextMember: for (MemberDefinition member = interfaceDef.getFirstMember(); member != null; member = member.getNextMember()) { if (member.isMethod() && !member.isConstructor() && !member.isInitializer()) { /* * Verify that each method throws RemoteException. */ ClassDeclaration[] exceptions = member.getExceptions(env); boolean hasRemoteException = false; for (int i = 0; i < exceptions.length; i++) { /* * rmic used to enforce that a remote method had to * explicitly list RemoteException in its "throws" * clause; i.e., just throwing Exception was not * acceptable. The current version of rmic does not * have this restriction, so the following code is * now commented out. Instead, the method is * considered valid if RemoteException is a subclass * of any of the methods declared exceptions. * * if (exceptions[i].getName().equals( * idRemoteException)) * { * hasRemoteException = true; * break; * } */ try { if (defRemoteException.subClassOf( env, exceptions[i])) { hasRemoteException = true; break; } } catch (ClassNotFound e) { env.error(0, "class.not.found", e.name, interfaceDef.getName()); continue nextMember; } } /* * If this method did not throw RemoteException as required, * generate the error but continue, so that multiple such * errors can be reported. */ if (!hasRemoteException) { env.error(0, "rmic.must.throw.remoteexception", interfaceDef.getName(), member.toString()); errors = true; continue nextMember; } /* * Verify that the implementation of this method throws only * java.lang.Exception or its subclasses (fix bugid 4092486). * JRMP does not support remote methods throwing * java.lang.Throwable or other subclasses. */ try { MemberDefinition implMethod = implClassDef.findMethod( env, member.getName(), member.getType()); if (implMethod != null) { // should not be null exceptions = implMethod.getExceptions(env); for (int i = 0; i < exceptions.length; i++) { if (!defException.superClassOf( env, exceptions[i])) { env.error(0, "rmic.must.only.throw.exception", implMethod.toString(), exceptions[i].getName());