Merge branch '2.0.x'
commit
da550efc6b
@ -0,0 +1,108 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012-2018 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.springframework.boot.diagnostics.analyzer;
|
||||||
|
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
import java.io.StringWriter;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.springframework.boot.diagnostics.AbstractFailureAnalyzer;
|
||||||
|
import org.springframework.boot.diagnostics.FailureAnalysis;
|
||||||
|
import org.springframework.util.ClassUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An {@link AbstractFailureAnalyzer} that analyzes {@link NoSuchMethodError
|
||||||
|
* NoSuchMethodErrors}.
|
||||||
|
*
|
||||||
|
* @author Andy Wilkinson
|
||||||
|
*/
|
||||||
|
class NoSuchMethodFailureAnalyzer extends AbstractFailureAnalyzer<NoSuchMethodError> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected FailureAnalysis analyze(Throwable rootFailure, NoSuchMethodError cause) {
|
||||||
|
String className = extractClassName(cause);
|
||||||
|
if (className == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
List<URL> candidates = findCandidates(className);
|
||||||
|
if (candidates == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
URL actual = getActual(className);
|
||||||
|
if (actual == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
StringWriter description = new StringWriter();
|
||||||
|
PrintWriter writer = new PrintWriter(description);
|
||||||
|
writer.print("An attempt was made to call the method ");
|
||||||
|
writer.print(cause.getMessage());
|
||||||
|
writer.print(" but it does not exist. Its class, ");
|
||||||
|
writer.print(className);
|
||||||
|
writer.println(", is available from the following locations:");
|
||||||
|
writer.println();
|
||||||
|
for (URL candidate : candidates) {
|
||||||
|
writer.print(" ");
|
||||||
|
writer.println(candidate);
|
||||||
|
}
|
||||||
|
writer.println();
|
||||||
|
writer.println("It was loaded from the following location:");
|
||||||
|
writer.println();
|
||||||
|
writer.print(" ");
|
||||||
|
writer.println(actual);
|
||||||
|
return new FailureAnalysis(description.toString(),
|
||||||
|
"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('(');
|
||||||
|
if (descriptorIndex == -1) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String classAndMethodName = cause.getMessage().substring(0, descriptorIndex);
|
||||||
|
int methodNameIndex = classAndMethodName.lastIndexOf('.');
|
||||||
|
if (methodNameIndex == -1) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return classAndMethodName.substring(0, methodNameIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<URL> findCandidates(String className) {
|
||||||
|
try {
|
||||||
|
return Collections.list((NoSuchMethodFailureAnalyzer.class.getClassLoader()
|
||||||
|
.getResources(ClassUtils.convertClassNameToResourcePath(className)
|
||||||
|
+ ".class")));
|
||||||
|
}
|
||||||
|
catch (Throwable ex) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private URL getActual(String className) {
|
||||||
|
try {
|
||||||
|
return getClass().getClassLoader().loadClass(className).getProtectionDomain()
|
||||||
|
.getCodeSource().getLocation();
|
||||||
|
}
|
||||||
|
catch (Throwable ex) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012-2018 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.springframework.boot.diagnostics.analyzer;
|
||||||
|
|
||||||
|
import javax.servlet.ServletContext;
|
||||||
|
import javax.servlet.http.HttpServlet;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import org.springframework.boot.diagnostics.FailureAnalysis;
|
||||||
|
import org.springframework.boot.testsupport.runner.classpath.ClassPathOverrides;
|
||||||
|
import org.springframework.boot.testsupport.runner.classpath.ModifiedClassPathRunner;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author awilkinson
|
||||||
|
*/
|
||||||
|
@RunWith(ModifiedClassPathRunner.class)
|
||||||
|
@ClassPathOverrides("javax.servlet:servlet-api:2.5")
|
||||||
|
public class NoSuchMethodFailureAnalyzerTests {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void noSuchMethodErrorIsAnalyzed() {
|
||||||
|
Throwable failure = createFailure();
|
||||||
|
assertThat(failure).isNotNull();
|
||||||
|
FailureAnalysis analysis = new NoSuchMethodFailureAnalyzer().analyze(failure);
|
||||||
|
assertThat(analysis).isNotNull();
|
||||||
|
assertThat(analysis.getDescription())
|
||||||
|
.contains("the method javax.servlet.ServletContext.addServlet"
|
||||||
|
+ "(Ljava/lang/String;Ljavax/servlet/Servlet;)"
|
||||||
|
+ "Ljavax/servlet/ServletRegistration$Dynamic;")
|
||||||
|
.contains("class, javax.servlet.ServletContext,");
|
||||||
|
}
|
||||||
|
|
||||||
|
private Throwable createFailure() {
|
||||||
|
try {
|
||||||
|
ServletContext servletContext = mock(ServletContext.class);
|
||||||
|
servletContext.addServlet("example", new HttpServlet() {
|
||||||
|
});
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
catch (Throwable ex) {
|
||||||
|
return ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue