getsentry / sentry-java

A Sentry SDK for Java, Android and other JVM languages.
https://docs.sentry.io/
MIT License
1.15k stars 433 forks source link

java.lang.ClassNotFoundException: org.springframework.web.servlet.HandlerExceptionResolver #1863

Open chulkilee opened 2 years ago

chulkilee commented 2 years ago

Platform:

Build system:

The version of the SDK: 5.5.1


I have the following issue:

When using io.sentry:sentry-spring-boot-starter as runtime deps on spring boot batch application, which has also a web endpoint (using , the spring boot application fails to start. See the stacktrace at the bottom.

The error says org.springframework.web.servlet.HandlerExceptionResolver is undefined. I see io.sentry:sentry-spring without having dependency to org.springframework:spring-webmvcdirectly - maybe that's the issue?

When I add org.springframework:spring-webmvc or org.springframework.boot:spring-boot-starter-web as runtime dep, it does not happen.

Also when I remove io.sentry:sentry-spring-boot-starter from the runtime dep, it does not happen.

Steps to reproduce:

Sorry, don't have time to make a minimal reproducible project for this.

Actual result:

java.lang.IllegalStateException: Error processing condition on io.sentry.spring.boot.SentryAutoConfiguration$HubConfiguration$SentryWebMvcConfiguration.sentryTracingFilter
    at org.springframework.boot.autoconfigure.condition.SpringBootCondition.matches(SpringBootCondition.java:60)
    at org.springframework.context.annotation.ConditionEvaluator.shouldSkip(ConditionEvaluator.java:108)
    at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsForBeanMethod(ConfigurationClassBeanDefinitionReader.java:193)
    at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsForConfigurationClass(ConfigurationClassBeanDefinitionReader.java:153)
    at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitions(ConfigurationClassBeanDefinitionReader.java:129)
    at org.springframework.context.annotation.ConfigurationClassPostProcessor.processConfigBeanDefinitions(ConfigurationClassPostProcessor.java:343)
    at org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(ConfigurationClassPostProcessor.java:247)
    at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanDefinitionRegistryPostProcessors(PostProcessorRegistrationDelegate.java:311)
    at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:112)
    at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:746)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:564)
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:144)
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:782)
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:774)
    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:439)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:339)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1340)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1329)
    at ---
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:568)
    at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:49)
    at org.springframework.boot.loader.Launcher.launch(Launcher.java:108)
    at org.springframework.boot.loader.Launcher.launch(Launcher.java:58)
    at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:88)
Caused by: java.lang.IllegalStateException: Failed to introspect Class [io.sentry.spring.boot.SentryAutoConfiguration$HubConfiguration$SentryWebMvcConfiguration] from ClassLoader [org.springframework.boot.loader.LaunchedURLClassLoader@72725ee1]
    at org.springframework.util.ReflectionUtils.getDeclaredMethods(ReflectionUtils.java:481)
    at org.springframework.util.ReflectionUtils.doWithMethods(ReflectionUtils.java:358)
    at org.springframework.util.ReflectionUtils.getUniqueDeclaredMethods(ReflectionUtils.java:414)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.lambda$getTypeForFactoryMethod$2(AbstractAutowireCapableBeanFactory.java:747)
    at java.base/java.util.concurrent.ConcurrentHashMap.computeIfAbsent(ConcurrentHashMap.java:1708)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.getTypeForFactoryMethod(AbstractAutowireCapableBeanFactory.java:746)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.determineTargetType(AbstractAutowireCapableBeanFactory.java:685)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.predictBeanType(AbstractAutowireCapableBeanFactory.java:656)
    at org.springframework.beans.factory.support.AbstractBeanFactory.isFactoryBean(AbstractBeanFactory.java:1670)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doGetBeanNamesForType(DefaultListableBeanFactory.java:570)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanNamesForType(DefaultListableBeanFactory.java:542)
    at org.springframework.boot.autoconfigure.condition.OnBeanCondition.collectBeanNamesForType(OnBeanCondition.java:238)
    at org.springframework.boot.autoconfigure.condition.OnBeanCondition.getBeanNamesForType(OnBeanCondition.java:231)
    at org.springframework.boot.autoconfigure.condition.OnBeanCondition.getBeanNamesForType(OnBeanCondition.java:221)
    at org.springframework.boot.autoconfigure.condition.OnBeanCondition.getMatchingBeans(OnBeanCondition.java:169)
    at org.springframework.boot.autoconfigure.condition.OnBeanCondition.getMatchOutcome(OnBeanCondition.java:119)
    at org.springframework.boot.autoconfigure.condition.AbstractNestedCondition$MemberOutcomes.getConditionOutcome(AbstractNestedCondition.java:194)
    at org.springframework.boot.autoconfigure.condition.AbstractNestedCondition$MemberOutcomes.<init>(AbstractNestedCondition.java:188)
    at org.springframework.boot.autoconfigure.condition.AbstractNestedCondition$MemberConditions.lambda$getMatchOutcomes$0(AbstractNestedCondition.java:168)
    at java.base/java.util.Map.forEach(Map.java:713)
    at java.base/java.util.Collections$UnmodifiableMap.forEach(Collections.java:1553)
    at org.springframework.boot.autoconfigure.condition.AbstractNestedCondition$MemberConditions.getMatchOutcomes(AbstractNestedCondition.java:168)
    at org.springframework.boot.autoconfigure.condition.AbstractNestedCondition$MemberMatchOutcomes.<init>(AbstractNestedCondition.java:78)
    at org.springframework.boot.autoconfigure.condition.AbstractNestedCondition.getMatchOutcome(AbstractNestedCondition.java:63)
    at org.springframework.boot.autoconfigure.condition.SpringBootCondition.matches(SpringBootCondition.java:47)
    ... 26 common frames omitted
