Skip to content

Commit 0173186

Browse files
committed
GH-2953: Add NullAway support into the project
Fixes: #2953 * Migrate nullability to JSpecify * Add `net.ltgt.errorprone` Gradle plugin and respective `NullAway` configuration * Remove redundant `com.github.spotbugs` since it covered now by the `net.ltgt.errorprone` tool * Use Java `23` for the latest fixes on Java nullability * Fix JavaDocs and `this-escape` warnings in the code * Use `main` for reusable workflows which come already with Java `23` * Fix all the nullability problems in the project
1 parent d84f727 commit 0173186

File tree

273 files changed

+3257
-3171
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

273 files changed

+3257
-3171
lines changed

.github/dependabot.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ updates:
1919
- patch
2020
patterns:
2121
- com.gradle.*
22-
- com.github.spotbugs
2322
- io.spring.*
2423
- org.ajoberstar.grgit
2524
- org.antora
@@ -28,6 +27,9 @@ updates:
2827
- org.hibernate.validator:hibernate-validator
2928
- org.apache.httpcomponents.client5:httpclient5
3029
- org.awaitility:awaitility
30+
- net.ltgt.errorprone
31+
- com.uber.nullaway*
32+
- com.google.errorprone*
3133

3234
- package-ecosystem: github-actions
3335
directory: /

.github/workflows/pr-build.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,4 @@ on:
88

99
jobs:
1010
build-pull-request:
11-
uses: spring-io/spring-github-workflows/.github/workflows/spring-gradle-pull-request-build.yml@v5
11+
uses: spring-io/spring-github-workflows/.github/workflows/spring-gradle-pull-request-build.yml@main

.github/workflows/release.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ jobs:
1212
contents: write
1313
issues: write
1414

15-
uses: spring-io/spring-github-workflows/.github/workflows/spring-artifactory-gradle-release.yml@v5
15+
uses: spring-io/spring-github-workflows/.github/workflows/spring-artifactory-gradle-release.yml@main
16+
with:
17+
deployMilestoneToCentral: true
1618
secrets:
1719
GH_ACTIONS_REPO_TOKEN: ${{ secrets.GH_ACTIONS_REPO_TOKEN }}
1820
DEVELOCITY_ACCESS_KEY: ${{ secrets.DEVELOCITY_ACCESS_KEY }}

build.gradle

Lines changed: 32 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ plugins {
1919
id 'io.spring.dependency-management' version '1.1.7' apply false
2020
id 'org.antora' version '1.0.0'
2121
id 'io.spring.antora.generate-antora-yml' version '0.0.1'
22-
id 'com.github.spotbugs' version '6.1.3'
2322
id 'io.freefair.aggregate-javadoc' version '8.11'
23+
id 'net.ltgt.errorprone' version '4.1.0' apply false
2424
}
2525

