java.lang.ArrayStoreException Analysis
This demo shows you how to troubleshoot a Spring boot 1 application that might appear java.lang.ArrayStoreException when you upgrade to spring Boot 2 o'clock.
Demo Address: Https://github.com/hengyunabc/spring-boot-inside/tree/master/demo-ArrayStoreException
There are two modules in the demo, Springboot1-starter and Springboot2-demo.
In the Springboot1-starter module, it is a simple healthindicator implementation
public class Myhealthindicator extends Abstracthealthindicator {
@Override
protected void Dohealthcheck ( Builder Builder) throws Exception {
builder.status (status.up);
Builder.withdetail ("Hello", "World");
}
@Configuration
@AutoConfigureBefore (endpointautoconfiguration.class)
@AutoConfigureAfter ( Healthindicatorautoconfiguration.class)
@ConditionalOnClass (value = {Healthindicator.class}) public
class myhealthindicatorautoconfiguration {
@Bean
@ConditionalOnMissingBean (myhealthindicator.class)
@ Conditionalonenabledhealthindicator (' my ') public
myhealthindicator Myhealthindicator () {return
new Myhealthindicator ();
}
Springboot2-demo is a simple spring boot2 application that references the Springboot1-starter module.
To import the project into the IDE and execute the arraystoreexceptiondemoapplication in Springboot2-demo, the exception thrown is
Caused by: java.lang.ArrayStoreException: sun.reflect.annotation.TypeNotPresentExceptionProxy
at sun.reflect.annotation.AnnotationParser.parseClassArray(AnnotationParser.java:724) ~[na:1.8.0_112]
at sun.reflect.annotation.AnnotationParser.parseArray(AnnotationParser.java:531) ~[na:1.8.0_112]
at sun.reflect.annotation.AnnotationParser.parseMemberValue(AnnotationParser.java:355) ~[na:1.8.0_112]
at sun.reflect.annotation.AnnotationParser.parseAnnotation2(AnnotationParser.java:286) ~[na:1.8.0_112]
at sun.reflect.annotation.AnnotationParser.parseAnnotations2(AnnotationParser.java:120) ~[na:1.8.0_112]
at sun.reflect.annotation.AnnotationParser.parseAnnotations(AnnotationParser.java:72) ~[na:1.8.0_112]
at java.lang.Class.createAnnotationData(Class.java:3521) ~[na:1.8.0_112]
at java.lang.Class.annotationData(Class.java:3510) ~[na:1.8.0_112]
at java.lang.Class.createAnnotationData(Class.java:3526) ~[na:1.8.0_112]
at java.lang.Class.annotationData(Class.java:3510) ~[na:1.8.0_112]
at java.lang.Class.getAnnotation(Class.java:3415) ~[na:1.8.0_112]
at java.lang.reflect.AnnotatedElement.isAnnotationPresent(AnnotatedElement.java:258) ~[na:1.8.0_112]
at java.lang.Class.isAnnotationPresent(Class.java:3425) ~[na:1.8.0_112]
at org.springframework.core.annotation.AnnotatedElementUtils.hasAnnotation(AnnotatedElementUtils.java:575) ~[spring-core-5.0.4.RELEASE.jar:5.0.4.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping.isHandler(RequestMappingHandlerMapping.java:177) ~[spring-webmvc-5.0.4.RELEASE.jar:5.0.4.RELEASE]
at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.initHandlerMethods(AbstractHandlerMethodMapping.java:217) ~[spring-webmvc-5.0.4.RELEASE.jar:5.0.4.RELEASE]
at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.afterPropertiesSet(AbstractHandlerMethodMapping.java:188) ~[spring-webmvc-5.0.4.RELEASE.jar:5.0.4.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping.afterPropertiesSet(RequestMappingHandlerMapping.java:129) ~[spring-webmvc-5.0.4.RELEASE.jar:5.0.4.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1769) ~[spring-beans-5.0.4.RELEASE.jar:5.0.4.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1706) ~[spring-beans-5.0.4.RELEASE.jar:5.0.4.RELEASE]
... 16 common frames omitted
using the Java Exception breakpoint
Here's how to troubleshoot this problem.
In the IDE, create a new breakpoint, the type is Java Exception breakpoint (if you do not know how to add, you can search for the IDE's use of documents), the exception class is the above thrown out of the java.lang.ArrayStoreException.
When the breakpoint is valid, view the parameters of the Annotationutils.findannotation (Class<?>, Class<a>, set<annotation>) line:686 function.
You can see that Clazz is class com.example.springboot1starter.myhealthindicatorautoconfiguration$ $EnhancerBySpringCGLIB $$ 945c1f Annotationtype is interface org.springframework.boot.actuate.endpoint.annotation.Endpoint
Indicates an error occurred while trying to find @endpoint information from the myhealthindicatorautoconfiguration.
Myhealthindicatorautoconfiguration really did not @endpoint, but why throw java.lang.ArrayStoreException? try to reproduce the exception with a simple example
First try the direct new myhealthindicatorautoconfiguration:
public static void Main (string[] args) {
myhealthindicatorautoconfiguration cc = new Myhealthindicatorautoconfiguration ();
}
The exception was thought to be thrown, but the discovery was performed properly.
Looking closely at the exception stack, you can find the exception thrown at the at Java.lang.Class.getDeclaredAnnotation (class.java:3458), and then try the following code:
public static void Main (string[] args) {
MyHealthIndicatorAutoConfiguration.class.getDeclaredAnnotation ( Endpoint.class);
}
Discovery can reproduce an exception:
Exception in thread "main" Java.lang.ArrayStoreException:sun.reflect.annotation.TypeNotPresentExceptionProxy
At Sun.reflect.annotation.AnnotationParser.parseClassArray (annotationparser.java:724) at
Sun.reflect.annotation.AnnotationParser.parseArray (annotationparser.java:531) at
Sun.reflect.annotation.AnnotationParser.parseMemberValue (annotationparser.java:355) at
Sun.reflect.annotation.AnnotationParser.parseAnnotation2 (annotationparser.java:286) at
Sun.reflect.annotation.AnnotationParser.parseAnnotations2 (annotationparser.java:120) at
Sun.reflect.annotation.AnnotationParser.parseAnnotations (annotationparser.java:72) at
Java.lang.Class.createAnnotationData (class.java:3521) at
java.lang.Class.annotationData (class.java:3510) At
java.lang.Class.getDeclaredAnnotation (class.java:3458)
why would it be java.lang.ArrayStoreException?
Take a closer look at the exception information: Java.lang.ArrayStoreException:sun.reflect.annotation.TypeNotPresentExceptionProxy
Arraystoreexception is an array-crossed exception, it has only one string message, and there is no cause.
So we try to break the point in the Sun.reflect.annotation.TypeNotPresentExceptionProxy constructor.
public class Typenotpresentexceptionproxy extends Exceptionproxy {
private static final long Serialversionuid = 55659 25172427947573L;
String TypeName;
Throwable cause;
Public Typenotpresentexceptionproxy (String typeName, throwable cause) {
this.typename = typeName;
This.cause = cause;
}
In the breakpoint, we can find that: TypeName is org.springframework.boot.actuate.autoconfigure.EndpointAutoConfiguration cause is Java.lang.ClassNotFoundException:org.springframework.boot.actuate.autoconfigure.EndpointAutoConfiguration
Finally the truth came out, is not found org.springframework.boot.actuate.autoconfigure.EndpointAutoConfiguration this class.
So how did it become arraystoreexception?
Looking at the code carefully, you can find that annotationparser.parseclassvalue the exception packaging into object
//sun.reflect.annotation.annotationparser.parseclassvalue (ByteBuffer, ConstantPool, class<?>) private static Object Parseclassvalue (Bytebuffer buf, Consta Ntpool Constpool, class<?> container) {int classindex = Buf.getsh
ORT () & 0xFFFF;
try {try {String sig = Constpool.getutf8at (Classindex);
Return Parsesig (sig, Container);
\ catch (IllegalArgumentException ex) {//Support obsolete early jsr175 format class files
Return Constpool.getclassat (Classindex);
The catch (Noclassdeffounderror e) {return new Typenotpresentexceptionproxy ("[Unknown]", e); catch (Typenotpresentexception e) {return new Typenotpresentexceptionproxy (e.typename), E.getcaus
E ()); }
}
Then in Sun.reflect.annotation.AnnotationParser.parseClassArray (int, bytebuffer, Constantpool, class<?>) And try to set it directly into the array.
Sun.reflect.annotation.AnnotationParser.parseClassArray (int, bytebuffer, Constantpool, class<?>)
Result[i] = Parseclassvalue (buf, Constpool, container);
And here the array is out of bounds, arraystoreexception only the type information of the crossed object, which is the
Java.lang.ArrayStoreException:sun.reflect.annotation.TypeNotPresentExceptionProxy
solve the problem
The discovery is java.lang.ClassNotFoundException: Org.springframework.boot.actuate.autoconfigure.EndpointAutoConfiguration, then add the @conditionalonclass check on it:
@Configuration
@AutoConfigureBefore (endpointautoconfiguration.class)
@AutoConfigureAfter ( Healthindicatorautoconfiguration.class)
@ConditionalOnClass (value = {Healthindicator.class, Endpointautoconfiguration.class}) Public
class Myhealthindicatorautoconfiguration {
The spring Boot2, to be exact, changed some of the package of the classes:
The spring Boot 1 class name is: Org.springframework.boot.actuate.autoconfigure.EndpointAutoConfiguration
Spring Boot 2 class name is: Org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration
summary
When a class loads, it does not load the Class<?> referenced by its annotation field, which is loaded when class.getdeclaredannotation (class<a>) is invoked
In the example above, it is @autoconfigurebefore (Endpointautoconfiguration.class) Endpointautoconfiguration will not be loaded with myhealthindicatorautoconfiguration.
The code for parsing bytecode inside the JDK is unreasonable, and the classnotfoundexception is eaten abnormally. Troubleshooting needs to be thoroughly debugged