Caused by: java.lang.NoClassDefFoundError: org/springframework/web/servlet/HandlerExceptionResolver
    at java.base/java.lang.ClassLoader.defineClass1(Native Method)
    at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1012)
    at java.base/java.security.SecureClassLoader.defineClass(SecureClassLoader.java:150)
    at java.base/java.net.URLClassLoader.defineClass(URLClassLoader.java:524)
    at java.base/java.net.URLClassLoader$1.run(URLClassLoader.java:427)
    at java.base/java.net.URLClassLoader$1.run(URLClassLoader.java:421)
    at java.base/java.security.AccessController.doPrivileged(AccessController.java:712)
    at java.base/java.net.URLClassLoader.findClass(URLClassLoader.java:420)
    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:587)
    at org.springframework.boot.loader.LaunchedURLClassLoader.loadClass(LaunchedURLClassLoader.java:151)
    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:520)
    at java.base/java.lang.Class.getDeclaredMethods0(Native Method)
    at java.base/java.lang.Class.privateGetDeclaredMethods(Class.java:3402)
    at java.base/java.lang.Class.getDeclaredMethods(Class.java:2504)
    at org.springframework.util.ReflectionUtils.getDeclaredMethods(ReflectionUtils.java:463)
    ... 50 common frames omitted
Caused by: java.lang.ClassNotFoundException: org.springframework.web.servlet.HandlerExceptionResolver
    at java.base/java.net.URLClassLoader.findClass(URLClassLoader.java:445)
    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:587)
    at org.springframework.boot.loader.LaunchedURLClassLoader.loadClass(LaunchedURLClassLoader.java:151)
    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:520)
    ... 65 common frames omitted

java.lang.IllegalStateException: Failed to introspect Class [io.sentry.spring.boot.SentryAutoConfiguration$HubConfiguration$SentryWebMvcConfiguration] from ClassLoader [org.springframework.boot.loader.LaunchedURLClassLoader@72725ee1]
    at org.springframework.util.ReflectionUtils.getDeclaredMethods(ReflectionUtils.java:481)
    at org.springframework.util.ReflectionUtils.doWithMethods(ReflectionUtils.java:358)
    at org.springframework.util.ReflectionUtils.getUniqueDeclaredMethods(ReflectionUtils.java:414)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.lambda$getTypeForFactoryMethod$2(AbstractAutowireCapableBeanFactory.java:747)
    at java.base/java.util.concurrent.ConcurrentHashMap.computeIfAbsent(ConcurrentHashMap.java:1708)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.getTypeForFactoryMethod(AbstractAutowireCapableBeanFactory.java:746)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.determineTargetType(AbstractAutowireCapableBeanFactory.java:685)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.predictBeanType(AbstractAutowireCapableBeanFactory.java:656)
    at org.springframework.beans.factory.support.AbstractBeanFactory.isFactoryBean(AbstractBeanFactory.java:1670)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doGetBeanNamesForType(DefaultListableBeanFactory.java:570)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanNamesForType(DefaultListableBeanFactory.java:542)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:667)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:659)
    at org.springframework.context.support.AbstractApplicationContext.getBeansOfType(AbstractApplicationContext.java:1300)
    at org.springframework.boot.SpringApplication.getExitCodeFromMappedException(SpringApplication.java:914)
    at org.springframework.boot.SpringApplication.getExitCodeFromException(SpringApplication.java:902)
    at org.springframework.boot.SpringApplication.handleExitCode(SpringApplication.java:889)
    at org.springframework.boot.SpringApplication.handleRunFailure(SpringApplication.java:830)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:349)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1340)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1329)
    at ---
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:568)
    at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:49)
    at org.springframework.boot.loader.Launcher.launch(Launcher.java:108)
    at org.springframework.boot.loader.Launcher.launch(Launcher.java:58)
    at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:88)
