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