错误 [Ljava.lang.Object;将 X509Certificate 的数组列表转换为数组时,无法转换为 [Ljava.security.cert.X509Certificate
Error [Ljava.lang.Object; cannot be cast to [Ljava.security.cert.X509Certificate when converting an arraylist of X509Certificate to array
我对这个 ssl 和证书很陌生。我有一个 jks 文件,其中包含一些服务器信任的证书。我正在尝试从 jks 文件中读取所有证书并将其 return 到 getAcceptedIssuers() 方法。证书的类型为 X509Certificate。
我实现的方法正确读取 jks 文件并创建 X509Certificate 证书的数组列表。接下来,当我尝试将数组列表转换为数组时,我得到了这个异常
[Ljava.lang.Object; cannot be cast to [Ljava.security.cert.X509Certificate;
at com.sample.ssl.GetCertificates.loadCertificatesFromCompanJks(GetCertificates.java:125)
at com.sample.ssl.GetCertificates.getAcceptedIssuers(GetCertificates.java:44)
at sun.security.ssl.AbstractTrustManagerWrapper.checkAlgorithmConstraints(Unknown Source)
at sun.security.ssl.AbstractTrustManagerWrapper.checkAdditionalTrust(Unknown Source)
at sun.security.ssl.AbstractTrustManagerWrapper.checkServerTrusted(Unknown Source)
at sun.security.ssl.ClientHandshaker.serverCertificate(Unknown Source)
at sun.security.ssl.ClientHandshaker.processMessage(Unknown Source)
at sun.security.ssl.Handshaker.processLoop(Unknown Source)
at sun.security.ssl.Handshaker.process_record(Unknown Source)
at sun.security.ssl.SSLSocketImpl.readRecord(Unknown Source)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(Unknown Source)
at sun.security.ssl.SSLSocketImpl.startHandshake(Unknown Source)
at sun.security.ssl.SSLSocketImpl.getSession(Unknown Source)
at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:91)
at org.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java:397)
at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:148)
at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:149)
at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:121)
at org.apache.http.impl.client.DefaultRequestDirector.tryConnect(DefaultRequestDirector.java:573)
at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:425)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:820)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:754)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:732)
at com.sample.ssl.GetCertificates.postMessage(GetCertificates.java:82)
at com.sample.ssl.GetCertificates.main(GetCertificates.java:138)
我的代码如下
public class GetCertificates {
static private TrustManager[] trustmgr = new TrustManager[]{new X509TrustManager() {
private X509Certificate[] certs = null;
public void checkClientTrusted(X509Certificate[] certs, String authType) {
System.out.println("checkClientTrusted");
}
public void checkServerTrusted(X509Certificate[] certs, String authType) {
System.out.println("checkServerTrusted");
}
public X509Certificate[] getAcceptedIssuers() {
System.out.println("getAcceptedIssuers");
certs = loadCertificatesFromCompanJks("C:/Users/vinod/Desktop/keystore.jks", "mypassword");
// return new
// X509Certificate[]{};
return certs;
}
}};
public void postMessage() {
try {
// here I prepare Url to execute and make a call
} catch (Exception ex) {
ex.printStackTrace();
}
}
public static X509Certificate[] loadCertificatesFromCompanJks(String jksPath, String keyStorePassword) {
try {
X509Certificate X509Certificate[] = null;
Certificate[] certs = null;
ArrayList<X509Certificate> serverCerts = new ArrayList<X509Certificate>();
FileInputStream is = new FileInputStream(jksPath);
KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
String password = keyStorePassword;
keystore.load(is, password.toCharArray());
Enumeration e = keystore.aliases();
for (; e.hasMoreElements(); ) {
String alias = (String) e.nextElement();
Certificate cert = keystore.getCertificate(alias);
X509Certificate cert1 = (X509Certificate) cert;
serverCerts.add(cert1);
}
is.close();
System.out.println("Number of server certificates : " + serverCerts.size());
X509Certificate = (java.security.cert.X509Certificate[]) serverCerts.toArray();
return X509Certificate;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static void main(String[] args) {
new GetCertificates().postMessage();
}
}
改变
X509Certificate = (java.security.cert.X509Certificate[]) serverCerts.toArray();
至
X509Certificate = serverCerts.toArray(new java.security.cert.X509Certificate[0]);
因为 toArray return Object[] 无法转换为 X509Certificate[] 即使数组的每个元素都可以转换为 X509Certificate
你的错误在这里:
X509Certificate = (java.security.cert.X509Certificate[]) serverCerts.toArray();
toArray()
的重载将 return 一个 Object[]
和一个 Object[]
不能转换为不同的数组类型。
将该行更改为:
X509Certificate = serverCerts.toArray(new X509Certificate[serverCerts.size()]);
在这里,您正在分配正确类型和大小的数组,并将其传递给 toArray
以从列表中填充。
(你也可以这样写...
X509Certificate = serverCerts.toArray(new X509Certificate[0]);
...但这会导致不必要的分配。请阅读 toArray(...)
的 javadocs 以获得更好的理解。 (不可否认,额外分配的成本很小,您可以通过传递预分配/共享的零大小数组来避免它。))
当你这样做的时候,改变你的变量名以符合 Java 风格约定。在同一行代码中为类型和变量使用相同的标识符是非常令人困惑的!
你要转换的是数组的元素而不是数组本身,这就是转换失败的原因。当您从列表中执行 toArray 而不指定类型时,您会得到一个 Object 数组,尽管这些对象的类型为 X509Certificate,因此您可以单独向上转换它们中的每一个,但您不能转换数组本身。如果您尝试转换它,那么您将 运行 放入此异常中。您的列表需要转换为 X509Certificate 类型的元素数组。
作为 Java8 中的替代方法,您可以这样做:
X509Certificate[] x509Certificates = serverCerts.parallelStream().toArray(X509Certificate[]::new);
我还建议尽可能继续使用 CamelCase 表示法。您使用大写字母作为变量名的首字母。它也应该更具描述性,因为您返回的是一组证书,而不仅仅是一个。
这个:
X509Certificate
应该是这样的x509Certificates
我对这个 ssl 和证书很陌生。我有一个 jks 文件,其中包含一些服务器信任的证书。我正在尝试从 jks 文件中读取所有证书并将其 return 到 getAcceptedIssuers() 方法。证书的类型为 X509Certificate。 我实现的方法正确读取 jks 文件并创建 X509Certificate 证书的数组列表。接下来,当我尝试将数组列表转换为数组时,我得到了这个异常
[Ljava.lang.Object; cannot be cast to [Ljava.security.cert.X509Certificate;
at com.sample.ssl.GetCertificates.loadCertificatesFromCompanJks(GetCertificates.java:125)
at com.sample.ssl.GetCertificates.getAcceptedIssuers(GetCertificates.java:44)
at sun.security.ssl.AbstractTrustManagerWrapper.checkAlgorithmConstraints(Unknown Source)
at sun.security.ssl.AbstractTrustManagerWrapper.checkAdditionalTrust(Unknown Source)
at sun.security.ssl.AbstractTrustManagerWrapper.checkServerTrusted(Unknown Source)
at sun.security.ssl.ClientHandshaker.serverCertificate(Unknown Source)
at sun.security.ssl.ClientHandshaker.processMessage(Unknown Source)
at sun.security.ssl.Handshaker.processLoop(Unknown Source)
at sun.security.ssl.Handshaker.process_record(Unknown Source)
at sun.security.ssl.SSLSocketImpl.readRecord(Unknown Source)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(Unknown Source)
at sun.security.ssl.SSLSocketImpl.startHandshake(Unknown Source)
at sun.security.ssl.SSLSocketImpl.getSession(Unknown Source)
at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:91)
at org.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java:397)
at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:148)
at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:149)
at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:121)
at org.apache.http.impl.client.DefaultRequestDirector.tryConnect(DefaultRequestDirector.java:573)
at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:425)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:820)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:754)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:732)
at com.sample.ssl.GetCertificates.postMessage(GetCertificates.java:82)
at com.sample.ssl.GetCertificates.main(GetCertificates.java:138)
我的代码如下
public class GetCertificates {
static private TrustManager[] trustmgr = new TrustManager[]{new X509TrustManager() {
private X509Certificate[] certs = null;
public void checkClientTrusted(X509Certificate[] certs, String authType) {
System.out.println("checkClientTrusted");
}
public void checkServerTrusted(X509Certificate[] certs, String authType) {
System.out.println("checkServerTrusted");
}
public X509Certificate[] getAcceptedIssuers() {
System.out.println("getAcceptedIssuers");
certs = loadCertificatesFromCompanJks("C:/Users/vinod/Desktop/keystore.jks", "mypassword");
// return new
// X509Certificate[]{};
return certs;
}
}};
public void postMessage() {
try {
// here I prepare Url to execute and make a call
} catch (Exception ex) {
ex.printStackTrace();
}
}
public static X509Certificate[] loadCertificatesFromCompanJks(String jksPath, String keyStorePassword) {
try {
X509Certificate X509Certificate[] = null;
Certificate[] certs = null;
ArrayList<X509Certificate> serverCerts = new ArrayList<X509Certificate>();
FileInputStream is = new FileInputStream(jksPath);
KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
String password = keyStorePassword;
keystore.load(is, password.toCharArray());
Enumeration e = keystore.aliases();
for (; e.hasMoreElements(); ) {
String alias = (String) e.nextElement();
Certificate cert = keystore.getCertificate(alias);
X509Certificate cert1 = (X509Certificate) cert;
serverCerts.add(cert1);
}
is.close();
System.out.println("Number of server certificates : " + serverCerts.size());
X509Certificate = (java.security.cert.X509Certificate[]) serverCerts.toArray();
return X509Certificate;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static void main(String[] args) {
new GetCertificates().postMessage();
}
}
改变
X509Certificate = (java.security.cert.X509Certificate[]) serverCerts.toArray();
至
X509Certificate = serverCerts.toArray(new java.security.cert.X509Certificate[0]);
因为 toArray return Object[] 无法转换为 X509Certificate[] 即使数组的每个元素都可以转换为 X509Certificate
你的错误在这里:
X509Certificate = (java.security.cert.X509Certificate[]) serverCerts.toArray();
toArray()
的重载将 return 一个 Object[]
和一个 Object[]
不能转换为不同的数组类型。
将该行更改为:
X509Certificate = serverCerts.toArray(new X509Certificate[serverCerts.size()]);
在这里,您正在分配正确类型和大小的数组,并将其传递给 toArray
以从列表中填充。
(你也可以这样写...
X509Certificate = serverCerts.toArray(new X509Certificate[0]);
...但这会导致不必要的分配。请阅读 toArray(...)
的 javadocs 以获得更好的理解。 (不可否认,额外分配的成本很小,您可以通过传递预分配/共享的零大小数组来避免它。))
当你这样做的时候,改变你的变量名以符合 Java 风格约定。在同一行代码中为类型和变量使用相同的标识符是非常令人困惑的!
你要转换的是数组的元素而不是数组本身,这就是转换失败的原因。当您从列表中执行 toArray 而不指定类型时,您会得到一个 Object 数组,尽管这些对象的类型为 X509Certificate,因此您可以单独向上转换它们中的每一个,但您不能转换数组本身。如果您尝试转换它,那么您将 运行 放入此异常中。您的列表需要转换为 X509Certificate 类型的元素数组。
作为 Java8 中的替代方法,您可以这样做:
X509Certificate[] x509Certificates = serverCerts.parallelStream().toArray(X509Certificate[]::new);
我还建议尽可能继续使用 CamelCase 表示法。您使用大写字母作为变量名的首字母。它也应该更具描述性,因为您返回的是一组证书,而不仅仅是一个。
这个:
X509Certificate
应该是这样的x509Certificates