Caused by: java.lang.NoClassDefFoundError: org/springframework/web/servlet/HandlerExceptionResolver
    at java.base/java.lang.ClassLoader.defineClass1(Native Method)
    at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1012)
    at java.base/java.security.SecureClassLoader.defineClass(SecureClassLoader.java:150)
    at java.base/java.net.URLClassLoader.defineClass(URLClassLoader.java:524)
    at java.base/java.net.URLClassLoader$1.run(URLClassLoader.java:427)
    at java.base/java.net.URLClassLoader$1.run(URLClassLoader.java:421)
    at java.base/java.security.AccessController.doPrivileged(AccessController.java:712)
    at java.base/java.net.URLClassLoader.findClass(URLClassLoader.java:420)
    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:587)
    at org.springframework.boot.loader.LaunchedURLClassLoader.loadClass(LaunchedURLClassLoader.java:151)
    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:520)
    at java.base/java.lang.Class.getDeclaredMethods0(Native Method)
    at java.base/java.lang.Class.privateGetDeclaredMethods(Class.java:3402)
    at java.base/java.lang.Class.getDeclaredMethods(Class.java:2504)
    at org.springframework.util.ReflectionUtils.getDeclaredMethods(ReflectionUtils.java:463)
    ... 29 common frames omitted
Caused by: java.lang.ClassNotFoundException: org.springframework.web.servlet.HandlerExceptionResolver
    at java.base/java.net.URLClassLoader.findClass(URLClassLoader.java:445)
    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:587)
    at org.springframework.boot.loader.LaunchedURLClassLoader.loadClass(LaunchedURLClassLoader.java:151)
    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:520)
    ... 44 common frames omitted

Expected result:

maciejwalkowiak commented 2 years ago

Thanks for reporting. Indeed SentryWebMvcConfiguration that was meant to be triggered only for Spring MVC application, triggers also when there is no Spring MVC, just that application runs in servlet mode (which in most cases means that it is a Spring MVC application, but not necessarily in this one).

I assume in your setup, you have only spring-web in your classpath from Spring Framework web-related dependencies?

mihalyr commented 5 months ago

Hi @bruno-garcia

It seems this was marked as completed, but today I just ran into the same problem with Spring Boot 3.2.4 and Sentry 7.6.0 when I tried to add the Spring Boot auto-configuration which was recommended in the Sentry documentation. Our project doesn't use Spring Web MVC.

