扩展JavaX509Certificate
以向其添加自定义函数的正确方法是什么?让我们以这个为例:
public abstract class MyX509Certificate extends java.security.cert.X509Certificate {
protected X509Certificate() {
super();
}
}
所以通常你只是从密钥库获取证书,然后像这样强制转换它:
X509Certificate cert = (X509Certificate) keystore.getCertificate(alias);
我试图像这样投射我的:
MyX509Certificate my = (MyX509Certificate) keystore.getCertificate(alias);
但我得到:
线程"main"中的异常 java.lang.ClassCastException: sun.security.x509.X509CertImpl 不能强制转换为 ca.carillon.crypto.cert.MyX509Certificate
为什么?
错误消息说:
java.lang.ClassCastException: sun.security.x509.X509CertImpl 不能强制转换为 ca.carillon.crypto.cert.MyX509Certificate
它基本上是说一种类型(sun.security.x509.X509CertImpl
)不能强制转换为另一种类型(您的MyX509Certificate
类)。
sun.security.x509.X509CertImpl
是java.security.cert.X509Certificate
的子类,它通过keystore.getCertificate
方法返回。
发生的情况是X509Certificate
是一个抽象类,keystore.getCertificate
将返回它的内部实现(子类)。这个子类可以不同,具体取决于您的环境(JVM、提供程序等)。在这种情况下,它返回一个sun.security.x509.X509CertImpl
- 你不会在任何地方看到这个类,因为它是 JVM 的内部,在大多数情况下,你实际上不需要知道它。你需要知道的是 这是一个X509Certificate
.
当你创建自己的X509Certificate
子类时,层次结构将是这样的:
X509Certificate <- super class
|
-------------------------------------
| |
sun.security.x509.X509CertImpl MyX509Certificate <- subclasses of X509Certificate
kesytore (X509CertImpl
) 返回的类和你的自定义类 (MyX509Certificate
) 都是X509Certificate
的子类。
当密钥库返回一个X509CertImpl
时,可以将其强制转换为X509Certificate
(可以将子类实例分配给具有超类类型的变量)。
但是,如果您尝试这样做:
MyX509Certificate my = (MyX509Certificate) keystore.getCertificate(alias);
密钥库返回一个X509CertImpl
,这是一个X509Certificate
,但它不是MyX509Certificate
- 你不能将一个"同级"类强制转换为另一个类。X509CertImpl
只知道它的超类(X509Certificate
),但它不知道MyX509Certificate
。
如果你想 向X509Certificate
添加功能,也许扩展它不是最好的解决方案,您应该采用"组合而不是继承"方法。
您可以创建一个具有X509Certificate
(又名"包装器")的类,并使用它添加功能:
public class MyCustomCertificate {
// wraps a X509Certificate
private X509Certificate cert;
public MyCustomCertificate(X509Certificate cert) {
this.cert = cert;
}
public void myCustomFunctionality1() {
// do something with this.cert
}
public void myCustomFunctionality2() {
// do something with this.cert
}
// and so on...
}
然后,使用密钥库返回的证书创建此类:
X509Certificate x509Cert = (X509Certificate) keystore.getCertificate(alias);
MyCustomCertificate myCert = new MyCustomCertificate(x509Cert);
X509Certificate
有很多未实现的方法,扩展它需要你实现它们(这不值得做,IMO)。相反,您可以使用密钥库返回的证书(已实现所有这些方法)并添加所需的功能。
但是,如果您确实要扩展X509Certificate
,则可以将方法委托给包装的证书:
public class MyCustomCertificate extends X509Certificate {
// wraps a X509Certificate
private X509Certificate cert;
public MyCustomCertificate(X509Certificate cert) {
this.cert = cert;
}
public void myCustomFunctionality1() {
// do something with this.cert
}
public void myCustomFunctionality2() {
// do something with this.cert
}
// delegate all X509Certificate methods to the wrapped certificate
public PublicKey getPublicKey() {
return this.cert.getPublicKey();
}
public Principal getSubjectDN() {
return this.cert.getSubjectDN();
}
// and so on...
}
正如另一个答案中提到的,你不应该尝试创建自己的类。您应该使用其他安全提供程序。
要回答您的实际问题,为什么您不能投到您的班级中,有一个原因。实例化的对象不是MyX509Certificate
,因此无法强制转换。仅当类是该类型时,才能将其强制转换为该类型。
例如:
public abstract class AbstractParentClass {
}
public class ChildClassA extends AbstractParentClass {
}
public class ChildClassB extends AbstractParentClass {
}
现在,您可以实例化ChildClassA
并将其分配给类型为AbstractParentClass
的变量,然后将其强制转换为ChildClassA
变量
public static void main(String[] args){
AbstractParentClass instance = new ChildClassA();
ChildClassA sameInstance = (ChildClassA) instance;
}
您不能做的是将其强制转换为不属于其类分类的类。
AbstractParentClass instance = new ChildClassA();
// This is runtime error because ChildClassB is not a ChildClassA
ChildClassB sameInstance = (ChildClassB) instance;
因此,除非您自己实例化该类(您不是,因为您是从密钥库中检索它),否则该类不属于MyX509Certificate
类型。