Make use of Beans.instantiate optional - JDK-8047773
diff --git a/activation/src/main/java/javax/activation/CommandInfo.java b/activation/src/main/java/javax/activation/CommandInfo.java index b3bd2bb..41fff46 100644 --- a/activation/src/main/java/javax/activation/CommandInfo.java +++ b/activation/src/main/java/javax/activation/CommandInfo.java
@@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright (c) 1997-2015 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997-2017 Oracle and/or its affiliates. All rights reserved. * * The contents of this file are subject to the terms of either the GNU * General Public License Version 2 only ("GPL") or the Common Development @@ -41,7 +41,10 @@ package javax.activation; import java.io.*; -import java.beans.Beans; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.security.AccessController; +import java.security.PrivilegedAction; /** * The CommandInfo class is used by CommandMap implementations to @@ -97,8 +100,14 @@ /** * Return the instantiated JavaBean component. * <p> - * Begin by instantiating the component with - * <code>Beans.instantiate()</code>. + * If the current runtime environment supports + * {@link java.beans.Beans#instantiate Beans.instantiate}, + * use it to instantiate the JavaBeans component. Otherwise, use + * {@link java.lang.Class#forName Class.forName}. + * <p> + * The component class needs to be public. + * On Java SE 9 and newer, if the component class is in a named module, + * it needs to be in an exported package. * <p> * If the bean implements the <code>javax.activation.CommandObject</code> * interface, call its <code>setCommandContext</code> method. @@ -129,7 +138,7 @@ Object new_bean = null; // try to instantiate the bean - new_bean = java.beans.Beans.instantiate(loader, className); + new_bean = Beans.instantiate(loader, className); // if we got one and it is a CommandObject if (new_bean != null) { @@ -148,4 +157,86 @@ return new_bean; } + + /** + * Helper class to invoke Beans.instantiate reflectively or the equivalent + * with core reflection when module java.desktop is not readable. + */ + private static final class Beans { + static final Method instantiateMethod; + + static { + Method m; + try { + Class<?> c = Class.forName("java.beans.Beans"); + m = c.getDeclaredMethod("instantiate", ClassLoader.class, String.class); + } catch (ClassNotFoundException e) { + m = null; + } catch (NoSuchMethodException e) { + m = null; + } + instantiateMethod = m; + } + + /** + * Equivalent to invoking java.beans.Beans.instantiate(loader, cn) + */ + static Object instantiate(ClassLoader loader, String cn) + throws IOException, ClassNotFoundException { + + Exception exception; + + if (instantiateMethod != null) { + + // invoke Beans.instantiate + try { + return instantiateMethod.invoke(null, loader, cn); + } catch (InvocationTargetException e) { + exception = e; + } catch (IllegalAccessException e) { + exception = e; + } + + } else { + + SecurityManager security = System.getSecurityManager(); + if (security != null) { + // if it's ok with the SecurityManager, it's ok with me. + String cname = cn.replace('/', '.'); + if (cname.startsWith("[")) { + int b = cname.lastIndexOf('[') + 2; + if (b > 1 && b < cname.length()) { + cname = cname.substring(b); + } + } + int i = cname.lastIndexOf('.'); + if (i != -1) { + security.checkPackageAccess(cname.substring(0, i)); + } + } + + // Beans.instantiate specified to use SCL when loader is null + if (loader == null) { + loader = (ClassLoader) + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + ClassLoader cl = null; + try { + cl = ClassLoader.getSystemClassLoader(); + } catch (SecurityException ex) { } + return cl; + } + }); + } + Class<?> beanClass = Class.forName(cn, true, loader); + try { + return beanClass.newInstance(); + } catch (Exception ex) { + throw new ClassNotFoundException(beanClass + ": " + ex, ex); + } + + } + return null; + } + } }