]> source.dussan.org Git - javassist.git/commitdiff
Now, the compiler accepts a method that calls
authorchiba <chiba@30ef5769-5b8d-40dd-aea6-55b5d6557bb3>
Sat, 8 May 2004 14:49:33 +0000 (14:49 +0000)
committerchiba <chiba@30ef5769-5b8d-40dd-aea6-55b5d6557bb3>
Sat, 8 May 2004 14:49:33 +0000 (14:49 +0000)
a private constructor declared in an enclosing class.

git-svn-id: http://anonsvn.jboss.org/repos/javassist/trunk@99 30ef5769-5b8d-40dd-aea6-55b5d6557bb3

src/main/javassist/CtClass.java
src/main/javassist/bytecode/MethodInfo.java
src/main/javassist/compiler/AccessorMaker.java
src/main/javassist/compiler/MemberCodeGen.java
src/main/javassist/runtime/Inner.java [new file with mode: 0644]

index 8641f9707e43b54b019998a0e1032716a61c5b54..68f6303126b6b257f39f3e8922cd1e96b301fec7 100644 (file)
@@ -35,7 +35,7 @@ public abstract class CtClass {
     /**
      * The version number of this release.
      */
-    public static final String version = "3.0 RC1";
+    public static final String version = "3.0 RC0";
 
     /**
      * Prints the version number and the copyright notice.
index ffe42438963a43cbc2ab5e6cbf11ade6a860b2ad..56ef8036cf6cd76cf26d6a0a8e49abaf519903a2 100644 (file)
@@ -57,6 +57,7 @@ public final class MethodInfo {
 
     /**
      * Constructs a <code>method_info</code> structure.
+     * The initial value of <code>access_flags</code> is zero.
      *
      * @param cp                a constant pool table
      * @param methodname        method name
index bfe59f510630ea57cdac2955b35fda036c751aa1..14f46194a9886ce0b46ebf4d46ead786d84685c2 100644 (file)
@@ -28,12 +28,59 @@ public class AccessorMaker {
     private int uniqueNumber;
     private HashMap accessors;
 
+    static final String lastParamType = "javassist.runtime.Inner";
+
     public AccessorMaker(CtClass c) {
         clazz = c;
         uniqueNumber = 1;
         accessors = new HashMap();
     }
 
+    public String getConstructor(CtClass c, String desc, MethodInfo orig)
+        throws CompileError
+    {
+        String key = "<init>:" + desc;
+        String consDesc = (String)accessors.get(key);
+        if (consDesc != null)
+            return consDesc;     // already exists.
+
+        consDesc = Descriptor.appendParameter(lastParamType, desc);
+        ClassFile cf = clazz.getClassFile();    // turn on the modified flag. 
+        try {
+            ConstPool cp = cf.getConstPool();
+            ClassPool pool = clazz.getClassPool();
+            MethodInfo minfo
+                = new MethodInfo(cp, MethodInfo.nameInit, consDesc);
+            minfo.setAccessFlags(0);
+            minfo.addAttribute(new SyntheticAttribute(cp));
+            ExceptionsAttribute ea = orig.getExceptionsAttribute();
+            if (ea != null)  
+                minfo.addAttribute(ea.copy(cp, null));
+
+            CtClass[] params = Descriptor.getParameterTypes(desc, pool);
+            Bytecode code = new Bytecode(cp);
+            code.addAload(0);
+            int regno = 1;
+            for (int i = 0; i < params.length; ++i)
+                regno += code.addLoad(regno, params[i]);
+            code.setMaxLocals(regno + 1);    // the last parameter is added.
+            code.addInvokespecial(clazz, MethodInfo.nameInit, desc);
+
+            code.addReturn(null);
+            minfo.setCodeAttribute(code.toCodeAttribute());
+            cf.addMethod(minfo);
+        }
+        catch (CannotCompileException e) {
+            throw new CompileError(e);
+        }
+        catch (NotFoundException e) {
+            throw new CompileError(e);
+        }
+
+        accessors.put(key, consDesc);
+        return consDesc;
+    }
+
     /**
      * Returns the name of the method for accessing a private method.
      *
index 0a58dc9711b3416081338fbeaffb111fe84fbff8..a70acf84efc370e5a29247f8c3384a9cdc92bee5 100644 (file)
@@ -331,6 +331,7 @@ public class MemberCodeGen extends CodeGen {
 
         int stack = bytecode.getStackDepth();
 
+        // generate code for evaluating arguments.
         atMethodArgs(args, types, dims, cnames);
 
         // used by invokeinterface
@@ -370,12 +371,16 @@ public class MemberCodeGen extends CodeGen {
             isSpecial = true;
             if (declClass != targetClass)
                 throw new CompileError("no such a constructor");
+
+            if (declClass != thisClass && AccessFlag.isPrivate(acc)) {
+                desc = getAccessibleConstructor(desc, declClass, minfo);
+                bytecode.addOpcode(Opcode.ACONST_NULL); // the last parameter
+            }
         }
         else if (AccessFlag.isPrivate(acc))
             if (declClass == thisClass)
                 isSpecial = true;
             else {
-                String orgName = mname;
                 isSpecial = false;
                 isStatic = true;
                 String origDesc = desc;
@@ -386,9 +391,6 @@ public class MemberCodeGen extends CodeGen {
                 acc = AccessFlag.setPackage(acc) | AccessFlag.STATIC;
                 mname = getAccessiblePrivate(mname, origDesc, desc,
                                              minfo, declClass);
-                if (mname == null)
-                    throw new CompileError("Method " + orgName
-                                           + " is private");
             }
 
         boolean popTarget = false;
@@ -435,14 +437,36 @@ public class MemberCodeGen extends CodeGen {
     {
         if (isEnclosing(declClass, thisClass)) {
             AccessorMaker maker = declClass.getAccessorMaker();
-            if (maker == null)
-                return null;
-            else
+            if (maker != null)
                 return maker.getMethodAccessor(methodName, desc, newDesc,
                                                minfo);
         }
-        else
-            return null;    // cannot access this private method.
+
+        throw new CompileError("Method " + methodName
+                               + " is private");
+    }
+
+    /*
+     * Finds (or adds if necessary) a hidden constructor if the given
+     * constructor is in an enclosing class.
+     *
+     * @param desc          the descriptor of the constructor.
+     * @param declClass     the class declaring the constructor.
+     * @param minfo         the method info of the constructor.
+     * @return the descriptor of the hidden constructor.
+     */
+    protected String getAccessibleConstructor(String desc, CtClass declClass,
+                                              MethodInfo minfo)
+        throws CompileError
+    {
+        if (isEnclosing(declClass, thisClass)) {
+            AccessorMaker maker = declClass.getAccessorMaker();
+            if (maker != null)
+                return maker.getConstructor(declClass, desc, minfo);
+        }
+        
+        throw new CompileError("the called constructor is private in "
+                               + declClass.getName());
     }
 
     private boolean isEnclosing(CtClass outer, CtClass inner) {
diff --git a/src/main/javassist/runtime/Inner.java b/src/main/javassist/runtime/Inner.java
new file mode 100644 (file)
index 0000000..2aadf19
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * Javassist, a Java-bytecode translator toolkit.
+ * Copyright (C) 1999-2004 Shigeru Chiba. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License.  Alternatively, the contents of this file may be used under
+ * the terms of the GNU Lesser General Public License Version 2.1 or later.
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ */
+
+package javassist.runtime;
+
+/**
+ * A support class for compiling a method declared in an inner class.
+ * This support class is required at runtime
+ * only if the method calls a private constructor in the enclosing class.
+ */
+public class Inner {
+}