diff options
author | nickl- <github@jigsoft.co.za> | 2017-10-27 07:59:12 +0200 |
---|---|---|
committer | nickl- <github@jigsoft.co.za> | 2017-11-12 23:49:21 +0200 |
commit | af399dbfa005ccde16247b88159cc269e243fb22 (patch) | |
tree | 36fd0a1a4944747b8bc22c1e3dd27b1fc3d30cc4 | |
parent | 45e201f2fbc0e75ee5c050f633e23ca5d418d52f (diff) | |
download | javassist-af399dbfa005ccde16247b88159cc269e243fb22.tar.gz javassist-af399dbfa005ccde16247b88159cc269e243fb22.zip |
Refactor definePackage as well.
Yes it is deprecated but seems the right thing to do
-rw-r--r-- | src/main/javassist/ClassPool.java | 69 | ||||
-rw-r--r-- | src/main/javassist/util/proxy/DefinePackageHelper.java | 179 |
2 files changed, 184 insertions, 64 deletions
diff --git a/src/main/javassist/ClassPool.java b/src/main/javassist/ClassPool.java index 89a0067e..73a4d857 100644 --- a/src/main/javassist/ClassPool.java +++ b/src/main/javassist/ClassPool.java @@ -21,19 +21,16 @@ import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.lang.reflect.Method; import java.net.URL; -import java.security.AccessController; -import java.security.PrivilegedActionException; -import java.security.PrivilegedExceptionAction; import java.security.ProtectionDomain; -import java.util.Hashtable; -import java.util.Iterator; import java.util.ArrayList; import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Iterator; import javassist.bytecode.ClassFile; import javassist.bytecode.Descriptor; +import javassist.util.proxy.DefinePackageHelper; /** * A container of <code>CtClass</code> objects. @@ -69,28 +66,8 @@ import javassist.bytecode.Descriptor; * @see javassist.CtClass * @see javassist.ClassPath */ +@SuppressWarnings({"unchecked", "rawtypes"}) public class ClassPool { - private static java.lang.reflect.Method definePackage = null; - - static { - if (ClassFile.MAJOR_VERSION < ClassFile.JAVA_9) - try { - AccessController.doPrivileged(new PrivilegedExceptionAction(){ - public Object run() throws Exception{ - Class cl = Class.forName("java.lang.ClassLoader"); - definePackage = cl.getDeclaredMethod("definePackage", - new Class[] { String.class, String.class, String.class, - String.class, String.class, String.class, - String.class, java.net.URL.class }); - return null; - } - }); - } - catch (PrivilegedActionException pae) { - throw new RuntimeException("cannot initialize ClassPool", - pae.getException()); - } - } /** * Determines the search order. @@ -1175,43 +1152,7 @@ public class ClassPool { public void makePackage(ClassLoader loader, String name) throws CannotCompileException { - if (definePackage == null) - throw new CannotCompileException("give the JVM --add-opens"); - - Object[] args = new Object[] { - name, null, null, null, null, null, null, null }; - Throwable t; - try { - makePackage2(definePackage, loader, args); - return; - } - catch (java.lang.reflect.InvocationTargetException e) { - t = e.getTargetException(); - if (t == null) - t = e; - else if (t instanceof IllegalArgumentException) { - // if the package is already defined, an IllegalArgumentException - // is thrown. - return; - } - } - catch (Exception e) { - t = e; - } - - throw new CannotCompileException(t); + DefinePackageHelper.definePackage(name, loader); } - private static synchronized Object makePackage2(Method method, - ClassLoader loader, Object[] args) - throws Exception - { - method.setAccessible(true); - try { - return method.invoke(loader, args); - } - finally { - method.setAccessible(false); - } - } } diff --git a/src/main/javassist/util/proxy/DefinePackageHelper.java b/src/main/javassist/util/proxy/DefinePackageHelper.java new file mode 100644 index 00000000..1fe0bd61 --- /dev/null +++ b/src/main/javassist/util/proxy/DefinePackageHelper.java @@ -0,0 +1,179 @@ +/* + * Javassist, a Java-bytecode translator toolkit. + * Copyright (C) 1999- 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, + * or the Apache License Version 2.0. + * + * 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.util.proxy; + +import java.lang.invoke.MethodHandle; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.net.URL; + +import javassist.CannotCompileException; +import javassist.CtClass; +import javassist.bytecode.ClassFile; + +/** + * Helper class for invoking {@link ClassLoader#defineClass(String,byte[],int,int)}. + * + * @since 3.22 + */ +public class DefinePackageHelper +{ + + private static enum SecuredPrivileged + { + JAVA_9 { + // definePackage has been discontinued for JAVA 9 + @Override + protected Package definePackage(ClassLoader loader, String name, String specTitle, + String specVersion, String specVendor, String implTitle, String implVersion, + String implVendor, URL sealBase) throws IllegalArgumentException + { + throw new RuntimeException("define package has been disabled for jigsaw"); + } + }, + JAVA_7 { + private final SecurityActions stack = SecurityActions.stack; + private final MethodHandle definePackage = getDefinePackageMethodHandle(); + private MethodHandle getDefinePackageMethodHandle() + { + if (stack.getCallerClass() != this.getClass()) + throw new IllegalAccessError("Access denied for caller."); + try { + return SecurityActions.getMethodHandle(ClassLoader.class, + "definePackage", new Class[] { + String.class, String.class, String.class, String.class, + String.class, String.class, String.class, URL.class + }); + } catch (NoSuchMethodException e) { + throw new RuntimeException("cannot initialize", e); + } + } + + @Override + protected Package definePackage(ClassLoader loader, String name, String specTitle, + String specVersion, String specVendor, String implTitle, String implVersion, + String implVendor, URL sealBase) throws IllegalArgumentException { + if (stack.getCallerClass() != DefinePackageHelper.class) + throw new IllegalAccessError("Access denied for caller."); + try { + return (Package) definePackage.invokeWithArguments(loader, name, specTitle, + specVersion, specVendor, implTitle, implVersion, implVendor, sealBase); + } catch (Throwable e) { + if (e instanceof IllegalArgumentException) throw (IllegalArgumentException) e; + if (e instanceof RuntimeException) throw (RuntimeException) e; + } + return null; + } + }, + JAVA_OTHER { + private final SecurityActions stack = SecurityActions.stack; + private final Method definePackage = getDefinePackageMethod(); + private Method getDefinePackageMethod() + { + if (stack.getCallerClass() != this.getClass()) + throw new IllegalAccessError("Access denied for caller."); + try { + return SecurityActions.getDeclaredMethod(ClassLoader.class, + "definePackage", new Class[] { + String.class, String.class, String.class, String.class, + String.class, String.class, String.class, URL.class + }); + } catch (NoSuchMethodException e) { + throw new RuntimeException("cannot initialize", e); + } + } + + @Override + protected Package definePackage(ClassLoader loader, String name, String specTitle, + String specVersion, String specVendor, String implTitle, String implVersion, + String implVendor, URL sealBase) throws IllegalArgumentException + { + if (stack.getCallerClass() != DefinePackageHelper.class) + throw new IllegalAccessError("Access denied for caller."); + try { + definePackage.setAccessible(true); + return (Package) definePackage.invoke(loader, new Object[] { + name, specTitle, specVersion, specVendor, implTitle, + implVersion, implVendor, sealBase + }); + } catch (Throwable e) { + if (e instanceof InvocationTargetException) { + Throwable t = ((InvocationTargetException) e).getTargetException(); + if (t instanceof IllegalArgumentException) + throw (IllegalArgumentException) t; + } + if (e instanceof RuntimeException) throw (RuntimeException) e; + } + finally { + definePackage.setAccessible(false); + } + return null; + } + }; + + protected abstract Package definePackage(ClassLoader loader, String name, String specTitle, + String specVersion, String specVendor, String implTitle, String implVersion, + String implVendor, URL sealBase) throws IllegalArgumentException; + } + + private static final SecuredPrivileged privileged = ClassFile.MAJOR_VERSION >= ClassFile.JAVA_9 + ? SecuredPrivileged.JAVA_9 + : ClassFile.MAJOR_VERSION >= ClassFile.JAVA_7 + ? SecuredPrivileged.JAVA_7 + : SecuredPrivileged.JAVA_OTHER; + + + /** + * Defines a new package. If the package is already defined, this method + * performs nothing. + * + * <p>You do not necessarily need to + * call this method. If this method is called, then + * <code>getPackage()</code> on the <code>Class</code> object returned + * by <code>toClass()</code> will return a non-null object.</p> + * + * <p>The jigsaw module introduced by Java 9 has broken this method. + * In Java 9 or later, the VM argument + * <code>--add-opens java.base/java.lang=ALL-UNNAMED</code> + * has to be given to the JVM so that this method can run. + * </p> + * + * @param loader the class loader passed to <code>toClass()</code> or + * the default one obtained by <code>getClassLoader()</code>. + * @param name the package name. + * @see #getClassLoader() + * @see #toClass(CtClass) + * @see CtClass#toClass() */ + public static void definePackage(String className, ClassLoader loader) + throws CannotCompileException + { + try { + privileged.definePackage(loader, className, + null, null, null, null, null, null, null); + } + catch (IllegalArgumentException e) { + // if the package is already defined, an IllegalArgumentException + // is thrown. + return; + } + catch (Exception e) { + throw new CannotCompileException(e); + } + } + + private DefinePackageHelper() {} +} |