Caused by: java.lang.IllegalStateException: Failed to introspect Class [io.sentry.spring.boot.jakarta.SentryAutoConfiguration$HubConfiguration$SentryWebMvcConfiguration] from ClassLoader [jdk.internal.loader.ClassLoaders$AppClassLoader@4f2410ac]

    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.predictBeanType(AbstractAutowireCapableBeanFactory.java:653) ~[spring-beans-6.1.5.jar:6.1.5]
    at org.springframework.beans.factory.support.AbstractBeanFactory.isFactoryBean(AbstractBeanFactory.java:1645) ~[spring-beans-6.1.5.jar:6.1.5]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doGetBeanNamesForType(DefaultListableBeanFactory.java:562) ~[spring-beans-6.1.5.jar:6.1.5]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanNamesForType(DefaultListableBeanFactory.java:534) ~[spring-beans-6.1.5.jar:6.1.5]
    at org.springframework.boot.autoconfigure.condition.OnBeanCondition.collectBeanNamesForType(OnBeanCondition.java:247) ~[spring-boot-autoconfigure-3.2.4.jar:3.2.4]
    at org.springframework.boot.autoconfigure.condition.OnBeanCondition.getBeanNamesForType(OnBeanCondition.java:240) ~[spring-boot-autoconfigure-3.2.4.jar:3.2.4]
    at org.springframework.boot.autoconfigure.condition.OnBeanCondition.getBeanNamesForType(OnBeanCondition.java:230) ~[spring-boot-autoconfigure-3.2.4.jar:3.2.4]
    at org.springframework.boot.autoconfigure.condition.OnBeanCondition.getMatchingBeans(OnBeanCondition.java:183) ~[spring-boot-autoconfigure-3.2.4.jar:3.2.4]
    at org.springframework.boot.autoconfigure.condition.OnBeanCondition.getMatchOutcome(OnBeanCondition.java:158) ~[spring-boot-autoconfigure-3.2.4.jar:3.2.4]
    at org.springframework.boot.autoconfigure.condition.SpringBootCondition.matches(SpringBootCondition.java:47) ~[spring-boot-autoconfigure-3.2.4.jar:3.2.4]
    ... 17 more
Caused by: java.lang.NoClassDefFoundError: org/springframework/web/servlet/HandlerExceptionResolver
    at java.base/java.lang.ClassLoader.defineClass1(Native Method) ~[?:?]
Caused by: java.lang.NoClassDefFoundError: org/springframework/web/servlet/HandlerExceptionResolver

    at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1027) ~[?:?]
    at java.base/java.security.SecureClassLoader.defineClass(SecureClassLoader.java:150) ~[?:?]
    at java.base/jdk.internal.loader.BuiltinClassLoader.defineClass(BuiltinClassLoader.java:862) ~[?:?]
    at java.base/jdk.internal.loader.BuiltinClassLoader.findClassOnClassPathOrNull(BuiltinClassLoader.java:760) ~[?:?]
    at java.base/jdk.internal.loader.BuiltinClassLoader.loadClassOrNull(BuiltinClassLoader.java:681) ~[?:?]
    at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:639) ~[?:?]
    at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188) ~[?:?]
    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:526) ~[?:?]
    at java.base/java.lang.Class.getDeclaredMethods0(Native Method) ~[?:?]
    at java.base/java.lang.Class.privateGetDeclaredMethods(Class.java:3578) ~[?:?]
    at java.base/java.lang.Class.getDeclaredMethods(Class.java:2676) ~[?:?]
    at org.springframework.util.ReflectionUtils.getDeclaredMethods(ReflectionUtils.java:465) ~[spring-core-6.1.5.jar:6.1.5]
    at org.springframework.util.ReflectionUtils.doWithMethods(ReflectionUtils.java:360) ~[spring-core-6.1.5.jar:6.1.5]
    at org.springframework.util.ReflectionUtils.getUniqueDeclaredMethods(ReflectionUtils.java:417) ~[spring-core-6.1.5.jar:6.1.5]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.lambda$getTypeForFactoryMethod$1(AbstractAutowireCapableBeanFactory.java:750) ~[spring-beans-6.1.5.jar:6.1.5]
    at java.base/java.util.concurrent.ConcurrentHashMap.computeIfAbsent(ConcurrentHashMap.java:1708) ~[?:?]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.getTypeForFactoryMethod(AbstractAutowireCapableBeanFactory.java:749) ~[spring-beans-6.1.5.jar:6.1.5]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.determineTargetType(AbstractAutowireCapableBeanFactory.java:682) ~[spring-beans-6.1.5.jar:6.1.5]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.predictBeanType(AbstractAutowireCapableBeanFactory.java:653) ~[spring-beans-6.1.5.jar:6.1.5]
    at org.springframework.beans.factory.support.AbstractBeanFactory.isFactoryBean(AbstractBeanFactory.java:1645) ~[spring-beans-6.1.5.jar:6.1.5]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doGetBeanNamesForType(DefaultListableBeanFactory.java:562) ~[spring-beans-6.1.5.jar:6.1.5]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanNamesForType(DefaultListableBeanFactory.java:534) ~[spring-beans-6.1.5.jar:6.1.5]
    at org.springframework.boot.autoconfigure.condition.OnBeanCondition.collectBeanNamesForType(OnBeanCondition.java:247) ~[spring-boot-autoconfigure-3.2.4.jar:3.2.4]
    at org.springframework.boot.autoconfigure.condition.OnBeanCondition.getBeanNamesForType(OnBeanCondition.java:240) ~[spring-boot-autoconfigure-3.2.4.jar:3.2.4]
    at org.springframework.boot.autoconfigure.condition.OnBeanCondition.getBeanNamesForType(OnBeanCondition.java:230) ~[spring-boot-autoconfigure-3.2.4.jar:3.2.4]
    at org.springframework.boot.autoconfigure.condition.OnBeanCondition.getMatchingBeans(OnBeanCondition.java:183) ~[spring-boot-autoconfigure-3.2.4.jar:3.2.4]
    at org.springframework.boot.autoconfigure.condition.OnBeanCondition.getMatchOutcome(OnBeanCondition.java:158) ~[spring-boot-autoconfigure-3.2.4.jar:3.2.4]
    at org.springframework.boot.autoconfigure.condition.SpringBootCondition.matches(SpringBootCondition.java:47) ~[spring-boot-autoconfigure-3.2.4.jar:3.2.4]
    ... 17 more
