扩展java.security.cert.X509Certificate的正确方法是什么?



扩展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.X509CertImpljava.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类型。

相关内容

最新更新