没有价值的 Optional 的 Broken toString
Broken toString of Optional without value
我有一个基于证书的身份验证:
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;
}
}
如您在上面的代码中所见,如果值为 "present",则将可选值打印到记录器。现在是什么意思?空值是有效值吗?答案在javadoc:
If a value is present in this Optional, returns the value,otherwise throws NoSuchElementException.
好的,返回值为 "present"。 null
是一个可能的返回值吗?我们阅读更多:
Returns: the non-null value held by this 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$797f0e.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)
有什么想法吗?
现在我在 IllegalArgumentException
的构造函数中创建了一个断点。
然后我后退 2 条跟踪并检查 CDI 调用。
我看到一个 NullBean
有一个 org.springframework.beans.factory.support.NullBean
的实例。
所以可选的似乎不是null
但是这个bean是一个null 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;
}
}
我有一个基于证书的身份验证:
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;
}
}
如您在上面的代码中所见,如果值为 "present",则将可选值打印到记录器。现在是什么意思?空值是有效值吗?答案在javadoc:
If a value is present in this Optional, returns the value,otherwise throws NoSuchElementException.
好的,返回值为 "present"。 null
是一个可能的返回值吗?我们阅读更多:
Returns: the non-null value held by this 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$797f0e.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)
有什么想法吗?
现在我在 IllegalArgumentException
的构造函数中创建了一个断点。
然后我后退 2 条跟踪并检查 CDI 调用。
我看到一个 NullBean
有一个 org.springframework.beans.factory.support.NullBean
的实例。
所以可选的似乎不是null
但是这个bean是一个null 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;
}
}