Skip to content

Commit 2fbbbb9

Browse files
committed
GH-10083: Apply Nullability to spring-integration-mail
Related to: #10083 Signed-off-by: Jiandong Ma <[email protected]>
1 parent d63dd26 commit 2fbbbb9

19 files changed

+109
-66
lines changed

spring-integration-mail/src/main/java/org/springframework/integration/mail/AbstractMailReceiver.java

Lines changed: 20 additions & 14 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.
@@ -40,6 +40,7 @@
4040
import jakarta.mail.Store;
4141
import jakarta.mail.URLName;
4242
import jakarta.mail.internet.MimeMessage;
43+
import org.jspecify.annotations.Nullable;
4344

4445
import org.springframework.beans.factory.DisposableBean;
4546
import org.springframework.expression.Expression;
@@ -78,18 +79,19 @@ public abstract class AbstractMailReceiver extends IntegrationObjectSupport impl
7879
*/
7980
public static final String DEFAULT_SI_USER_FLAG = "spring-integration-mail-adapter";
8081

81-
private final URLName url;
82+
private final @Nullable URLName url;
8283

8384
private final ReentrantReadWriteLock folderLock = new ReentrantReadWriteLock();
8485

8586
private final Lock folderReadLock = this.folderLock.readLock();
8687

8788
private final Lock folderWriteLock = this.folderLock.writeLock();
8889

89-
private String protocol;
90+
private @Nullable String protocol;
9091

9192
private int maxFetchSize = -1;
9293

94+
@SuppressWarnings("NullAway.Init")
9395
private Session session;
9496

9597
private boolean shouldDeleteMessages;
@@ -98,13 +100,14 @@ public abstract class AbstractMailReceiver extends IntegrationObjectSupport impl
98100

99101
private Properties javaMailProperties = new Properties();
100102

101-
private Authenticator javaMailAuthenticator;
103+
private @Nullable Authenticator javaMailAuthenticator;
102104

105+
@SuppressWarnings("NullAway.Init")
103106
private StandardEvaluationContext evaluationContext;
104107

105-
private Expression selectorExpression;
108+
private @Nullable Expression selectorExpression;
106109

107-
private HeaderMapper<MimeMessage> headerMapper;
110+
private @Nullable HeaderMapper<MimeMessage> headerMapper;
108111

109112
private String userFlag = DEFAULT_SI_USER_FLAG;
110113

@@ -116,8 +119,10 @@ public abstract class AbstractMailReceiver extends IntegrationObjectSupport impl
116119

117120
private boolean flaggedAsFallback = true;
118121

122+
@SuppressWarnings("NullAway.Init")
119123
private volatile Store store;
120124

125+
@SuppressWarnings("NullAway.Init")
121126
private volatile Folder folder;
122127

