Improve detection of NoSuchMethodError on Java 13
Closes gh-17544
This commit is contained in:
parent
3a49996dbd
commit
cc6f321da4
|
@ -31,12 +31,14 @@ import org.springframework.util.ClassUtils;
|
|||
* NoSuchMethodErrors}.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
class NoSuchMethodFailureAnalyzer extends AbstractFailureAnalyzer<NoSuchMethodError> {
|
||||
|
||||
@Override
|
||||
protected FailureAnalysis analyze(Throwable rootFailure, NoSuchMethodError cause) {
|
||||
String className = extractClassName(cause);
|
||||
String message = cleanMessage(cause);
|
||||
String className = extractClassName(message);
|
||||
if (className == null) {
|
||||
return null;
|
||||
}
|
||||
|
@ -48,24 +50,33 @@ class NoSuchMethodFailureAnalyzer extends AbstractFailureAnalyzer<NoSuchMethodEr
|
|||
if (actual == null) {
|
||||
return null;
|
||||
}
|
||||
String description = getDescription(cause, className, candidates, actual);
|
||||
String description = getDescription(cause, 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) {
|
||||
int descriptorIndex = cause.getMessage().indexOf('(');
|
||||
private String cleanMessage(NoSuchMethodError error) {
|
||||
int loadedFromIndex = error.getMessage().indexOf(" (loaded from");
|
||||
if (loadedFromIndex == -1) {
|
||||
return error.getMessage();
|
||||
}
|
||||
return error.getMessage().substring(0, loadedFromIndex);
|
||||
}
|
||||
|
||||
private String extractClassName(String message) {
|
||||
int descriptorIndex = message.indexOf('(');
|
||||
if (descriptorIndex == -1) {
|
||||
return null;
|
||||
}
|
||||
String classAndMethodName = cause.getMessage().substring(0, descriptorIndex);
|
||||
String classAndMethodName = message.substring(0, descriptorIndex);
|
||||
int methodNameIndex = classAndMethodName.lastIndexOf('.');
|
||||
if (methodNameIndex == -1) {
|
||||
return null;
|
||||
}
|
||||
return classAndMethodName.substring(0, methodNameIndex);
|
||||
String className = classAndMethodName.substring(0, methodNameIndex);
|
||||
return className.replace('/', '.');
|
||||
}
|
||||
|
||||
private List<URL> findCandidates(String className) {
|
||||
|
@ -87,7 +98,8 @@ class NoSuchMethodFailureAnalyzer extends AbstractFailureAnalyzer<NoSuchMethodEr
|
|||
}
|
||||
}
|
||||
|
||||
private String getDescription(NoSuchMethodError cause, String className, List<URL> candidates, URL actual) {
|
||||
private String getDescription(NoSuchMethodError cause, String message, String className, List<URL> candidates,
|
||||
URL actual) {
|
||||
StringWriter description = new StringWriter();
|
||||
PrintWriter writer = new PrintWriter(description);
|
||||
writer.println("An attempt was made to call a method that does not"
|
||||
|
@ -99,7 +111,7 @@ class NoSuchMethodFailureAnalyzer extends AbstractFailureAnalyzer<NoSuchMethodEr
|
|||
writer.println("The following method did not exist:");
|
||||
writer.println();
|
||||
writer.print(" ");
|
||||
writer.println(cause.getMessage());
|
||||
writer.println(message);
|
||||
writer.println();
|
||||
writer.println("The method's class, " + className + ", is available from the following locations:");
|
||||
writer.println();
|
||||
|
|
|
@ -20,6 +20,9 @@ import javax.servlet.ServletContext;
|
|||
import javax.servlet.http.HttpServlet;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.condition.DisabledOnJre;
|
||||
import org.junit.jupiter.api.condition.EnabledOnJre;
|
||||
import org.junit.jupiter.api.condition.JRE;
|
||||
|
||||
import org.springframework.boot.diagnostics.FailureAnalysis;
|
||||
import org.springframework.boot.testsupport.classpath.ClassPathOverrides;
|
||||
|
@ -36,16 +39,29 @@ import static org.mockito.Mockito.mock;
|
|||
class NoSuchMethodFailureAnalyzerTests {
|
||||
|
||||
@Test
|
||||
void noSuchMethodErrorIsAnalyzed() {
|
||||
@EnabledOnJre({ JRE.JAVA_8, JRE.JAVA_11, JRE.JAVA_12 })
|
||||
void noSuchMethodErrorIsAnalyzedJava8To12() {
|
||||
testNoSuchMethodErrorFailureAnalysis(
|
||||
"javax.servlet.ServletContext.addServlet(Ljava/lang/String;Ljavax/servlet/Servlet;)"
|
||||
+ "Ljavax/servlet/ServletRegistration$Dynamic;");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisabledOnJre({ JRE.JAVA_8, JRE.JAVA_11, JRE.JAVA_12 })
|
||||
void noSuchMethodErrorIsAnalyzedJava13AndLater() {
|
||||
testNoSuchMethodErrorFailureAnalysis(
|
||||
"javax/servlet/ServletContext.addServlet(Ljava/lang/String;Ljavax/servlet/Servlet;)"
|
||||
+ "Ljavax/servlet/ServletRegistration$Dynamic;");
|
||||
}
|
||||
|
||||
private void testNoSuchMethodErrorFailureAnalysis(String expectedMethodRepresentation) {
|
||||
Throwable failure = createFailure();
|
||||
assertThat(failure).isNotNull();
|
||||
FailureAnalysis analysis = new NoSuchMethodFailureAnalyzer().analyze(failure);
|
||||
assertThat(analysis).isNotNull();
|
||||
assertThat(analysis.getDescription())
|
||||
.contains(NoSuchMethodFailureAnalyzerTests.class.getName() + ".createFailure(")
|
||||
.contains("javax.servlet.ServletContext.addServlet(Ljava/lang/String;Ljavax/servlet/Servlet;)"
|
||||
+ "Ljavax/servlet/ServletRegistration$Dynamic;")
|
||||
.contains("class, javax.servlet.ServletContext,");
|
||||
.contains(expectedMethodRepresentation).contains("class, javax.servlet.ServletContext,");
|
||||
}
|
||||
|
||||
private Throwable createFailure() {
|
||||
|
|
Loading…
Reference in New Issue