https://github.com/forcedotcom/wsc中的Java代码包含一些不推荐使用的代码来创建新实例
运输是一个界面
public interface Transport {
}
......
Transport t = (Transport) config.getTransport().newInstance();
t.setConfig(config);
return t
我尝试使用修复的方法
Transport t = (Transport) config.getTransport().getDeclaredConstructor().newInstance();
t.setConfig(config);
return t
这将创建一个警告“未选中作为原始类型'java.lang.Class'的成员的getDeclaredConstructor(Class ..)调用''
我正在寻找一种更好的方法来解决此已弃用的呼叫。
此代码不是我编写的。它提供了与Salesforce.com的Java SOAP连接。我已经编写了自己的代码以在Java 8中使用它,但是,我认为更新代码以与Java 9+一起使用将很有用。
答案 0 :(得分:2)
在通过替换遵循 Javadoc 中的建议时,还需要考虑另外两个方面:
clz.newInstance()
与:
clz.getDeclaredConstructor().newInstance()
首先,Class#getDeclaredConstructor
可能会抛出 InvocationTargetException
或 NoSuchMethodException
(ReflectiveOperationException
的两种形式),而对于这些条件,Class#newInstance
会抛出 InstantiationException
.
由于这些不是 RuntimeException
的类型,因此需要明确处理它们,可以说是通过捕获它们并将它们设置为可以抛出的(新)InstantiationException
的原因,以保留调用代码的签名。
其次,Class#getDeclaredConstructor
会导致进行额外的 "accessDeclaredMembers"
安全检查(以及 checkPackageAccess()
也会进行的 Class#newInstance
检查)。
因此,可能需要采取额外的步骤(例如使用 AccessController#doPrivileged
)来确保调用者不会在此额外检查中失败。
所以,这样的方法:
Object createInstance(Class clz)
throws InstantiationException, IllegalAccessException {
return clz.newInstance();
}
可能,一旦正确修改,看起来更像这样:
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;
}
}
答案 1 :(得分:0)
如Class#newInstance()
弃用消息所述,正确的替代方法是使用:
其次:
没有“更好的方法”,因为您所拥有的已经是正确的解决方案。您遇到的问题与raw types有关。查看您提供的GitHub链接,我假设config
是ConnectorConfig
的实例。如果正确,那么不幸的是,getTransport()
返回Class
而不是Class<?>
或Class<? extends Transport>
。这是您正在使用的库的API的问题;您可能需要考虑提交一个尚不存在的问题。
未选中对getDeclaredConstructor
的调用,因为它返回Constructor<T>
(其中T
来自Class
的通用参数),但是您有原始的Class
。您有两种选择可以消除警告:
将Class
对象投射到Class<?>
。
Transport t = (Transport) ((Class<?>) config.getTransport()).getDeclaredConstructor().newInstance();
在尽可能小的范围内使用@SuppressWarnings("unchecked")
。
@SuppressWarnings("unchecked")
Transport t = (Transport) config.getTransport().newInstance();
使用Class#newInstance
不会导致此“未检查的呼叫”警告的原因是因为该方法返回了T
,当Class
原始时,它会简单地解析为Object
—非通用类型。
答案 2 :(得分:0)
感谢出色的建议
我以以下方式应用了建议,以使其更容易阅读
Class<?> transClass = config.getTransport();
Transport t = (Transport) transClass.getDeclaredConstructor().newInstance();
t.setConfig(this);