Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fix to Java newInstance() deprecated

Java code from https://github.com/forcedotcom/wsc contains some deprecated code to create new instances

Transport is an interface

public interface Transport {

}

......

        Transport t = (Transport) config.getTransport().newInstance();
        t.setConfig(config);
        return t 

methods that I have tried to fix by using

        Transport t = (Transport) config.getTransport().getDeclaredConstructor().newInstance();
        t.setConfig(config);
        return t

This creates a warning "Unchecked call to getDeclaredConstructor(Class..) as a member of raw type 'java.lang.Class' '

I am looking for a better way to fix this deprecated call.

This code was not written by me. It provides a Java SOAP connection to Salesforce.com. I have written my own code to use it with Java 8, however, I thought it would be useful to update the code to work with Java 9+

like image 343
Des Albert Avatar asked Sep 19 '25 21:09

Des Albert


2 Answers

Thanks for the excellent suggestions

I have applied the recommendations in the following way to make it a little easier to read

        Class<?> transClass = config.getTransport();
        Transport t = (Transport) transClass.getDeclaredConstructor().newInstance();
        t.setConfig(this);
like image 66
Des Albert Avatar answered Sep 23 '25 07:09

Des Albert


There are two further aspects that need to be considered when following the recommendation in the Javadoc by replacing:

clz.newInstance()

with:

clz.getDeclaredConstructor().newInstance()

Firstly, Class#getDeclaredConstructor may throw InvocationTargetException or NoSuchMethodException (both forms of ReflectiveOperationException), where as Class#newInstance throws InstantiationException for these conditions.

As these are not types of RuntimeException, they need to be explicitly handled, arguably by catching them and setting them as a cause for a (new) InstantiationException that can be thrown, to preserve the signature for the calling code.

Secondly, Class#getDeclaredConstructor can cause an additional "accessDeclaredMembers" security check to be made (as well as the checkPackageAccess() check that Class#newInstance also makes).

Therefore, additional steps (such as the use of AccessController#doPrivileged) may need to be taken to ensure the caller does not fail this additional check.

So, a method like this:

Object createInstance(Class clz) 
        throws InstantiationException, IllegalAccessException { 
    return clz.newInstance();
}

might, once correctly modified, look something more like this:

Object createInstance(Class<?> clz)
        throws InstantiationException, IllegalAccessException {
    try {
        return AccessController.doPrivileged(new PrivilegedExceptionAction() {
            public Object run() throws InstantiationException, IllegalAccessException {
                try {
                    return clz.getDeclaredConstructor().newInstance();
                } catch (InvocationTargetException|NoSuchMethodException e) {
                    throw (InstantiationException)((new InstantiationException()).initCause(e));
                }
            }
        });
    } catch (PrivilegedActionException pae) {
        Exception e = pae.getException();
        if (e instanceof InstantiationException) throw (InstantiationException)e;
        throw (IllegalAccessException)e;
    }
}
like image 22
ngmr Avatar answered Sep 23 '25 06:09

ngmr