2626
description = 'Spring AMQP'
@@ -73,12 +73,12 @@ ext {
7373
antora {
7474
version = '3.2.0-alpha.2'
7575
playbook = file('src/reference/antora/antora-playbook.yml')
76-
options = ['to-dir' : project.layout.buildDirectory.dir('site').get().toString(), clean: true, fetch: !project.gradle.startParameter.offline, stacktrace: true]
76+
options = ['to-dir': project.layout.buildDirectory.dir('site').get().toString(), clean: true, fetch: !project.gradle.startParameter.offline, stacktrace: true]
7777
dependencies = [
78-
'@antora/atlas-extension': '1.0.0-alpha.2',
79-
'@antora/collector-extension': '1.0.0-beta.3',
80-
'@asciidoctor/tabs': '1.0.0-beta.6',
81-
'@springio/antora-extensions': '1.14.2',
78+
'@antora/atlas-extension' : '1.0.0-alpha.2',
79+
'@antora/collector-extension' : '1.0.0-beta.3',
80+
'@asciidoctor/tabs' : '1.0.0-beta.6',
81+
'@springio/antora-extensions' : '1.14.2',
8282
'@springio/asciidoctor-extensions': '1.0.0-alpha.14',
8383
]
8484
}
@@ -158,25 +158,42 @@ configure(javaProjects) { subproject ->
158158
apply plugin: 'checkstyle'
159159
apply plugin: 'kotlin'
160160
apply plugin: 'kotlin-spring'
161+
apply plugin: 'net.ltgt.errorprone'
161162

162163
apply from: "${rootProject.projectDir}/gradle/publish-maven.gradle"
163164

164165
java {
166+
toolchain {
167+
languageVersion = JavaLanguageVersion.of(23)
168+
}
165169
withJavadocJar()
166170
withSourcesJar()
167171
registerFeature('optional') {
168172
usingSourceSet(sourceSets.main)
169173
}
170174
}
171175

172-
compileJava {
173-
options.release = 17
174-
}
175-
176-
compileTestJava {
176+
tasks.withType(JavaCompile) {
177177
sourceCompatibility = JavaVersion.VERSION_17
178-
targetCompatibility = JavaVersion.VERSION_17
179178
options.encoding = 'UTF-8'
179+
options.errorprone {
180+
disableAllChecks = true
181+
if (!name.toLowerCase().contains('test')) {
182+
option('NullAway:OnlyNullMarked', 'true')
183+
option('NullAway:CustomContractAnnotations', 'org.springframework.lang.Contract')
184+
option('NullAway:JSpecifyMode', 'true')
185+
error('NullAway')
186+
}
187+
}
188+
}
189+
190+
compileTestKotlin {
191+
kotlinOptions {
192+
jvmTarget = JavaVersion.VERSION_17
193+
}
194+
compilerOptions {
195+
allWarningsAsErrors = true
196+
}
180197
}
181198

182199
eclipse {
@@ -187,10 +204,6 @@ configure(javaProjects) { subproject ->
187204

188205
// dependencies that are common across all java projects
189206
dependencies {
190-
def spotbugsAnnotations = "com.github.spotbugs:spotbugs-annotations:${spotbugs.toolVersion.get()}"
191-
compileOnly spotbugsAnnotations
192-
testCompileOnly spotbugsAnnotations
193-
194207
testImplementation 'org.apache.logging.log4j:log4j-core'
195208
testImplementation "org.hamcrest:hamcrest-core:$hamcrestVersion"
196209
testImplementation("org.mockito:mockito-core:$mockitoVersion") {
@@ -211,6 +224,9 @@ configure(javaProjects) { subproject ->
211224

212225
testImplementation 'org.jetbrains.kotlin:kotlin-reflect'
213226
testImplementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8'
227+
228+
errorprone 'com.uber.nullaway:nullaway:0.12.3'
229+
errorprone 'com.google.errorprone:error_prone_core:2.36.0'
214230
}
215231

216232
// enable all compiler warnings; individual projects may customize further
@@ -430,12 +446,6 @@ project('spring-rabbit') {
430446
exclude group: 'org.hamcrest', module: 'hamcrest-core'
431447
}
432448
}
433-
434-
compileKotlin {
435-
compilerOptions {
436-
allWarningsAsErrors = true
437-
}
438-
}
439449
}
440450

441451
project('spring-rabbit-stream') {

spring-amqp/src/main/java/org/springframework/amqp/AmqpException.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2019 the original author or authors.
2+
* Copyright 2002-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,10 +16,13 @@
1616

1717
package org.springframework.amqp;
1818

19+
import org.jspecify.annotations.Nullable;
20+
1921
/**
2022
* Base RuntimeException for errors that occur when executing AMQP operations.
2123
*
2224
* @author Mark Fisher
25+
* @author Artem Bilan
2326
*/
2427
@SuppressWarnings("serial")
2528
public class AmqpException extends RuntimeException {
@@ -28,11 +31,11 @@ public AmqpException(String message) {
2831
super(message);
2932
}
3033

31-
public AmqpException(Throwable cause) {
34+
public AmqpException(@Nullable Throwable cause) {
3235
super(cause);
3336
}
3437

35-
public AmqpException(String message, Throwable cause) {
38+
public AmqpException(@Nullable String message, @Nullable Throwable cause) {
3639
super(message, cause);
3740
}
3841

spring-amqp/src/main/java/org/springframework/amqp/AmqpRejectAndDontRequeueException.java

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2019 the original author or authors.
2+
* Copyright 2002-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,13 +16,16 @@
1616

1717
package org.springframework.amqp;
1818

19-
import org.springframework.lang.Nullable;
19+
import org.jspecify.annotations.Nullable;
2020

2121
/**
2222
* Exception for listener implementations used to indicate the
23-
* basic.reject will be sent with requeue=false in order to enable
24-
* features such as DLQ.
23+
* {@code basic.reject} will be sent with {@code requeue=false}
24+
* in order to enable features such as DLQ.
25+
*
2526
* @author Gary Russell
27+
* @author Artem Bilan
28+
*
2629
* @since 1.0.1
2730
*
2831
*/

spring-amqp/src/main/java/org/springframework/amqp/UncategorizedAmqpException.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2019 the original author or authors.
2+
* Copyright 2002-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,6 +16,8 @@
1616

1717
package org.springframework.amqp;
1818

19+
import org.jspecify.annotations.Nullable;
20+
1921
/**
2022
* A "catch-all" exception type within the AmqpException hierarchy
2123
* when no more specific cause is known.
@@ -25,7 +27,7 @@
2527
@SuppressWarnings("serial")
2628
public class UncategorizedAmqpException extends AmqpException {
2729

28-
public UncategorizedAmqpException(Throwable cause) {
30+
public UncategorizedAmqpException(@Nullable Throwable cause) {
2931
super(cause);
3032
}
3133

spring-amqp/src/main/java/org/springframework/amqp/core/AbstractBuilder.java

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2016-2024 the original author or authors.
2+
* Copyright 2016-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -19,30 +19,34 @@
1919
import java.util.LinkedHashMap;
2020
import java.util.Map;
2121

22+
import org.jspecify.annotations.Nullable;
23+
2224
/**
2325
* Base class for builders supporting arguments.
2426
*
2527
* @author Gary Russell
2628
* @author Ngoc Nhan
29+
* @author Artem Bilan
30+
*
2731
* @since 1.6
2832
*
2933
*/
3034
public abstract class AbstractBuilder {
3135

32-
private Map<String, Object> arguments;
36+
private @Nullable Map<String, @Nullable Object> arguments;
3337

3438
/**
3539
* Return the arguments map, after creating one if necessary.
3640
* @return the arguments.
3741
*/
38-
protected Map<String, Object> getOrCreateArguments() {
42+
protected Map<String, @Nullable Object> getOrCreateArguments() {
3943
if (this.arguments == null) {
4044
this.arguments = new LinkedHashMap<>();
4145
}
4246
return this.arguments;
4347
}
4448

45-
protected Map<String, Object> getArguments() {
49+
protected @Nullable Map<String, @Nullable Object> getArguments() {
4650
return this.arguments;
4751
}
4852

spring-amqp/src/main/java/org/springframework/amqp/core/AbstractDeclarable.java

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2024 the original author or authors.
2+
* Copyright 2002-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -25,7 +25,8 @@
2525
import java.util.concurrent.locks.Lock;
2626
import java.util.concurrent.locks.ReentrantLock;
2727

28-
import org.springframework.lang.Nullable;
28+
import org.jspecify.annotations.Nullable;
29+
2930
import org.springframework.util.Assert;
3031

3132
/**
@@ -41,7 +42,7 @@ public abstract class AbstractDeclarable implements Declarable {
4142

4243
private final Lock lock = new ReentrantLock();
4344

44-
private final Map<String, Object> arguments;
45+
protected final Map<String, Object> arguments;
4546

4647
private boolean shouldDeclare = true;
4748

@@ -58,7 +59,7 @@ public AbstractDeclarable() {
5859
* @param arguments the arguments.
5960
* @since 2.2.2
6061
*/
61-
public AbstractDeclarable(@Nullable Map<String, Object> arguments) {
62+
public AbstractDeclarable(@Nullable Map<String, @Nullable Object> arguments) {
6263
if (arguments != null) {
6364
this.arguments = new HashMap<>(arguments);
6465
}
@@ -101,7 +102,8 @@ public void setIgnoreDeclarationExceptions(boolean ignoreDeclarationExceptions)
101102
}
102103

103104
@Override
104-
public void setAdminsThatShouldDeclare(@Nullable Object... adminArgs) {
105+
@SuppressWarnings("NullAway") // Dataflow analysis limitation
106+
public void setAdminsThatShouldDeclare(@Nullable Object @Nullable ... adminArgs) {
105107
Collection<Object> admins = new ArrayList<>();
106108
if (adminArgs != null) {
107109
if (adminArgs.length > 1) {

spring-amqp/src/main/java/org/springframework/amqp/core/AbstractExchange.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2019 the original author or authors.
2+
* Copyright 2002-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -18,6 +18,7 @@
1818

1919
import java.util.Map;
2020

21+
import org.jspecify.annotations.Nullable;
2122

2223
/**
2324
* Common properties that describe all exchange types.
@@ -71,7 +72,9 @@ public AbstractExchange(String name, boolean durable, boolean autoDelete) {
7172
* longer in use
7273
* @param arguments the arguments used to declare the exchange
7374
*/
74-
public AbstractExchange(String name, boolean durable, boolean autoDelete, Map<String, Object> arguments) {
75+
public AbstractExchange(String name, boolean durable, boolean autoDelete,
76+
@Nullable Map<String, @Nullable Object> arguments) {
77+
7578
super(arguments);
7679
this.name = name;
7780
this.durable = durable;

0 commit comments

Comments
 (0)