123128
public AbstractMailReceiver() {
@@ -129,7 +134,7 @@ public AbstractMailReceiver(URLName urlName) {
129134
this.url = urlName;
130135
}
131136

132-
public AbstractMailReceiver(String url) {
137+
public AbstractMailReceiver(@Nullable String url) {
133138
if (url != null) {
134139
this.url = new URLName(url);
135140
}
@@ -138,7 +143,7 @@ public AbstractMailReceiver(String url) {
138143
}
139144
}
140145

141-
public void setSelectorExpression(Expression selectorExpression) {
146+
public void setSelectorExpression(@Nullable Expression selectorExpression) {
142147
this.selectorExpression = selectorExpression;
143148
}
144149

@@ -359,7 +364,8 @@ protected void openFolder() throws MessagingException {
359364
connectStoreIfNecessary();
360365
}
361366
if (this.folder == null || !this.folder.exists()) {
362-
throw new IllegalStateException("no such folder [" + this.url.getFile() + "]");
367+
String file = this.url != null ? this.url.getFile() : "";
368+
throw new IllegalStateException("no such folder [" + file + "]");
363369
}
364370
if (this.folder.isOpen()) {
365371
return;
@@ -637,8 +643,8 @@ public void destroy() {
637643
try {
638644
closeFolder();
639645
MailTransportUtils.closeService(this.store);
640-
this.folder = null;
641-
this.store = null;
646+
// this.folder = null;
647+
// this.store = null;
642648
}
643649
finally {
644650
this.folderWriteLock.unlock();
@@ -654,7 +660,7 @@ protected void onInit() {
654660

655661
@Override
656662
public String toString() {
657-
return this.url.toString();
663+
return this.url != null ? this.toString() : "url not given";
658664
}
659665

660666
Store getStore() {
@@ -674,7 +680,7 @@ private final class IntegrationMimeMessage extends MimeMessage {
674680

675681
private final MimeMessage source;
676682

677-
private final Object content;
683+
private final @Nullable Object content;
678684

679685
IntegrationMimeMessage(MimeMessage source) throws MessagingException {
680686
super(source);
@@ -727,7 +733,7 @@ public int getLineCount() throws MessagingException {
727733
}
728734

729735
@Override
730-
public Object getContent() throws IOException, MessagingException {
736+
public @Nullable Object getContent() throws IOException, MessagingException {
731737
if (AbstractMailReceiver.this.simpleContent) {
732738
return super.getContent();
733739
}

spring-integration-mail/src/main/java/org/springframework/integration/mail/ImapIdleChannelAdapter.java

Lines changed: 10 additions & 6 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.
@@ -24,6 +24,7 @@
2424
import jakarta.mail.Folder;
2525
import jakarta.mail.Message;
2626
import org.aopalliance.aop.Advice;
27+
import org.jspecify.annotations.Nullable;
2728

2829
import org.springframework.aop.framework.ProxyFactory;
2930
import org.springframework.beans.factory.BeanClassLoaderAware;
@@ -35,7 +36,6 @@
3536
import org.springframework.integration.transaction.IntegrationResourceHolder;
3637
import org.springframework.integration.transaction.IntegrationResourceHolderSynchronization;
3738
import org.springframework.integration.transaction.TransactionSynchronizationFactory;
38-
import org.springframework.lang.Nullable;
3939
import org.springframework.messaging.MessagingException;
4040
import org.springframework.transaction.support.TransactionSynchronization;
4141
import org.springframework.transaction.support.TransactionSynchronizationManager;
@@ -62,18 +62,22 @@ public class ImapIdleChannelAdapter extends MessageProducerSupport implements Be
6262

6363
private final ImapMailReceiver mailReceiver;
6464

65+
@SuppressWarnings("NullAway.Init")
6566
private Executor taskExecutor;
6667

67-
private TransactionSynchronizationFactory transactionSynchronizationFactory;
68+
private @Nullable TransactionSynchronizationFactory transactionSynchronizationFactory;
6869

70+
@SuppressWarnings("NullAway.Init")
6971
private ClassLoader classLoader;
7072

73+
@SuppressWarnings("NullAway.Init")
7174
private ApplicationEventPublisher applicationEventPublisher;
7275

7376
private boolean shouldReconnectAutomatically = true;
7477

75-
private List<Advice> adviceChain;
78+
private @Nullable List<Advice> adviceChain;
7679

80+
@SuppressWarnings("NullAway.Init")
7781
private Consumer<Object> messageSender;
7882

7983
private long reconnectDelay = DEFAULT_RECONNECT_DELAY; // milliseconds
@@ -252,8 +256,8 @@ private void delayNextIdleCall() {
252256
}
253257
}
254258

255-
@Nullable
256-
private static jakarta.mail.MessagingException getJakartaMailMessagingExceptionFromCause(Throwable cause) {
259+
@SuppressWarnings("NullAway")
260+
private static jakarta.mail.MessagingException getJakartaMailMessagingExceptionFromCause(@Nullable Throwable cause) {
257261
if (cause == null) {
258262
return null;
259263
}

spring-integration-mail/src/main/java/org/springframework/integration/mail/ImapMailReceiver.java

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import jakarta.mail.search.NotTerm;
3434
import jakarta.mail.search.SearchTerm;
3535
import org.eclipse.angus.mail.imap.IMAPFolder;
36+
import org.jspecify.annotations.Nullable;
3637

3738
import org.springframework.scheduling.TaskScheduler;
3839
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
@@ -67,19 +68,20 @@ public class ImapMailReceiver extends AbstractMailReceiver {
6768

6869
private long cancelIdleInterval = DEFAULT_CANCEL_IDLE_INTERVAL;
6970

71+
@SuppressWarnings("NullAway.Init")
7072
private TaskScheduler scheduler;
7173

7274
private boolean isInternalScheduler;
7375

74-
private volatile ScheduledFuture<?> pingTask;
76+
private volatile @Nullable ScheduledFuture<?> pingTask;
7577

7678
@SuppressWarnings("this-escape")
7779
public ImapMailReceiver() {
7880
setProtocol(PROTOCOL);
7981
}
8082

8183
@SuppressWarnings("this-escape")
82-
public ImapMailReceiver(String url) {
84+
public ImapMailReceiver(@Nullable String url) {
8385
super(url);
8486
if (url != null) {
8587
Assert.isTrue(url.toLowerCase(Locale.ROOT).startsWith(PROTOCOL),
@@ -238,7 +240,7 @@ private Message[] nullSafeMessages(Message[] messageArray) {
238240
}
239241
}
240242

241-
private SearchTerm compileSearchTerms(Flags supportedFlags) {
243+
private @Nullable SearchTerm compileSearchTerms(Flags supportedFlags) {
242244
return this.searchTermStrategy.generateSearchTerm(supportedFlags, this.getFolder());
243245
}
244246

@@ -277,7 +279,7 @@ private class DefaultSearchTermStrategy implements SearchTermStrategy {
277279
}
278280

279281
@Override
280-
public SearchTerm generateSearchTerm(Flags supportedFlags, Folder folder) {
282+
public @Nullable SearchTerm generateSearchTerm(Flags supportedFlags, Folder folder) {
281283
SearchTerm searchTerm = null;
282284
boolean recentFlagSupported = false;
283285
if (supportedFlags != null) {
@@ -320,7 +322,7 @@ public SearchTerm generateSearchTerm(Flags supportedFlags, Folder folder) {
320322
return searchTerm;
321323
}
322324

323-
private SearchTerm applyTermsWhenNoRecentFlag(Folder folder, SearchTerm searchTerm) {
325+
private SearchTerm applyTermsWhenNoRecentFlag(Folder folder, @Nullable SearchTerm searchTerm) {
324326
NotTerm notFlagged;
325327
if (folder.getPermanentFlags().contains(Flag.USER)) {
326328
logger.debug(() -> "This email server does not support RECENT flag, but it does support " +

spring-integration-mail/src/main/java/org/springframework/integration/mail/MailReceiver.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2021 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.integration.mail;
1818

19+
import org.jspecify.annotations.Nullable;
20+
1921
/**
2022
* Strategy interface for receiving mail {@link jakarta.mail.Message Messages}.
2123
*
@@ -25,6 +27,6 @@
2527
*/
2628
public interface MailReceiver {
2729

28-
Object[] receive() throws jakarta.mail.MessagingException;
30+
Object @Nullable [] receive() throws jakarta.mail.MessagingException;
2931

3032
}

spring-integration-mail/src/main/java/org/springframework/integration/mail/MailReceivingMessageSource.java

Lines changed: 4 additions & 2 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.
@@ -20,6 +20,8 @@
2020
import java.util.Queue;
2121
import java.util.concurrent.ConcurrentLinkedQueue;
2222

23+
import org.jspecify.annotations.Nullable;
24+
2325
import org.springframework.core.log.LogMessage;
2426
import org.springframework.integration.endpoint.AbstractMessageSource;
2527
import org.springframework.messaging.MessagingException;
@@ -54,7 +56,7 @@ public String getComponentType() {
5456
}
5557

5658
@Override
57-
protected Object doReceive() {
59+
protected @Nullable Object doReceive() {
5860
try {
5961
Object mailMessage = this.mailQueue.poll();
6062
if (mailMessage == null) {

spring-integration-mail/src/main/java/org/springframework/integration/mail/MailSendingMessageHandler.java

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,12 @@
1616

1717
package org.springframework.integration.mail;
1818

19+
import java.util.Arrays;
20+
import java.util.Objects;
21+
1922
import jakarta.mail.MessagingException;
2023
import jakarta.mail.internet.MimeMessage;
24+
import org.jspecify.annotations.Nullable;
2125

2226
import org.springframework.core.io.ByteArrayResource;
2327
import org.springframework.integration.handler.AbstractMessageHandler;
@@ -190,12 +194,14 @@ private void applyHeadersToMailMessage(MailMessage mailMessage, MessageHeaders h
190194
}
191195
}
192196

193-
private String[] retrieveHeaderValueAsStringArray(MessageHeaders headers, String key) {
197+
private String @Nullable [] retrieveHeaderValueAsStringArray(MessageHeaders headers, String key) {
194198
Object value = headers.get(key);
195199
String[] returnedHeaders = null;
196200
if (value != null) {
197-
if (value instanceof String[]) {
198-
returnedHeaders = (String[]) value;
201+
if (value instanceof String[] strArr) {
202+
returnedHeaders = Arrays.stream(strArr)
203+
.filter(Objects::nonNull)
204+
.toArray(String[]::new);
199205
}
200206
else if (value instanceof String) {
201207
returnedHeaders = StringUtils.commaDelimitedListToStringArray((String) value);

spring-integration-mail/src/main/java/org/springframework/integration/mail/MailTransportUtils.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2007-2024 the original author or authors.
2+
* Copyright 2007-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.
@@ -22,6 +22,7 @@
2222
import jakarta.mail.URLName;
2323
import org.apache.commons.logging.Log;
2424
import org.apache.commons.logging.LogFactory;
25+
import org.jspecify.annotations.Nullable;
2526

2627
import org.springframework.util.StringUtils;
2728

@@ -44,7 +45,7 @@ public abstract class MailTransportUtils {
4445
* @see jakarta.mail.Transport
4546
* @see jakarta.mail.Store
4647
*/
47-
public static void closeService(Service service) {
48+
public static void closeService(@Nullable Service service) {
4849
if (service != null) {
4950
try {
5051
service.close();
@@ -61,7 +62,7 @@ public static void closeService(Service service) {
6162
* @param folder the JavaMail Folder to close (may be <code>null</code>)
6263
* @param expunge whether all deleted messages should be expunged from the folder
6364
*/
64-
public static void closeFolder(Folder folder, boolean expunge) {
65+
public static void closeFolder(@Nullable Folder folder, boolean expunge) {
6566
if (folder != null && folder.isOpen()) {
6667
try {
6768
folder.close(expunge);

spring-integration-mail/src/main/java/org/springframework/integration/mail/Pop3MailReceiver.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import jakarta.mail.MessagingException;
2222
import jakarta.mail.URLName;
2323
import jakarta.mail.internet.MimeMessage;
24+
import org.jspecify.annotations.Nullable;
2425

2526
import org.springframework.util.Assert;
2627

@@ -41,7 +42,7 @@ public Pop3MailReceiver() {
4142
}
4243

4344
@SuppressWarnings("this-escape")
44-
public Pop3MailReceiver(String url) {
45+
public Pop3MailReceiver(@Nullable String url) {
4546
super(url);
4647
if (url != null) {
4748
Assert.isTrue(url.startsWith(PROTOCOL), "url must start with 'pop3'");

0 commit comments

Comments
 (0)