Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in / Register
Toggle navigation
S
spring-boot
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
DEMO
spring-boot
Commits
ac4dcfbf
Commit
ac4dcfbf
authored
Jul 26, 2019
by
Stephane Nicoll
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Improve detection of NoSuchMethodError cause
Closes gh-17649
parent
9e8649cc
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
123 additions
and
18 deletions
+123
-18
NoSuchMethodFailureAnalyzer.java
...oot/diagnostics/analyzer/NoSuchMethodFailureAnalyzer.java
+78
-15
NoSuchMethodFailureAnalyzerTests.java
...iagnostics/analyzer/NoSuchMethodFailureAnalyzerTests.java
+45
-3
No files found.
spring-boot-project/spring-boot/src/main/java/org/springframework/boot/diagnostics/analyzer/NoSuchMethodFailureAnalyzer.java
View file @
ac4dcfbf
...
@@ -31,12 +31,26 @@ import org.springframework.util.ClassUtils;
...
@@ -31,12 +31,26 @@ import org.springframework.util.ClassUtils;
* NoSuchMethodErrors}.
* NoSuchMethodErrors}.
*
*
* @author Andy Wilkinson
* @author Andy Wilkinson
* @author Stephane Nicoll
*/
*/
class
NoSuchMethodFailureAnalyzer
extends
AbstractFailureAnalyzer
<
NoSuchMethodError
>
{
class
NoSuchMethodFailureAnalyzer
extends
AbstractFailureAnalyzer
<
NoSuchMethodError
>
{
@Override
@Override
protected
FailureAnalysis
analyze
(
Throwable
rootFailure
,
NoSuchMethodError
cause
)
{
protected
FailureAnalysis
analyze
(
Throwable
rootFailure
,
NoSuchMethodError
cause
)
{
String
className
=
extractClassName
(
cause
);
NoSuchMethodDescriptor
descriptor
=
getNoSuchMethodDescriptor
(
cause
.
getMessage
());
if
(
descriptor
==
null
)
{
return
null
;
}
String
description
=
getDescription
(
cause
,
descriptor
);
return
new
FailureAnalysis
(
description
,
"Correct the classpath of your application so that it contains a single, compatible version of "
+
descriptor
.
getClassName
(),
cause
);
}
protected
NoSuchMethodDescriptor
getNoSuchMethodDescriptor
(
String
cause
)
{
String
message
=
cleanMessage
(
cause
);
String
className
=
extractClassName
(
message
);
if
(
className
==
null
)
{
if
(
className
==
null
)
{
return
null
;
return
null
;
}
}
...
@@ -48,24 +62,36 @@ class NoSuchMethodFailureAnalyzer extends AbstractFailureAnalyzer<NoSuchMethodEr
...
@@ -48,24 +62,36 @@ class NoSuchMethodFailureAnalyzer extends AbstractFailureAnalyzer<NoSuchMethodEr
if
(
actual
==
null
)
{
if
(
actual
==
null
)
{
return
null
;
return
null
;
}
}
String
description
=
getDescription
(
cause
,
className
,
candidates
,
actual
);
return
new
NoSuchMethodDescriptor
(
message
,
className
,
candidates
,
actual
);
return
new
FailureAnalysis
(
description
,
"Correct the classpath of your application so that it contains a single,"
+
" compatible version of "
+
className
,
cause
);
}
}
private
String
extractClassName
(
NoSuchMethodError
cause
)
{
private
String
cleanMessage
(
String
message
)
{
int
descriptorIndex
=
cause
.
getMessage
().
indexOf
(
'('
);
int
loadedFromIndex
=
message
.
indexOf
(
" (loaded from"
);
if
(
loadedFromIndex
==
-
1
)
{
return
message
;
}
return
message
.
substring
(
0
,
loadedFromIndex
);
}
private
String
extractClassName
(
String
message
)
{
if
(
message
.
startsWith
(
"'"
)
&&
message
.
endsWith
(
"'"
))
{
int
splitIndex
=
message
.
indexOf
(
' '
);
if
(
splitIndex
==
-
1
)
{
return
null
;
}
message
=
message
.
substring
(
splitIndex
+
1
);
}
int
descriptorIndex
=
message
.
indexOf
(
'('
);
if
(
descriptorIndex
==
-
1
)
{
if
(
descriptorIndex
==
-
1
)
{
return
null
;
return
null
;
}
}
String
classAndMethodName
=
cause
.
getMessage
()
.
substring
(
0
,
descriptorIndex
);
String
classAndMethodName
=
message
.
substring
(
0
,
descriptorIndex
);
int
methodNameIndex
=
classAndMethodName
.
lastIndexOf
(
'.'
);
int
methodNameIndex
=
classAndMethodName
.
lastIndexOf
(
'.'
);
if
(
methodNameIndex
==
-
1
)
{
if
(
methodNameIndex
==
-
1
)
{
return
null
;
return
null
;
}
}
return
classAndMethodName
.
substring
(
0
,
methodNameIndex
);
String
className
=
classAndMethodName
.
substring
(
0
,
methodNameIndex
);
return
className
.
replace
(
'/'
,
'.'
);
}
}
private
List
<
URL
>
findCandidates
(
String
className
)
{
private
List
<
URL
>
findCandidates
(
String
className
)
{
...
@@ -87,7 +113,7 @@ class NoSuchMethodFailureAnalyzer extends AbstractFailureAnalyzer<NoSuchMethodEr
...
@@ -87,7 +113,7 @@ class NoSuchMethodFailureAnalyzer extends AbstractFailureAnalyzer<NoSuchMethodEr
}
}
}
}
private
String
getDescription
(
NoSuchMethodError
cause
,
String
className
,
List
<
URL
>
candidates
,
URL
actual
)
{
private
String
getDescription
(
NoSuchMethodError
cause
,
NoSuchMethodDescriptor
descriptor
)
{
StringWriter
description
=
new
StringWriter
();
StringWriter
description
=
new
StringWriter
();
PrintWriter
writer
=
new
PrintWriter
(
description
);
PrintWriter
writer
=
new
PrintWriter
(
description
);
writer
.
println
(
"An attempt was made to call a method that does not"
writer
.
println
(
"An attempt was made to call a method that does not"
...
@@ -99,11 +125,12 @@ class NoSuchMethodFailureAnalyzer extends AbstractFailureAnalyzer<NoSuchMethodEr
...
@@ -99,11 +125,12 @@ class NoSuchMethodFailureAnalyzer extends AbstractFailureAnalyzer<NoSuchMethodEr
writer
.
println
(
"The following method did not exist:"
);
writer
.
println
(
"The following method did not exist:"
);
writer
.
println
();
writer
.
println
();
writer
.
print
(
" "
);
writer
.
print
(
" "
);
writer
.
println
(
cause
.
get
Message
());
writer
.
println
(
descriptor
.
getError
Message
());
writer
.
println
();
writer
.
println
();
writer
.
println
(
"The method's class, "
+
className
+
", is available from the following locations:"
);
writer
.
println
(
"The method's class, "
+
descriptor
.
getClassName
()
+
", is available from the following locations:"
);
writer
.
println
();
writer
.
println
();
for
(
URL
candidate
:
candidates
)
{
for
(
URL
candidate
:
descriptor
.
getCandidateLocations
()
)
{
writer
.
print
(
" "
);
writer
.
print
(
" "
);
writer
.
println
(
candidate
);
writer
.
println
(
candidate
);
}
}
...
@@ -111,8 +138,44 @@ class NoSuchMethodFailureAnalyzer extends AbstractFailureAnalyzer<NoSuchMethodEr
...
@@ -111,8 +138,44 @@ class NoSuchMethodFailureAnalyzer extends AbstractFailureAnalyzer<NoSuchMethodEr
writer
.
println
(
"It was loaded from the following location:"
);
writer
.
println
(
"It was loaded from the following location:"
);
writer
.
println
();
writer
.
println
();
writer
.
print
(
" "
);
writer
.
print
(
" "
);
writer
.
println
(
actual
);
writer
.
println
(
descriptor
.
getActualLocation
()
);
return
description
.
toString
();
return
description
.
toString
();
}
}
protected
static
class
NoSuchMethodDescriptor
{
private
final
String
errorMessage
;
private
final
String
className
;
private
final
List
<
URL
>
candidateLocations
;
private
final
URL
actualLocation
;
public
NoSuchMethodDescriptor
(
String
errorMessage
,
String
className
,
List
<
URL
>
candidateLocations
,
URL
actualLocation
)
{
this
.
errorMessage
=
errorMessage
;
this
.
className
=
className
;
this
.
candidateLocations
=
candidateLocations
;
this
.
actualLocation
=
actualLocation
;
}
public
String
getErrorMessage
()
{
return
this
.
errorMessage
;
}
public
String
getClassName
()
{
return
this
.
className
;
}
public
List
<
URL
>
getCandidateLocations
()
{
return
this
.
candidateLocations
;
}
public
URL
getActualLocation
()
{
return
this
.
actualLocation
;
}
}
}
}
spring-boot-project/spring-boot/src/test/java/org/springframework/boot/diagnostics/analyzer/NoSuchMethodFailureAnalyzerTests.java
View file @
ac4dcfbf
...
@@ -23,6 +23,7 @@ import org.junit.Test;
...
@@ -23,6 +23,7 @@ import org.junit.Test;
import
org.junit.runner.RunWith
;
import
org.junit.runner.RunWith
;
import
org.springframework.boot.diagnostics.FailureAnalysis
;
import
org.springframework.boot.diagnostics.FailureAnalysis
;
import
org.springframework.boot.diagnostics.analyzer.NoSuchMethodFailureAnalyzer.NoSuchMethodDescriptor
;
import
org.springframework.boot.testsupport.runner.classpath.ClassPathOverrides
;
import
org.springframework.boot.testsupport.runner.classpath.ClassPathOverrides
;
import
org.springframework.boot.testsupport.runner.classpath.ModifiedClassPathRunner
;
import
org.springframework.boot.testsupport.runner.classpath.ModifiedClassPathRunner
;
...
@@ -33,11 +34,54 @@ import static org.mockito.Mockito.mock;
...
@@ -33,11 +34,54 @@ import static org.mockito.Mockito.mock;
* Tests for {@link NoSuchMethodFailureAnalyzer}.
* Tests for {@link NoSuchMethodFailureAnalyzer}.
*
*
* @author Andy Wilkinson
* @author Andy Wilkinson
* @author Stephane Nicoll
*/
*/
@RunWith
(
ModifiedClassPathRunner
.
class
)
@RunWith
(
ModifiedClassPathRunner
.
class
)
@ClassPathOverrides
(
"javax.servlet:servlet-api:2.5"
)
@ClassPathOverrides
(
"javax.servlet:servlet-api:2.5"
)
public
class
NoSuchMethodFailureAnalyzerTests
{
public
class
NoSuchMethodFailureAnalyzerTests
{
@Test
public
void
parseJava8ErrorMessage
()
{
NoSuchMethodDescriptor
descriptor
=
new
NoSuchMethodFailureAnalyzer
().
getNoSuchMethodDescriptor
(
"javax.servlet.ServletContext.addServlet(Ljava/lang/String;Ljavax/servlet/Servlet;)"
+
"Ljavax/servlet/ServletRegistration$Dynamic;"
);
assertThat
(
descriptor
).
isNotNull
();
assertThat
(
descriptor
.
getErrorMessage
())
.
isEqualTo
(
"javax.servlet.ServletContext.addServlet(Ljava/lang/String;Ljavax/servlet/Servlet;)"
+
"Ljavax/servlet/ServletRegistration$Dynamic;"
);
assertThat
(
descriptor
.
getClassName
()).
isEqualTo
(
"javax.servlet.ServletContext"
);
assertThat
(
descriptor
.
getCandidateLocations
().
size
()).
isGreaterThan
(
1
);
assertThat
(
descriptor
.
getActualLocation
().
toString
()).
contains
(
"servlet-api-2.5.jar"
);
}
@Test
public
void
parseJavaOpenJ9ErrorMessage
()
{
NoSuchMethodDescriptor
descriptor
=
new
NoSuchMethodFailureAnalyzer
().
getNoSuchMethodDescriptor
(
"javax/servlet/ServletContext.addServlet(Ljava/lang/String;Ljavax/servlet/Servlet;)"
+
"Ljavax/servlet/ServletRegistration$Dynamic; (loaded from file..."
);
assertThat
(
descriptor
).
isNotNull
();
assertThat
(
descriptor
.
getErrorMessage
())
.
isEqualTo
(
"javax/servlet/ServletContext.addServlet(Ljava/lang/String;Ljavax/servlet/Servlet;)"
+
"Ljavax/servlet/ServletRegistration$Dynamic;"
);
assertThat
(
descriptor
.
getClassName
()).
isEqualTo
(
"javax.servlet.ServletContext"
);
assertThat
(
descriptor
.
getCandidateLocations
().
size
()).
isGreaterThan
(
1
);
assertThat
(
descriptor
.
getActualLocation
().
toString
()).
contains
(
"servlet-api-2.5.jar"
);
}
@Test
public
void
parseJavaImprovedHotspotErrorMessage
()
{
NoSuchMethodDescriptor
descriptor
=
new
NoSuchMethodFailureAnalyzer
().
getNoSuchMethodDescriptor
(
"'javax.servlet.ServletRegistration$Dynamic javax.servlet.ServletContext.addServlet("
+
"java.lang.String, javax.servlet.Servlet)'"
);
assertThat
(
descriptor
).
isNotNull
();
assertThat
(
descriptor
.
getErrorMessage
())
.
isEqualTo
(
"'javax.servlet.ServletRegistration$Dynamic javax.servlet.ServletContext.addServlet("
+
"java.lang.String, javax.servlet.Servlet)'"
);
assertThat
(
descriptor
.
getClassName
()).
isEqualTo
(
"javax.servlet.ServletContext"
);
assertThat
(
descriptor
.
getCandidateLocations
().
size
()).
isGreaterThan
(
1
);
assertThat
(
descriptor
.
getActualLocation
().
toString
()).
contains
(
"servlet-api-2.5.jar"
);
}
@Test
@Test
public
void
noSuchMethodErrorIsAnalyzed
()
{
public
void
noSuchMethodErrorIsAnalyzed
()
{
Throwable
failure
=
createFailure
();
Throwable
failure
=
createFailure
();
...
@@ -45,9 +89,7 @@ public class NoSuchMethodFailureAnalyzerTests {
...
@@ -45,9 +89,7 @@ public class NoSuchMethodFailureAnalyzerTests {
FailureAnalysis
analysis
=
new
NoSuchMethodFailureAnalyzer
().
analyze
(
failure
);
FailureAnalysis
analysis
=
new
NoSuchMethodFailureAnalyzer
().
analyze
(
failure
);
assertThat
(
analysis
).
isNotNull
();
assertThat
(
analysis
).
isNotNull
();
assertThat
(
analysis
.
getDescription
())
assertThat
(
analysis
.
getDescription
())
.
contains
(
NoSuchMethodFailureAnalyzerTests
.
class
.
getName
()
+
".createFailure("
)
.
contains
(
NoSuchMethodFailureAnalyzerTests
.
class
.
getName
()
+
".createFailure("
).
contains
(
"addServlet("
)
.
contains
(
"javax.servlet.ServletContext.addServlet"
+
"(Ljava/lang/String;Ljavax/servlet/Servlet;)"
+
"Ljavax/servlet/ServletRegistration$Dynamic;"
)
.
contains
(
"class, javax.servlet.ServletContext,"
);
.
contains
(
"class, javax.servlet.ServletContext,"
);
}
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment