Skip to content

Commit

Permalink
Release/v3.7.2 (#222)
Browse files Browse the repository at this point in the history
* (docs): update docs references from `master` to `main`

* (docs): switch build status badge to buildkite

* Update selector to accept only the major version

* Update Changelog

* update linting

* Added severity check (#214)

* added severity check

* fixed linting

* fixed linting v2

* added changelog entry

* Reverting changes

* update notify override with null check

* Update changelog

* Update Bugsnag.java

call notify override method on null severity

* add aopproxyutils dependancy and add handling in scheduledTaskConfig class (#218)

* add aopproxyutils dependancy and add handling in scheduledTaskConfig class

* fixed comment typo

* fixed import of aoputils

* added proxy testing

* fixed linting

* Updated tests

* updated tests

* update changelog

* moving createProxy method to util class

* update variable name

* reverting

* Update Serializer object to be an interface (#219)

* Adding non serializable metadata handling

* removed an unused import

* update feature

* update changelog

* Add serializeObject public method

* Fixed linting

* fixed tests

* Implemented Serializer interface

* update scenarios

* update changelog

* Changes based on feedback

* update tests

* updates based on reviews

* Update bugsnag/src/main/java/com/bugsnag/Configuration.java

Co-authored-by: Tom Longridge <[email protected]>

* update config

---------

Co-authored-by: Tom Longridge <[email protected]>

* v3.7.2

---------

Co-authored-by: Yousif Ahmed <[email protected]>
Co-authored-by: Yousif <[email protected]>
Co-authored-by: Tom Longridge <[email protected]>
  • Loading branch information
4 people authored Aug 29, 2024
1 parent 8cc7444 commit 8663402
Show file tree
Hide file tree
Showing 17 changed files with 177 additions and 49 deletions.
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,21 @@
# Changelog

## 3.7.2 (2024-08-28)

### Changed

* Add a null check for `Severity` to the notify override method. [#214](https://github.com/bugsnag/bugsnag-java/pull/214)

* Created Serializer interface, allowing for implementation of a custom serializer. [#219](https://github.com/bugsnag/bugsnag-java/pull/219)

* Updated ScheduleTaskConfiguration configureTask method to properly handle wrapped/proxied objects. [#218](https://github.com/bugsnag/bugsnag-java/pull/218)

### Bug Fixes

* Update `BugsnagImportSelector` to allow major versions that do not have a minor version.
fixes [issue #211](https://github.com/bugsnag/bugsnag-java/issues/211).
[#213](https://github.com/bugsnag/bugsnag-java/pull/213)

## 3.7.1 (2023-10-25)

* Restore `BugsnagServletContainerInitializer` and `BugsnagServletRequestListener` to the `com.bugsnag.servlet` package.
Expand Down
8 changes: 4 additions & 4 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,15 +122,15 @@ To start a release:
- `./gradlew -Preleasing=true clean publishAllPublicationsToSonatypeRepository`
- Verify that the artefacts are uploaded to sonatype - ensure that JARs, POMs and JAVADOCs are present for each module.
- Test the Sonatype artefacts in the example app by adding the newly created 'combugsnag-XXXX' repository to the build.gradle: maven {url "https://oss.sonatype.org/service/local/repositories/combugsnag-XXXX/content/"}
- Once you are happy, make a PR from your release branch to `master` entitled `Release vX.Y.Z`
- Once you are happy, make a PR from your release branch to `main` entitled `Release vX.Y.Z`
- Get the release PR reviewed – all code changes should have been reviewed already, this should be a review of the integration of all changes to be shipped and the changelog
- Once merged:
- Pull the latest changes (checking out `master` if necessary)
- Pull the latest changes (checking out `main` if necessary)
- Create a release build and upload to sonatype:
- `./gradlew -Preleasing=true clean publishAllPublicationsToSonatypeRepository`
- Release to GitHub:
- [ ] Create *and tag* the release from `master` on [GitHub Releases](https://github.com/bugsnag/bugsnag-android/releases), attaching the changelog entry and build artifacts
- Checkout `master` and pull the latest changes
- [ ] Create *and tag* the release from `main` on [GitHub Releases](https://github.com/bugsnag/bugsnag-android/releases), attaching the changelog entry and build artifacts
- Checkout `main` and pull the latest changes
- "Promote" the release build on Maven Central:
- Go to the [sonatype open source dashboard](https://oss.sonatype.org/index.html#stagingRepositories)
- Click the search box at the top right, and type “com.bugsnag”
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Bugsnag exception reporter for Java
[![Documentation](https://img.shields.io/badge/docs-latest-blue.svg)](https://docs.bugsnag.com/platforms/java)
[![Build status](https://travis-ci.org/bugsnag/bugsnag-java.svg?branch=master)](https://travis-ci.org/bugsnag/bugsnag-java)
[![Build status](https://badge.buildkite.com/de087a23152718c7d33b0ae7f566a940a92fb9d92becdb61a3.svg?branch=main)](https://buildkite.com/bugsnag/bugsnag-java)

The Bugsnag exception reporter for Java automatically detects and reports errors and exceptions in your Java code. Learn more about [reporting Java exceptions](https://www.bugsnag.com/platforms/java/) with Bugsnag.

Expand Down Expand Up @@ -35,7 +35,7 @@ The Bugsnag exception reporter for Java automatically detects and reports errors
## Contributing

All contributors are welcome! For information on how to build, test, and release
`bugsnag-java`, see our [contributing guide](https://github.com/bugsnag/bugsnag-java/blob/master/CONTRIBUTING.md).
`bugsnag-java`, see our [contributing guide](https://github.com/bugsnag/bugsnag-java/blob/main/CONTRIBUTING.md).

## License

Expand Down
9 changes: 7 additions & 2 deletions bugsnag-spring/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -134,27 +134,32 @@ dependencies {
compileJavax "javax.servlet:javax.servlet-api:${javaxServletApiVersion}"
compileJavax "org.springframework:spring-webmvc:${javaxSpringVersion}"
compileJavax "org.springframework.boot:spring-boot:${javaxSpringBootVersion}"
compileJavax "org.springframework:spring-aop:${javaxSpringVersion}"

compileJakarta "jakarta.servlet:jakarta.servlet-api:${jakartaServletApiVersion}"
compileJakarta "org.springframework:spring-webmvc:${jakartaSpringVersion}"
compileJakarta "org.springframework.boot:spring-boot:${jakartaSpringBootVersion}"
compileJakarta "org.springframework:spring-aop:${jakartaSpringVersion}"


commonTestImplementation project(':bugsnag').sourceSets.test.output
commonTestImplementation project(':bugsnag')

commonTestImplementation "junit:junit:${junitVersion}"

commonTestCompileOnly "org.mockito:mockito-core:2.10.0"

jakartaTestImplementation "org.mockito:mockito-core:${mockitoVersion}"
jakartaTestImplementation "jakarta.servlet:jakarta.servlet-api:${jakartaServletApiVersion}"
jakartaTestImplementation "org.springframework.boot:spring-boot-starter-test:${jakartaSpringBootVersion}"
jakartaTestImplementation "org.springframework.boot:spring-boot-starter-web:${jakartaSpringBootVersion}"
jakartaTestImplementation "org.springframework:spring-aop:${jakartaSpringVersion}"

javaxTestImplementation "org.mockito:mockito-core:2.10.0"
javaxTestImplementation "javax.servlet:javax.servlet-api:${javaxServletApiVersion}"
javaxTestImplementation "org.springframework.boot:spring-boot-starter-test:${javaxSpringBootVersion}"
javaxTestImplementation "org.springframework.boot:spring-boot-starter-web:${javaxSpringBootVersion}"
javaxTestImplementation "org.springframework:spring-aop:${javaxSpringVersion}"
}

dependencies {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,14 @@ private static int getMajorVersion(String version) {
return 0;
}
int firstDot = version.indexOf(".");
String majorVersion;

if (firstDot == -1) {
return 0;
majorVersion = version;
} else {
majorVersion = version.substring(0, firstDot);
}

String majorVersion = version.substring(0, firstDot);
try {
return Integer.parseInt(majorVersion);
} catch (NumberFormatException nfe) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.framework.AopProxyUtils;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.concurrent.ConcurrentTaskScheduler;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;

import org.springframework.util.ErrorHandler;

import java.lang.reflect.Field;
Expand Down Expand Up @@ -49,10 +52,17 @@ public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
? registrarScheduler : beanLocator.resolveTaskScheduler();

if (taskScheduler != null) {
//check if taskSchedular is a proxy
if (AopUtils.isAopProxy(taskScheduler)) {
//if it's a proxy then get the target class and cast as necessary
Class<?> targetClass = AopProxyUtils.ultimateTargetClass(taskScheduler);
if (TaskScheduler.class.isAssignableFrom(targetClass)) {
taskScheduler = (TaskScheduler) AopProxyUtils.getSingletonTarget(taskScheduler);
}
}
configureExistingTaskScheduler(taskScheduler, bugsnagErrorHandler);
} else {
ScheduledExecutorService executorService
= beanLocator.resolveScheduledExecutorService();
ScheduledExecutorService executorService = beanLocator.resolveScheduledExecutorService();
taskScheduler = createNewTaskScheduler(executorService, bugsnagErrorHandler);
taskRegistrar.setScheduler(taskScheduler);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,18 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.mockito.Mockito.when;

import com.bugsnag.testapp.springboot.TestSpringBootApplication;

import org.aopalliance.intercept.MethodInterceptor;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;

import org.mockito.Mock;

import org.springframework.aop.framework.ProxyFactory;
import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
Expand Down Expand Up @@ -113,6 +115,31 @@ public void findExecutorByName() throws NoSuchFieldException, IllegalAccessExcep
assertEquals(expected, accessField(scheduler, "scheduledExecutor"));
}

@Test
public void configureTasks_withProxyWrappedRegistrar() throws NoSuchFieldException, IllegalAccessException {
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
when(context.getBean(TaskScheduler.class)).thenReturn(scheduler);
TaskScheduler proxyScheduler = createProxy(scheduler);
registrar.setScheduler(proxyScheduler);
Object errorHandler = accessField(scheduler, "errorHandler");
assertFalse(
errorHandler instanceof BugsnagScheduledTaskExceptionHandler,
"errorHandler should not be BugsnagScheduledTaskExceptionHandler"
);
configuration.configureTasks(registrar);
errorHandler = accessField(scheduler, "errorHandler");
assertTrue(
"errorHandler should be BugsnagScheduledTaskExceptionHandler",
errorHandler instanceof BugsnagScheduledTaskExceptionHandler
);
}

private TaskScheduler createProxy(TaskScheduler target) {
ProxyFactory factory = new ProxyFactory(target);
factory.addAdvice((MethodInterceptor) invocation -> invocation.proceed());
return (TaskScheduler) factory.getProxy();
}

private Object accessField(Object object, String fieldName)
throws NoSuchFieldException, IllegalAccessException {
Field field = object.getClass().getDeclaredField(fieldName);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,17 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.mockito.Mockito.when;

import com.bugsnag.testapp.springboot.TestSpringBootApplication;

import org.aopalliance.intercept.MethodInterceptor;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
Expand Down Expand Up @@ -111,6 +114,31 @@ public void findExecutorByName() throws NoSuchFieldException, IllegalAccessExcep
assertEquals(expected, accessField(scheduler, "scheduledExecutor"));
}

@Test
public void configureTasks_withProxyWrappedRegistrar() throws NoSuchFieldException, IllegalAccessException {
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
when(context.getBean(TaskScheduler.class)).thenReturn(scheduler);
TaskScheduler proxyScheduler = createProxy(scheduler);
registrar.setScheduler(proxyScheduler);
Object errorHandler = accessField(scheduler, "errorHandler");
assertFalse(
errorHandler instanceof BugsnagScheduledTaskExceptionHandler,
"errorHandler should not be BugsnagScheduledTaskExceptionHandler"
);
configuration.configureTasks(registrar);
errorHandler = accessField(scheduler, "errorHandler");
assertTrue(
"errorHandler should be BugsnagScheduledTaskExceptionHandler",
errorHandler instanceof BugsnagScheduledTaskExceptionHandler
);
}

private TaskScheduler createProxy(TaskScheduler target) {
ProxyFactory factory = new ProxyFactory(target);
factory.addAdvice((MethodInterceptor) invocation -> invocation.proceed());
return (TaskScheduler) factory.getProxy();
}

private Object accessField(Object object, String fieldName)
throws NoSuchFieldException, IllegalAccessException {
Field field = object.getClass().getDeclaredField(fieldName);
Expand Down
3 changes: 3 additions & 0 deletions bugsnag/src/main/java/com/bugsnag/Bugsnag.java
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,9 @@ public boolean notify(Throwable throwable, Severity severity, Callback callback)
LOGGER.warn("Tried to notify with a null Throwable");
return false;
}
if (severity == null) {
return notify(throwable, callback);
}

HandledState handledState = HandledState.newInstance(
HandledState.SeverityReasonType.REASON_USER_SPECIFIED, severity);
Expand Down
4 changes: 2 additions & 2 deletions bugsnag/src/main/java/com/bugsnag/Configuration.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import com.bugsnag.delivery.Delivery;
import com.bugsnag.delivery.HttpDelivery;
import com.bugsnag.delivery.SyncHttpDelivery;
import com.bugsnag.serialization.DefaultSerializer;
import com.bugsnag.serialization.Serializer;

import org.slf4j.Logger;
Expand Down Expand Up @@ -44,15 +45,14 @@ public class Configuration {
public String[] projectPackages;
public String releaseStage;
public boolean sendThreads = false;
public Serializer serializer = new DefaultSerializer();

Collection<Callback> callbacks = new ConcurrentLinkedQueue<Callback>();
Serializer serializer = new Serializer();
private final AtomicBoolean autoCaptureSessions = new AtomicBoolean(true);
private final AtomicBoolean sendUncaughtExceptions = new AtomicBoolean(true);

Configuration(String apiKey) {
this.apiKey = apiKey;

// Add built-in callbacks
addCallback(new AppCallback(this));
addCallback(new DeviceCallback());
Expand Down
2 changes: 1 addition & 1 deletion bugsnag/src/main/java/com/bugsnag/Notifier.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
class Notifier {

private static final String NOTIFIER_NAME = "Bugsnag Java";
private static final String NOTIFIER_VERSION = "3.7.1";
private static final String NOTIFIER_VERSION = "3.7.2";
private static final String NOTIFIER_URL = "https://github.com/bugsnag/bugsnag-java";

private String notifierName = NOTIFIER_NAME;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.bugsnag.serialization;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.IOException;
import java.io.OutputStream;

public class DefaultSerializer implements Serializer {
private ObjectMapper mapper = new ObjectMapper();

/**
* Constructor.
*/
// Use deprecated method to ensure we don't break with older versions of jackson
@SuppressWarnings("deprecation")
public DefaultSerializer() {
mapper
.setSerializationInclusion(JsonInclude.Include.NON_EMPTY)
.setVisibilityChecker(
mapper.getVisibilityChecker().with(JsonAutoDetect.Visibility.NONE));
}

@Override
public void writeToStream(OutputStream stream, Object object) throws SerializationException {
try {
mapper.writeValue(stream, object);
} catch (IOException ex) {
throw new SerializationException("Exception during serialization", ex);
}
}
}
34 changes: 6 additions & 28 deletions bugsnag/src/main/java/com/bugsnag/serialization/Serializer.java
Original file line number Diff line number Diff line change
@@ -1,39 +1,17 @@
package com.bugsnag.serialization;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.IOException;
import java.io.OutputStream;

public class Serializer {
private ObjectMapper mapper = new ObjectMapper();

/**
* Constructor.
*/
// Use deprecated method to ensure we don't break with older versions of jackson
@SuppressWarnings("deprecation")
public Serializer() {
mapper
.setSerializationInclusion(JsonInclude.Include.NON_EMPTY)
.setVisibilityChecker(
mapper.getVisibilityChecker().with(JsonAutoDetect.Visibility.NONE));
}

/**
* The Serializer is called to generate the JSON for an object to be added as metadata to a Bugsnag event.
*/
public interface Serializer {
/**
* Write the object to the stream.
* Write the specified object to the provided stream to be used on metadata for a Bugsnag event.
*
* @param stream the stream to write the object to.
* @param object the object to write to the stream.
* @throws SerializationException the object could not be serialized.
*/
public void writeToStream(OutputStream stream, Object object) throws SerializationException {
try {
mapper.writeValue(stream, object);
} catch (IOException ex) {
throw new SerializationException("Exception during serialization", ex);
}
}
void writeToStream(OutputStream stream, Object object) throws SerializationException;
}
Loading

0 comments on commit 8663402

Please sign in to comment.