java.lang.ArrayStoreException Analysis
This demo shows you how to troubleshoot a Spring boot 1 application that might appear when you upgrade to spring Boot 2 o'clock java.lang.ArrayStoreException
.
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's a simple HealthIndicator
implementation.
Public class extends abstracthealthindicator { @Override protectedvoidthrows Exception { builder.status (status.up); Builder.withdetail ("Hello", "World");} }
@Configuration @autoconfigurebefore (endpointautoconfiguration.class) @AutoConfigureAfter (healthindicatorautoconfiguration.class) @ConditionalOnClass (value= {Healthindicator.class }) Public classmyhealthindicatorautoconfiguration {@Bean @ConditionalOnMissingBean (myhealthindicator.class) @ConditionalOnEnabledHealthIndicator ("My") Publicmyhealthindicator Myhealthindicator () {return NewMyhealthindicator (); }}
springboot2-demo
is a simple spring boot2 application that references the springboot1-starter
module.
Import the project into the IDE, execute springboot2-demo
in ArrayStoreExceptionDemoApplication
, throw the exception 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:~[na:1.8). 0_112] at Sun.reflect.annotation.AnnotationParser.parseAnnotations (Annotationparser.java:~[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] ...Common frames omitted
Using Java Exception Breakpoint
Below 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 corresponding IDE's use of the document), the exception class is thrown above java.lang.ArrayStoreException
.
When the breakpoint is working, look at AnnotationUtils.findAnnotation(Class<?>, Class<A>, Set<Annotation>) line: 686
the parameters of the function.
can find
- Clazz is
class com.example.springboot1starter.MyHealthIndicatorAutoConfiguration$$EnhancerBySpringCGLIB$$945c1f
- Annotationtype is
interface org.springframework.boot.actuate.endpoint.annotation.Endpoint
The description is an MyHealthIndicatorAutoConfiguration
error when trying to find information from inside @Endpoint
.
MyHealthIndicatorAutoConfiguration
Not really @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) { new myhealthindicatorautoconfiguration ();}
I thought I was going to throw an exception, but I found it normal.
If you look at the exception stack carefully, you can see that the at java.lang.Class.getDeclaredAnnotation(Class.java:3458)
exception is thrown, then try the following code:
Public Static void Main (string[] args) { myhealthindicatorautoconfiguration. class. getdeclaredannotation (Endpoint. Class);}
Found to be able to reproduce the 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?
Look at the exception information again: Java.lang.ArrayStoreException:sun.reflect.annotation.TypeNotPresentExceptionProxy
ArrayStoreException
is an array of out-of-bounds exceptions, it has only one string message, and it does not cause
.
Then we try to sun.reflect.annotation.TypeNotPresentExceptionProxy
break the point in the constructor.
Public class extends exceptionproxy { privatestaticfinallong serialversionuid = 5565925172427947573L; String TypeName; Throwable cause; Public Typenotpresentexceptionproxy (String typeName, throwable cause) { this. TypeName= TypeName; this. Cause = cause; }
In the breakpoint, we can find:
- TypeName is
org.springframework.boot.actuate.autoconfigure.EndpointAutoConfiguration
- Cause is
java.lang.ClassNotFoundException: org.springframework.boot.actuate.autoconfigure.EndpointAutoConfiguration
Finally the truth, is not found org.springframework.boot.actuate.autoconfigure.EndpointAutoConfiguration
this class.
So how does it turn out ArrayStoreException
to be?
Take a closer look at the code, and you'll find that AnnotationParser.parseClassValue
wrapping the exceptionObject
//Sun.reflect.annotation.AnnotationParser.parseClassValue (Bytebuffer, Constantpool, class<?>) Private StaticObject Parseclassvalue (bytebuffer buf, Constantpool Constpool, Class<?>container) { intClassindex = Buf.getshort () & 0xFFFF; Try { Try{String sig=Constpool.getutf8at (Classindex); returnParsesig (sig, Container); } Catch(IllegalArgumentException ex) {//Support obsolete early jsr175 format class files returnConstpool.getclassat (Classindex); } } Catch(Noclassdeffounderror e) {return NewTypenotpresentexceptionproxy ("[Unknown]", E); } Catch(typenotpresentexception e) {return NewTypenotpresentexceptionproxy (E.typename (), E.getcause ()); } }
And then sun.reflect.annotation.AnnotationParser.parseClassArray(int, ByteBuffer, ConstantPool, Class<?>)
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 Object
type information, which is above
Java.lang.ArrayStoreException:sun.reflect.annotation.TypeNotPresentExceptionProxy
Solve the problem
Found Yes java.lang.ClassNotFoundException: org.springframework.boot.actuate.autoconfigure.EndpointAutoConfiguration
, then add @ConditionalOnClass
the check to be able to:
@Configuration @autoconfigurebefore (endpointautoconfiguration. class ) @AutoConfigureAfter (healthindicatorautoconfiguration. class = {healthindicator. Class, Endpointautoconfiguration. class })publicclass Myhealthindicatorautoconfiguration {
The spring boot2, to be precise, changed some classes of the package:
The spring Boot 1 class name is:
- Org.springframework.boot.actuate.autoconfigure.EndpointAutoConfiguration
The Spring Boot 2 class name is:
- Org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration
Summarize
Deep Spring Boot: How to troubleshoot Java.lang.ArrayStoreException