Caused by: java.lang.ClassNotFoundException: org.springframework.web.servlet.HandlerExceptionResolver
    at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641) ~[?:?]
    at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188) ~[?:?]
    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:526) ~[?:?]
    at java.base/java.lang.ClassLoader.defineClass1(Native Method) ~[?:?]
    at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1027) ~[?:?]
    at java.base/java.security.SecureClassLoader.defineClass(SecureClassLoader.java:150) ~[?:?]
    at java.base/jdk.internal.loader.BuiltinClassLoader.defineClass(BuiltinClassLoader.java:862) ~[?:?]
    at java.base/jdk.internal.loader.BuiltinClassLoader.findClassOnClassPathOrNull(BuiltinClassLoader.java:760) ~[?:?]
    at java.base/jdk.internal.loader.BuiltinClassLoader.loadClassOrNull(BuiltinClassLoader.java:681) ~[?:?]
    at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:639) ~[?:?]
    at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188) ~[?:?]
    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:526) ~[?:?]
    at java.base/java.lang.Class.getDeclaredMethods0(Native Method) ~[?:?]
    at java.base/java.lang.Class.privateGetDeclaredMethods(Class.java:3578) ~[?:?]
Caused by: java.lang.ClassNotFoundException: org.springframework.web.servlet.HandlerExceptionResolver

    at java.base/java.lang.Class.getDeclaredMethods(Class.java:2676) ~[?:?]
    at org.springframework.util.ReflectionUtils.getDeclaredMethods(ReflectionUtils.java:465) ~[spring-core-6.1.5.jar:6.1.5]
    at org.springframework.util.ReflectionUtils.doWithMethods(ReflectionUtils.java:360) ~[spring-core-6.1.5.jar:6.1.5]
    at org.springframework.util.ReflectionUtils.getUniqueDeclaredMethods(ReflectionUtils.java:417) ~[spring-core-6.1.5.jar:6.1.5]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.lambda$getTypeForFactoryMethod$1(AbstractAutowireCapableBeanFactory.java:750) ~[spring-beans-6.1.5.jar:6.1.5]
    at java.base/java.util.concurrent.ConcurrentHashMap.computeIfAbsent(ConcurrentHashMap.java:1708) ~[?:?]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.getTypeForFactoryMethod(AbstractAutowireCapableBeanFactory.java:749) ~[spring-beans-6.1.5.jar:6.1.5]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.determineTargetType(AbstractAutowireCapableBeanFactory.java:682) ~[spring-beans-6.1.5.jar:6.1.5]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.predictBeanType(AbstractAutowireCapableBeanFactory.java:653) ~[spring-beans-6.1.5.jar:6.1.5]
    at org.springframework.beans.factory.support.AbstractBeanFactory.isFactoryBean(AbstractBeanFactory.java:1645) ~[spring-beans-6.1.5.jar:6.1.5]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doGetBeanNamesForType(DefaultListableBeanFactory.java:562) ~[spring-beans-6.1.5.jar:6.1.5]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanNamesForType(DefaultListableBeanFactory.java:534) ~[spring-beans-6.1.5.jar:6.1.5]
    at org.springframework.boot.autoconfigure.condition.OnBeanCondition.collectBeanNamesForType(OnBeanCondition.java:247) ~[spring-boot-autoconfigure-3.2.4.jar:3.2.4]
    at org.springframework.boot.autoconfigure.condition.OnBeanCondition.getBeanNamesForType(OnBeanCondition.java:240) ~[spring-boot-autoconfigure-3.2.4.jar:3.2.4]
    at org.springframework.boot.autoconfigure.condition.OnBeanCondition.getBeanNamesForType(OnBeanCondition.java:230) ~[spring-boot-autoconfigure-3.2.4.jar:3.2.4]
    at org.springframework.boot.autoconfigure.condition.OnBeanCondition.getMatchingBeans(OnBeanCondition.java:183) ~[spring-boot-autoconfigure-3.2.4.jar:3.2.4]
    at org.springframework.boot.autoconfigure.condition.OnBeanCondition.getMatchOutcome(OnBeanCondition.java:158) ~[spring-boot-autoconfigure-3.2.4.jar:3.2.4]
    at org.springframework.boot.autoconfigure.condition.SpringBootCondition.matches(SpringBootCondition.java:47) ~[spring-boot-autoconfigure-3.2.4.jar:3.2.4]
    ... 17 more

