Jim
Jim

Reputation: 19582

Downcasting of arrays in java

I am not sure how downcasting of arrays works.
Example this works:

String[] sArray = {"a", "b"};  
Object[] o = sArray;  
f((String[]) o);  

static void f(String[] s){  
  System.out.println("Ok");   
}  

But for the following:
new F(cert, (X509Certificate[]) ks.getCertificateChain("ALIAS"), key));
where F is

public F(X509Certificate certificate, X509Certificate[] certificateChain, PrivateKey privateKey) {      
}  

I get ClassCastException

java.lang.ClassCastException: [Ljava.security.cert.Certificate; incompatible with [Ljava.security.cert.X509Certificate;

Why?

Upvotes: 4

Views: 3408

Answers (2)

Tom Anderson
Tom Anderson

Reputation: 47243

Arrays in Java are objects, and as such, have a class. They aren't simply identityless containers. When you say:

String[] sArray = {"a", "b"};

You are creating an object of class String[], and putting two strings in it. There is an alternative way of writing it which makes that clearer:

String[] sArray = new String[] {"a", "b"};

You can cast references to arrays in much the same way as you can cast references to any other objects; you can always make a widening conversion (eg assigning an expression of type String[] to a variable of type Object[]), and you can make a narrowing conversion using an explicit cast (eg assigning an expression of type Object[] to a variable of type String[]). As with other objects, when you do an explicit case, the actual class of the object is checked at runtime, and if it doesn't fit the desired type, a ClassCastException is thrown. As with other objects, the actual class of the object does not change when you cast. Only the type of the variable does.

In your case, it looks like ks.getCertificateChain("ALIAS") returns a Certificate[]. It's possible that the elements in it are instances of X509Certificate, but the array itself is still a Certificate[]. When you try to cast it to X509Certificate[], that fails.

If you need a X509Certificate[], then what you will have to do is copy the contents of the array into a new array which is a X509Certificate[]. You can do that as tbk suggests, or you can call Arrays.copyOf, looking something like:

Certificate[] Certificates = ks.getCertificateChain("ALIAS");
X509Certificate[] x509Certificates = Arrays.copyOf(certificates, certificates.length, X509Certificate[].class);

Upvotes: 5

tbl
tbl

Reputation: 771

You can not cast down an array in java, but you can work around it by doing the following:

Certificate[] certs = ...;
X509Certificate[] x509certs = new X509Certificate[certs.length];
for(int i = 0; i < certs.length; i++) {
  x509certs[i] = (X509Certificate)certs[i];
}

Edit: An alternative to this is shown in this post. However, it involves System.arraycopy() which will likely perform the same when it comes to runtime.

Upvotes: 2

Related Questions