Skip to content

Commit

Permalink
Merge pull request #191 from bugsnag/integration/spring-boot-3
Browse files Browse the repository at this point in the history
  • Loading branch information
yousif-bugsnag authored Jun 6, 2023
2 parents 444ab64 + 62deb73 commit 5e06bce
Show file tree
Hide file tree
Showing 104 changed files with 2,732 additions and 212 deletions.
29 changes: 23 additions & 6 deletions .buildkite/pipeline.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ steps:
plugins:
- docker-compose#v3.7.0:
run: java-common
command: './gradlew :bugsnag:assemble :bugsnag-spring:assemble'
command: './gradlew :bugsnag:assemble :bugsnag-spring:javax:assemble :bugsnag-spring:assemble'

- label: ':docker: Run JVM tests'
key: 'java-jvm-tests'
Expand All @@ -21,19 +21,36 @@ steps:
run: java-common
command: './gradlew check test'

- label: ':docker: Mazerunner tests batch 1'
- label: ':docker: Mazerunner java8 tests batch 1'
key: 'java-mazerunner-tests-1'
timeout_in_minutes: 30
plugins:
- docker-compose#v3.7.0:
run: java-mazerunner
run: java8-mazerunner
command: 'bundle exec maze-runner --exclude=features/[^a-m].*.feature'

- label: ':docker: Mazerunner tests batch 2'
- label: ':docker: Mazerunner java8 tests batch 2'
key: 'java-mazerunner-tests-2'
timeout_in_minutes: 30
plugins:
- docker-compose#v3.7.0:
pull: java-mazerunner
run: java-mazerunner
pull: java8-mazerunner
run: java8-mazerunner
command: 'bundle exec maze-runner --exclude=features/[^n-z].*.feature'

- label: ':docker: Mazerunner java17 tests batch 1'
key: 'java-mazerunner-tests-3'
timeout_in_minutes: 30
plugins:
- docker-compose#v3.7.0:
run: java17-mazerunner
command: 'bundle exec maze-runner --exclude=features/[^a-m].*.feature'

- label: ':docker: Mazerunner java17 tests batch 2'
key: 'java-mazerunner-tests-4'
timeout_in_minutes: 30
plugins:
- docker-compose#v3.7.0:
pull: java17-mazerunner
run: java17-mazerunner
command: 'bundle exec maze-runner --exclude=features/[^n-z].*.feature'
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

## TBD