Dependencies:

dependencies {
    implementation platform("org.springframework.boot:spring-boot-dependencies:$springBootVersion")

    implementation('org.springframework.boot:spring-boot-starter-web') {
        exclude group: 'org.springframework', module: 'spring-webmvc'
    }
    // Use Jetty and Jersey instead of Tomcat and Spring Web MVC
    implementation "org.springframework.boot:spring-boot-starter-jetty"
    implementation "org.springframework.boot:spring-boot-starter-jersey"

    // Replace the Spring boot defaults with the selected modules
    modules {
        module("org.springframework.boot:spring-boot-starter-logging") {
            replacedBy("org.springframework.boot:spring-boot-starter-log4j2", "Use Log4j2 instead of Logback")
        }
        module("org.springframework.boot:spring-boot-starter-tomcat") {
            replacedBy("org.springframework.boot:spring-boot-starter-jetty", "Use Jetty instead of Tomcat")
        }
    }

    // Logging
    implementation 'org.springframework.boot:spring-boot-starter-log4j2'
    runtimeOnly "org.apache.logging.log4j:log4j-layout-template-json"

    // Sentry
    implementation "io.sentry:sentry-spring-boot-starter-jakarta:$sentryVersion"
    implementation "io.sentry:sentry-okhttp:$sentryVersion"
    runtimeOnly "io.sentry:sentry-log4j2:$sentryVersion"

Spring configuration:

spring:
  main:
    web-application-type: servlet

sentry:
  dsn: "${SENTRY_DSN:}"
  release: "${SENTRY_RELEASE:}"
  traces-sample-rate: "${SENTRY_TRACES_SAMPLE_RATE:0.0}"
  trace-options-requests: "${SENTRY_TRACE_OPTIONS_REQUESTS:false}"
adinauer commented 5 months ago

Hello @mihalyr thanks for the report. That's odd. The only place where HandlerExceptionResolver is used is guarded by a conditional: https://github.com/getsentry/sentry-java/blob/305baf5bd419920f4b80ff6f0075c13dd42c2b94/sentry-spring-boot-jakarta/src/main/java/io/sentry/spring/boot/jakarta/SentryAutoConfiguration.java#L302

We'll have to do some testing and report back.

adinauer commented 5 months ago

@mihalyr I'm able to reproduce the issue. Trying to figure out why this is happening and how to fix it.

adinauer commented 5 months ago

I've found a way to fix it (described in the PR).

adinauer commented 5 months ago

@mihalyr we've just released 7.7.0 which should fix the problem, please let us know if it worked.

mihalyr commented 5 months ago

@adinauer amazing, this was a very quick turnaround, thank you so much!

I can confirm that now I can boot the server without the errors, but now I'm facing runtime errors on incoming API calls, here is the full stacktrace:

2024-04-08T13:04:38,600 [WARN ] (qtp198341554-75) : ServletChannel - /users/self
java.lang.NoClassDefFoundError: org/springframework/web/servlet/HandlerMapping
    at io.sentry.spring.jakarta.tracing.SpringMvcTransactionNameProvider.provideTransactionName(SpringMvcTransactionNameProvider.java:20) ~[sentry-spring-jakarta-7.7.0.jar:?]
    at io.sentry.spring.jakarta.tracing.SentryTracingFilter.doFilterWithTransaction(SentryTracingFilter.java:114) ~[sentry-spring-jakarta-7.7.0.jar:?]
    at io.sentry.spring.jakarta.tracing.SentryTracingFilter.doFilterInternal(SentryTracingFilter.java:87) ~[sentry-spring-jakarta-7.7.0.jar:?]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.1.5.jar:6.1.5]
    at org.eclipse.jetty.ee10.servlet.FilterHolder.doFilter(FilterHolder.java:205) ~[jetty-ee10-servlet-12.0.7.jar:12.0.7]
    at org.eclipse.jetty.ee10.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1586) ~[jetty-ee10-servlet-12.0.7.jar:12.0.7]
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-6.1.5.jar:6.1.5]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.1.5.jar:6.1.5]
    at org.eclipse.jetty.ee10.servlet.FilterHolder.doFilter(FilterHolder.java:205) ~[jetty-ee10-servlet-12.0.7.jar:12.0.7]
    at org.eclipse.jetty.ee10.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1586) ~[jetty-ee10-servlet-12.0.7.jar:12.0.7]
    at io.sentry.spring.jakarta.SentrySpringFilter.doFilterInternal(SentrySpringFilter.java:71) ~[sentry-spring-jakarta-7.7.0.jar:?]
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.1.5.jar:6.1.5]
    at org.eclipse.jetty.ee10.servlet.FilterHolder.doFilter(FilterHolder.java:205) ~[jetty-ee10-servlet-12.0.7.jar:12.0.7]
    at org.eclipse.jetty.ee10.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1586) ~[jetty-ee10-servlet-12.0.7.jar:12.0.7]
    at org.eclipse.jetty.ee10.servlet.ServletHandler$MappedServlet.handle(ServletHandler.java:1547) ~[jetty-ee10-servlet-12.0.7.jar:12.0.7]
    at org.eclipse.jetty.ee10.servlet.ServletChannel.dispatch(ServletChannel.java:814) ~[jetty-ee10-servlet-12.0.7.jar:12.0.7]
    at org.eclipse.jetty.ee10.servlet.ServletChannel.handle(ServletChannel.java:431) ~[jetty-ee10-servlet-12.0.7.jar:12.0.7]
    at org.eclipse.jetty.ee10.servlet.ServletHandler.handle(ServletHandler.java:464) ~[jetty-ee10-servlet-12.0.7.jar:12.0.7]
    at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:571) ~[jetty-security-12.0.7.jar:12.0.7]
    at org.eclipse.jetty.ee10.servlet.SessionHandler.handle(SessionHandler.java:703) ~[jetty-ee10-servlet-12.0.7.jar:12.0.7]
    at org.eclipse.jetty.server.handler.ContextHandler.handle(ContextHandler.java:765) ~[jetty-server-12.0.7.jar:12.0.7]
    at org.eclipse.jetty.server.handler.gzip.GzipHandler.handle(GzipHandler.java:597) ~[jetty-server-12.0.7.jar:12.0.7]
    at org.eclipse.jetty.server.Handler$Wrapper.handle(Handler.java:716) ~[jetty-server-12.0.7.jar:12.0.7]
    at org.eclipse.jetty.server.handler.EventsHandler.handle(EventsHandler.java:81) ~[jetty-server-12.0.7.jar:12.0.7]
    at org.eclipse.jetty.server.Server.handle(Server.java:179) ~[jetty-server-12.0.7.jar:12.0.7]
    at org.eclipse.jetty.server.internal.HttpChannelState$HandlerInvoker.run(HttpChannelState.java:619) ~[jetty-server-12.0.7.jar:12.0.7]
    at org.eclipse.jetty.server.internal.HttpConnection.onFillable(HttpConnection.java:411) ~[jetty-server-12.0.7.jar:12.0.7]
    at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:322) ~[jetty-io-12.0.7.jar:12.0.7]
    at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:99) ~[jetty-io-12.0.7.jar:12.0.7]
    at org.eclipse.jetty.io.SelectableChannelEndPoint$1.run(SelectableChannelEndPoint.java:53) ~[jetty-io-12.0.7.jar:12.0.7]
    at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.runTask(AdaptiveExecutionStrategy.java:478) ~[jetty-util-12.0.7.jar:12.0.7]
    at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.consumeTask(AdaptiveExecutionStrategy.java:441) ~[jetty-util-12.0.7.jar:12.0.7]
    at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.tryProduce(AdaptiveExecutionStrategy.java:293) ~[jetty-util-12.0.7.jar:12.0.7]
    at org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy.run(AdaptiveExecutionStrategy.java:201) ~[jetty-util-12.0.7.jar:12.0.7]
    at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:410) ~[jetty-util-12.0.7.jar:12.0.7]
    at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:971) ~[jetty-util-12.0.7.jar:12.0.7]
    at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.doRunJob(QueuedThreadPool.java:1201) ~[jetty-util-12.0.7.jar:12.0.7]
    at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:1156) ~[jetty-util-12.0.7.jar:12.0.7]
    at java.base/java.lang.Thread.run(Thread.java:1583) [?:?]
