3 changed files with 173 additions and 0 deletions
@ -0,0 +1,108 @@
@@ -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 @@
@@ -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