* Support Spring 6 / Spring Boot 3
[#191](https://github.com/bugsnag/bugsnag-java/pull/191)

* Bump Jackson from 2.13.3 for critical vulnerability fixes
[#184](https://github.com/bugsnag/bugsnag-java/pull/184)

Expand Down
2 changes: 1 addition & 1 deletion Gemfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
source 'https://rubygems.org'

gem 'bugsnag-maze-runner', git: 'https://github.com/bugsnag/maze-runner', tag: 'v7.10.2'
gem 'bugsnag-maze-runner', git: 'https://github.com/bugsnag/maze-runner', tag: 'v7.24.0'
gem 'os'
34 changes: 25 additions & 9 deletions bugsnag-spring/build.gradle
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
ext {
springVersion = '4.3.18.RELEASE'
springBootVersion = '1.5.15.RELEASE'
springVersion = '6.0.0'
springBootVersion = '3.0.0'
}

apply plugin: 'java-library'
Expand All @@ -12,16 +12,32 @@ repositories {
}

dependencies {
compile project(':bugsnag')
testCompile project(path: ':bugsnag', configuration: 'testRuntime')
compileOnly project(':bugsnag-spring:javax')
api project(':bugsnag')

compileOnly "javax.servlet:javax.servlet-api:${servletApiVersion}"
compileOnly "jakarta.servlet:jakarta.servlet-api:${jakartaServletApiVersion}"
compileOnly "org.springframework:spring-webmvc:${springVersion}"
compileOnly "org.springframework.boot:spring-boot:${springBootVersion}"
compileOnly "ch.qos.logback:logback-core:${logbackVersion}"
compileOnly "org.slf4j:slf4j-api:${slf4jApiVersion}"

testCompile "junit:junit:4.13.2"
testCompile "javax.servlet:javax.servlet-api:${servletApiVersion}"
testCompile "org.springframework.boot:spring-boot-starter-test:${springBootVersion}"
testCompile "org.springframework.boot:spring-boot-starter-web:${springBootVersion}"
testImplementation project(':bugsnag').sourceSets.test.output
testImplementation project(':bugsnag-spring:javax')
testImplementation project(':bugsnag')
testImplementation "junit:junit:${junitVersion}"
testImplementation "jakarta.servlet:jakarta.servlet-api:${jakartaServletApiVersion}"
testImplementation "org.springframework.boot:spring-boot-starter-test:${springBootVersion}"
testImplementation "org.springframework.boot:spring-boot-starter-web:${springBootVersion}"
testImplementation "org.mockito:mockito-core:${mockitoVersion}"
}

evaluationDependsOnChildren()

tasks['jar'].dependsOn(project(':bugsnag-spring:javax').tasks['jar'])

jar {
from project.sourceSets.main.allSource
from project(':bugsnag-spring:javax').configurations.archives.artifacts.files.collect { file ->
zipTree(file)
}
}
35 changes: 35 additions & 0 deletions bugsnag-spring/javax/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
ext {
springVersion = '5.3.20'
springBootVersion = '2.5.14'
}

apply plugin: 'java'
apply plugin: 'java-library'

apply from: '../../common.gradle'

compileJava {
sourceCompatibility = '1.8'
targetCompatibility = '1.8'
}

repositories {
mavenCentral()
}

dependencies {
api project(':bugsnag')
testImplementation project(':bugsnag').sourceSets.test.output

compileOnly "javax.servlet:javax.servlet-api:${javaxServletApiVersion}"
compileOnly "org.springframework:spring-webmvc:${springVersion}"
compileOnly "org.springframework.boot:spring-boot:${springBootVersion}"
compileOnly "ch.qos.logback:logback-core:${logbackVersion}"
compileOnly "org.slf4j:slf4j-api:${slf4jApiVersion}"

testImplementation "junit:junit:${junitVersion}"
testImplementation "javax.servlet:javax.servlet-api:${javaxServletApiVersion}"
testImplementation "org.springframework.boot:spring-boot-starter-test:${springBootVersion}"
testImplementation "org.springframework.boot:spring-boot-starter-web:${springBootVersion}"
testImplementation "org.mockito:mockito-core:${mockitoVersion}"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package com.bugsnag;

import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.SpringVersion;
import org.springframework.core.type.AnnotationMetadata;

public class BugsnagImportSelector implements ImportSelector {

private static final String[] SPRING_JAKARTA_CLASSES = {
"com.bugsnag.SpringBootJakartaConfiguration",
"com.bugsnag.JakartaMvcConfiguration",
"com.bugsnag.ScheduledTaskConfiguration"
};

private static final String[] SPRING_JAVAX_CLASSES = {
"com.bugsnag.SpringBootJavaxConfiguration",
"com.bugsnag.JavaxMvcConfiguration",
"com.bugsnag.ScheduledTaskConfiguration"
};

@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
if (isSpringJakartaCompatible() && isJava17Compatible()) {
return SPRING_JAKARTA_CLASSES;
}

return SPRING_JAVAX_CLASSES;
}

private static boolean isSpringJakartaCompatible() {
return getMajorVersion(SpringVersion.getVersion()) >= 6;
}

private static boolean isJava17Compatible() {
return getMajorVersion(System.getProperty("java.version")) >= 17;
}

private static int getMajorVersion(String version) {
if (version == null) {
return 0;
}
int firstDot = version.indexOf(".");
if (firstDot == -1) {
return 0;
}

String majorVersion = version.substring(0, firstDot);
try {
return Integer.parseInt(majorVersion);
} catch (NumberFormatException nfe) {
return 0;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import org.springframework.web.servlet.ModelAndView;

import java.util.Collections;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

Expand All @@ -20,11 +19,11 @@
* resolvers.
*/
@Order(Ordered.HIGHEST_PRECEDENCE)
class BugsnagMvcExceptionHandler implements HandlerExceptionResolver {
class BugsnagJavaxMvcExceptionHandler implements HandlerExceptionResolver {

private final Bugsnag bugsnag;

BugsnagMvcExceptionHandler(final Bugsnag bugsnag) {
BugsnagJavaxMvcExceptionHandler(final Bugsnag bugsnag) {
this.bugsnag = bugsnag;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,21 @@

import com.bugsnag.callbacks.Callback;

import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.core.SpringVersion;

import java.util.Map;
import javax.annotation.PostConstruct;

/**
* Configuration to integrate Bugsnag with Spring.
*/
@Configuration
@Import({
SpringBootConfiguration.class,
MvcConfiguration.class,
ScheduledTaskConfiguration.class})
public class BugsnagSpringConfiguration {
@Import(BugsnagImportSelector.class)
public class BugsnagSpringConfiguration implements InitializingBean {

@Autowired
private Bugsnag bugsnag;
Expand Down Expand Up @@ -64,9 +61,8 @@ ScheduledTaskBeanLocator scheduledTaskBeanLocator() {
* If using Logback, stop any configured appender from creating Bugsnag reports for Spring log
* messages as they effectively duplicate error reports for unhandled exceptions.
*/
@PostConstruct
@SuppressWarnings("checkstyle:emptycatchblock")
void excludeLoggers() {
@Override
public void afterPropertiesSet() {
try {
// Exclude Tomcat logger when processing HTTP requests via a servlet.
// Regex specified to match the servlet variable parts of the logger name, e.g.
Expand All @@ -86,5 +82,4 @@ void excludeLoggers() {
// logback was not in classpath, ignore throwable to allow further initialisation
}
}

}
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
package com.bugsnag;

import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;

import javax.annotation.PostConstruct;

/**
* If spring-webmvc is loaded, add configuration for reporting unhandled exceptions.
*/
@Configuration
@Conditional(SpringWebMvcLoadedCondition.class)
class MvcConfiguration {
class JavaxMvcConfiguration implements InitializingBean {

@Autowired
private Bugsnag bugsnag;
Expand All @@ -22,15 +21,15 @@ class MvcConfiguration {
* for uncaught exceptions thrown from request handlers.
*/
@Bean
BugsnagMvcExceptionHandler bugsnagHandlerExceptionResolver() {
return new BugsnagMvcExceptionHandler(bugsnag);
BugsnagJavaxMvcExceptionHandler bugsnagHandlerExceptionResolver() {
return new BugsnagJavaxMvcExceptionHandler(bugsnag);
}

/**
* Add a callback to assign specified severities for some Spring exceptions.
*/
@PostConstruct
void addExceptionClassCallback() {
@Override
public void afterPropertiesSet() {
bugsnag.addCallback(new ExceptionClassCallback());
}
}
Original file line number Diff line number Diff line change
@@ -1,25 +1,14 @@
package com.bugsnag;

import com.bugsnag.callbacks.Callback;
import com.bugsnag.servlet.BugsnagServletRequestListener;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringBootVersion;
import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;

import java.util.Map;
import javax.servlet.ServletRequestListener;

/**
* If spring-boot is loaded, add configuration specific to Spring Boot
*/
@Configuration
@Conditional(SpringBootLoadedCondition.class)
class SpringBootConfiguration {

public class SpringBootConfiguration {
@Autowired
private Bugsnag bugsnag;

Expand Down Expand Up @@ -53,19 +42,4 @@ public void beforeSendSession(SessionPayload payload) {
private void addSpringRuntimeVersion(Map<String, Object> device) {
Diagnostics.addDeviceRuntimeVersion(device, "springBoot", SpringBootVersion.getVersion());
}

/**
* The {@link com.bugsnag.servlet.BugsnagServletContainerInitializer} does not work for Spring Boot, need to
* register the {@link BugsnagServletRequestListener} using a Spring Boot
* {@link ServletListenerRegistrationBean} instead. This adds session tracking and
* automatic servlet request metadata collection.
*/
@Bean
@Conditional(SpringWebMvcLoadedCondition.class)
ServletListenerRegistrationBean<ServletRequestListener> listenerRegistrationBean() {
ServletListenerRegistrationBean<ServletRequestListener> srb =
new ServletListenerRegistrationBean<ServletRequestListener>();
srb.setListener(new BugsnagServletRequestListener());
return srb;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.bugsnag;

import com.bugsnag.servlet.javax.BugsnagServletRequestListener;

import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;

import javax.servlet.ServletRequestListener;

/**
* If spring-boot is loaded, add configuration specific to Spring Boot
*/
@Configuration
@Conditional(SpringBootLoadedCondition.class)
class SpringBootJavaxConfiguration extends SpringBootConfiguration {

/**
* The {@link com.bugsnag.servlet.javax.BugsnagServletContainerInitializer} does not work for Spring Boot, need to
* register the {@link BugsnagServletRequestListener} using a Spring Boot
* {@link ServletListenerRegistrationBean} instead. This adds session tracking and
* automatic servlet request metadata collection.
*/
@Bean
@Conditional(SpringWebMvcLoadedCondition.class)
ServletListenerRegistrationBean<ServletRequestListener> listenerRegistrationBean() {
ServletListenerRegistrationBean<ServletRequestListener> srb =
new ServletListenerRegistrationBean<ServletRequestListener>();
srb.setListener(new BugsnagServletRequestListener());
return srb;
}
}
Loading

0 comments on commit 5e06bce

Please sign in to comment.