Caused by: java.lang.ClassNotFoundException: org.springframework.web.servlet.HandlerMapping
    ... 39 more

Probably the SpringMvcTransactionNameProvider shouldn't be used if Spring MVC is not present.

adinauer commented 5 months ago

Ah sorry - I should have done more testing. I'll take another look.

adinauer commented 5 months ago

We have a PR for a fix open but you'll have to supply your own TransactionNameProvider bean since I had to disable the default. We can take another look at this in the future to supply a fallback default for servlet mode.

Also we should add tests for this but I think that involves creating another sample application with tests that spin up the sample and hit it with requests. Since I'm in the middle of something right now, I'll postpone the tests.

Here's how to supply the bean in case you want to provide custom logic for setting transaction name:

  @Bean
  TransactionNameProvider transactionNameProvider() {
    return new TransactionNameProvider() {
      @Override
      public String provideTransactionName(HttpServletRequest request) {
        return request.getMethod() + " " + request.getServletPath();
      }
    };
  }

Usually we use request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE) to get the endpoint that was requested with IDs replaced. So /todo/100 becomes /todo/{id}. I couldn't find a way to do this if MVC isn't present, so we're setting the requestURI instead.

adinauer commented 5 months ago

@mihalyr we've just released 7.8.0, can you please give it another try?

