• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Javassist, a Java-bytecode translator toolkit.
3  * Copyright (C) 1999- Shigeru Chiba. All Rights Reserved.
4  *
5  * The contents of this file are subject to the Mozilla Public License Version
6  * 1.1 (the "License"); you may not use this file except in compliance with
7  * the License.  Alternatively, the contents of this file may be used under
8  * the terms of the GNU Lesser General Public License Version 2.1 or later,
9  * or the Apache License Version 2.0.
10  *
11  * Software distributed under the License is distributed on an "AS IS" basis,
12  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13  * for the specific language governing rights and limitations under the
14  * License.
15  */
16 
17 package javassist.util.proxy;
18 
19 import java.lang.invoke.MethodHandle;
20 import java.lang.reflect.InvocationTargetException;
21 import java.lang.reflect.Method;
22 import java.net.URL;
23 
24 import javassist.CannotCompileException;
25 import javassist.CtClass;
26 import javassist.bytecode.ClassFile;
27 
28 /**
29  * Helper class for invoking {@link ClassLoader#defineClass(String,byte[],int,int)}.
30  *
31  * @since 3.22
32  */
33 public class DefinePackageHelper
34 {
35     private static abstract class Helper {
definePackage(ClassLoader loader, String name, String specTitle, String specVersion, String specVendor, String implTitle, String implVersion, String implVendor, URL sealBase)36         abstract Package definePackage(ClassLoader loader, String name, String specTitle,
37                 String specVersion, String specVendor, String implTitle, String implVersion,
38                 String implVendor, URL sealBase)
39             throws IllegalArgumentException;
40     }
41 
42     private static class Java9 extends Helper {
43         // definePackage has been discontinued for JAVA 9
44         @Override
definePackage(ClassLoader loader, String name, String specTitle, String specVersion, String specVendor, String implTitle, String implVersion, String implVendor, URL sealBase)45         Package definePackage(ClassLoader loader, String name, String specTitle,
46                     String specVersion, String specVendor, String implTitle, String implVersion,
47                     String implVendor, URL sealBase)
48             throws IllegalArgumentException
49         {
50             throw new RuntimeException("define package has been disabled for jigsaw");
51         }
52     };
53 
54     private static class Java7 extends Helper {
55         private final SecurityActions stack = SecurityActions.stack;
56         private final MethodHandle definePackage = getDefinePackageMethodHandle();
57 
getDefinePackageMethodHandle()58         private MethodHandle getDefinePackageMethodHandle() {
59             if (stack.getCallerClass() != this.getClass())
60                 throw new IllegalAccessError("Access denied for caller.");
61             try {
62                 return SecurityActions.getMethodHandle(ClassLoader.class,
63                             "definePackage", new Class[] {
64                                 String.class, String.class, String.class, String.class,
65                                 String.class, String.class, String.class, URL.class
66                             });
67             } catch (NoSuchMethodException e) {
68                 throw new RuntimeException("cannot initialize", e);
69             }
70         }
71 
72         @Override
definePackage(ClassLoader loader, String name, String specTitle, String specVersion, String specVendor, String implTitle, String implVersion, String implVendor, URL sealBase)73         Package definePackage(ClassLoader loader, String name, String specTitle,
74                     String specVersion, String specVendor, String implTitle, String implVersion,
75                     String implVendor, URL sealBase)
76             throws IllegalArgumentException
77         {
78             if (stack.getCallerClass() != DefinePackageHelper.class)
79                 throw new IllegalAccessError("Access denied for caller.");
80             try {
81                 return (Package) definePackage.invokeWithArguments(loader, name, specTitle,
82                         specVersion, specVendor, implTitle, implVersion, implVendor, sealBase);
83             } catch (Throwable e) {
84                 if (e instanceof IllegalArgumentException) throw (IllegalArgumentException) e;
85                 if (e instanceof RuntimeException) throw (RuntimeException) e;
86             }
87             return null;
88         }
89     }
90 
91     private static class JavaOther extends Helper {
92         private final SecurityActions stack = SecurityActions.stack;
93         private final Method definePackage = getDefinePackageMethod();
94 
getDefinePackageMethod()95         private Method getDefinePackageMethod() {
96             if (stack.getCallerClass() != this.getClass())
97                 throw new IllegalAccessError("Access denied for caller.");
98             try {
99                 return SecurityActions.getDeclaredMethod(ClassLoader.class,
100                             "definePackage", new Class[] {
101                                 String.class, String.class, String.class, String.class,
102                                 String.class, String.class, String.class, URL.class
103                             });
104             } catch (NoSuchMethodException e) {
105                 throw new RuntimeException("cannot initialize", e);
106             }
107         }
108 
109         @Override
definePackage(ClassLoader loader, String name, String specTitle, String specVersion, String specVendor, String implTitle, String implVersion, String implVendor, URL sealBase)110         Package definePackage(ClassLoader loader, String name, String specTitle,
111                     String specVersion, String specVendor, String implTitle, String implVersion,
112                     String implVendor, URL sealBase)
113             throws IllegalArgumentException
114         {
115             if (stack.getCallerClass() != DefinePackageHelper.class)
116                 throw new IllegalAccessError("Access denied for caller.");
117             try {
118                 definePackage.setAccessible(true);
119                 return (Package) definePackage.invoke(loader, new Object[] {
120                         name, specTitle, specVersion, specVendor, implTitle,
121                         implVersion, implVendor, sealBase
122                     });
123             } catch (Throwable e) {
124                 if (e instanceof InvocationTargetException) {
125                     Throwable t = ((InvocationTargetException) e).getTargetException();
126                     if (t instanceof IllegalArgumentException)
127                         throw (IllegalArgumentException) t;
128                 }
129                 if (e instanceof RuntimeException) throw (RuntimeException) e;
130             }
131             finally {
132                 definePackage.setAccessible(false);
133             }
134             return null;
135         }
136     };
137 
138     private static final Helper privileged
139         = ClassFile.MAJOR_VERSION >= ClassFile.JAVA_9
140           ? new Java9() : ClassFile.MAJOR_VERSION >= ClassFile.JAVA_7
141                           ? new Java7() : new JavaOther();
142 
143     /**
144      * Defines a new package.  If the package is already defined, this method
145      * performs nothing.
146      *
147      * <p>You do not necessarily need to
148      * call this method.  If this method is called, then
149      * <code>getPackage()</code> on the <code>Class</code> object returned
150      * by <code>toClass()</code> will return a non-null object.</p>
151      *
152      * <p>The jigsaw module introduced by Java 9 has broken this method.
153      * In Java 9 or later, the VM argument
154      * <code>--add-opens java.base/java.lang=ALL-UNNAMED</code>
155      * has to be given to the JVM so that this method can run.
156      * </p>
157      *
158      * @param loader        the class loader passed to <code>toClass()</code> or
159      *                      the default one obtained by <code>getClassLoader()</code>.
160      * @param className     the package name.
161      * @see Class#getClassLoader()
162      * @see CtClass#toClass()
163      */
definePackage(String className, ClassLoader loader)164     public static void definePackage(String className, ClassLoader loader)
165         throws CannotCompileException
166     {
167         try {
168             privileged.definePackage(loader, className,
169                     null, null, null, null, null, null, null);
170         }
171         catch (IllegalArgumentException e) {
172             // if the package is already defined, an IllegalArgumentException
173             // is thrown.
174             return;
175         }
176         catch (Exception e) {
177             throw new CannotCompileException(e);
178         }
179     }
180 
DefinePackageHelper()181     private DefinePackageHelper() {}
182 }
183