Hello,

As found by Phil Race, the original substitution text for Class.newInstance (JDK-8159330) is not equivalent in all cases. This should be addressed. The current suggested replacement text is

"The call

 clazz.newInstance()

can be replaced by

 clazz.getConstructor().newInstance()"

The getConstructor call only returns *public* constructors while newInstance can call non-public constructors too, subject to the appropriate security checks.


Therefore, using "getDeclaredConstructor()" is a better replacement since it should be able to find and call non-public constructors when that is permissible. The patch for this is:

--- a/src/java.base/share/classes/java/lang/Class.java Wed Nov 02 16:24:43 2016 -0700 +++ b/src/java.base/share/classes/java/lang/Class.java Wed Nov 02 17:36:25 2016 -0700
@@ -485,7 +485,7 @@
      * can be replaced by
      *
      * <pre>{@code
-     * clazz.getConstructor().newInstance()
+     * clazz.getDeclaredConstructor().newInstance()
      * }</pre>
      *
      * The latter sequence of calls is inferred to be able to throw

I wrote a simple program to try calling constructors with different access levels private, protected, package (default), and public in different settings and in the cases I tested clazz.newInstance() and clazz.getConstructor().newInstance() agreed on both returning an object or both throwing an exception. This property also held when a security manager was enabled.

Doing a quick examination of the sources of java.lang.Class,

    public T newInstance()
        throws InstantiationException, IllegalAccessException
    {
        if (System.getSecurityManager() != null) {
checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), false);
        }

            // various things elided...
            try {
                Class<?>[] empty = {};
final Constructor<T> c = getConstructor0(empty, Member.DECLARED);
                // various more things elided...
            } catch (NoSuchMethodException e) {
                throw (InstantiationException)
                    new InstantiationException(getName()).initCause(e);
            }
        }
            // still more things elided
    }

compared to

public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
        throws NoSuchMethodException, SecurityException {
checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
        return getConstructor0(parameterTypes, Member.DECLARED);
    }

Both alternatives are wrappers around the lower-level getConstructor0 method.

Thanks to Phil for noticing the problem with the existing text.

Cheers,

-Joe

Reply via email to