mihalyr commented 5 months ago

@adinauer thank you, this now works and for simple URL paths it works out of box, but for endpoints with path params it creates a new transaction for every single path parameter. I think, here comes the custom TransactionNameProvider in picture. I'll try a quick implementation just to test if it works as expected.

mihalyr commented 5 months ago

I wanted to do for tx naming what we do for our metric instrumentation where I have a Jersey filter that has access to the resource class and method names so I can easily use those for tx naming. But it seems that Sentry's tx name provider only has access to the servlet request.

Is it possible to set the tx name manually instead of using the tx name provider? I would implement a jersey filter and call Sentry from there to set a tx name. Is that possible?

mihalyr commented 5 months ago

Nvm, I found a way, I can do the same what Spring does and just inject a request attribute from my Jersey filter that will be picked up by Sentry's TransactionNameProvider since it is called later in the request processing, this should work.

Thank you @adinauer for the help and addressing this very quickly!

madukan commented 3 months ago

Using Sentry 7.10.0. Still have this issue. It is a Spring Boot (not MCV) project.

I had to add MVC dependancy to solve the issue.

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

Ideally Sentry should work in all types of Spring boot projects as it claims to be. I'd love to see it working well in Spring-Boot-Shell with Native builds please.

adinauer commented 3 months ago

@madukan are you seeing the java.lang.ClassNotFoundException: org.springframework.web.servlet.HandlerExceptionResolver or a different exception?

madukan commented 3 months ago

@adinauer I see the same exception. Pretty sure it is easy to re-produce if you didn't include the library I mentioned in the comment above at https://github.com/getsentry/sentry-java/issues/1863#issuecomment-2183917841 comment.

adinauer commented 3 months ago

Thanks, we'll investigate. I can't give an ETA though.