无值的toString损坏

时间:2019-06-04 07:38:02

标签: java spring optional

我具有基于证书的身份验证:

import java.security.cert.X509Certificate;
import java.util.Optional;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.inject.Inject;
import javax.inject.Named;
import javax.naming.InvalidNameException;
import javax.naming.ldap.LdapName;
import javax.naming.ldap.Rdn;

@Named
public class UsernameService {

    private static final String MISSING_NAME = null;

    private static final Logger LOG = Logger.getLogger(UsernameService.class.getCanonicalName());

    @Inject
    private final Optional<X509Certificate> cert = null;

    public String currentRequestUsername() {
        if (cert.isPresent()) {
            try {
                LOG.finest("Check Certificate: " + cert); // <- exception!
                for (Rdn rdn : new LdapName(cert.get().getSubjectDN().getName()).getRdns()) {
                    LOG.finest("Check RDN entry for Common name(cn): " + rdn);
                    if (rdn.getType().equals("CN")) {
                        LOG.finer("Found Username: " + rdn.getValue().toString());
                        return rdn.getValue().toString();
                    }
                }
            } catch (InvalidNameException e) {
                LOG.log(Level.CONFIG, "Parse DName impossible: " + cert.get().getSubjectDN().getName() + ".", e);
            } catch (NullPointerException e) {
                LOG.log(Level.FINE, e.getMessage(), e);
            }
        }
        return MISSING_NAME;
    }
}

如您在上面的代码中看到的,如果值“存在”,则将可选内容打印到记录器中。现在是什么意思?空值是有效值吗?答案在javadoc中:

  

如果此Optional中存在值,则返回该值,否则抛出NoSuchElementException。

好,因此重现值是“存在的”。 null是否可能返回值?我们了解更多:

  

返回:此Optional保留的非空值

因此,不,不会标识为空值。

App-Config执行请求范围的证书Bean:

@Bean
@Autowired
@Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
public X509Certificate getCertificate(HttpServletRequest r) {
    X509Certificate[] certs = (X509Certificate[]) r.getAttribute("javax.servlet.request.X509Certificate");
    if (certs == null || certs.length == 0) {
        return null;
    }
    return certs[0];
}

但是我在控制台中遇到了异常:

org.springframework.aop.AopInvocationException: AOP configuration seems to be invalid: tried calling method [public abstract java.lang.String java.security.cert.Certificate.toString()] on target [null]; nested exception is java.lang.IllegalArgumentException: object is not an instance of declaring class
        at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:351)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198)
        at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:752)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
        at org.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(DelegatingIntroductionInterceptor.java:136)
        at org.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(DelegatingIntroductionInterceptor.java:124)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
        at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688)
        at $java.security.cert.X509Certificate$$EnhancerBySpringCGLIB$$96797f0e.toString(<generated>)
        at java.util.Formatter$FormatSpecifier.printString(Formatter.java:2886)
        at java.util.Formatter$FormatSpecifier.print(Formatter.java:2763)
        at java.util.Formatter.format(Formatter.java:2520)
        at java.util.Formatter.format(Formatter.java:2455)
        at java.lang.String.format(String.java:2940)
        at java.util.Optional.toString(Optional.java:346)
        at java.lang.String.valueOf(String.java:2994)
        at java.lang.StringBuilder.append(StringBuilder.java:131)
        at XXX.UsernameService.currentRequestUsername(UsernameService.java:27)
...
Caused by: java.lang.IllegalArgumentException: object is not an instance of declaring class
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

有什么主意吗?

1 个答案:

答案 0 :(得分:1)

现在,我在IllegalArgumentException的构造函数中创建了一个断点。 然后我退回了2条痕迹并检查了CDI调用。

Debug point in IAE constructor

我看到一个NullBean的实例为org.springframework.beans.factory.support.NullBean

因此可选值似乎不是null,但是bean是空bean。

我的解决方案是简单地捕获NullBean不是证书的异常。

import java.security.cert.X509Certificate;
import java.util.Optional;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.inject.Inject;
import javax.inject.Named;
import javax.naming.InvalidNameException;
import javax.naming.ldap.LdapName;
import javax.naming.ldap.Rdn;

@Named
public class UsernameService {

    private static final String MISSING_NAME = null;

    private static final Logger LOG = Logger.getLogger(UsernameService.class.getCanonicalName());

    @Inject
    private final Optional<X509Certificate> cert = null;

    public String currentRequestUsername() {
        if (cert.isPresent()) {
            try {
                LOG.finest("Check Certificate: " + cert);
                for (Rdn rdn : new LdapName(cert.get().getSubjectDN().getName()).getRdns()) {
                    LOG.finest("Check RDN entry for Common name(cn): " + rdn);
                    if (rdn.getType().equals("CN")) {
                        LOG.finer("Found Username: " + rdn.getValue().toString());
                        return rdn.getValue().toString();
                    }
                }
            } catch (InvalidNameException e) {
                LOG.log(Level.CONFIG, "Parse DName impossible: " + cert.get().getSubjectDN().getName() + ".", e);
            } catch (NullPointerException e) {
                LOG.log(Level.FINE, e.getMessage(), e);
            } catch (RuntimeException e) {
                LOG.log(Level.FINE, e.getMessage(), e);
            }
        }
        return MISSING_NAME;
    }
}