Skip to content

Commit 2c3c0d3

Browse files
artembilancppwfs
authored andcommitted
spring-projectsGH-10083: Implement Nullability in ZK module
Related to: spring-projects#10083 * Add `@org.jspecify.annotations.NullMarked` to all the packages in the ZK module * Fix all the respective Nullability failures in the ZK module * Fix message in assert for `candidate` in the `LeaderInitiatorFactoryBean.afterPropertiesSet()` * Fix warning for `serialVersionUID` in the `ZookeeperLockRegistry`
1 parent 07778e1 commit 2c3c0d3

File tree

10 files changed

+88
-62
lines changed

10 files changed

+88
-62
lines changed

spring-integration-zookeeper/src/main/java/org/springframework/integration/zookeeper/config/CuratorFrameworkFactoryBean.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2015-2024 the original author or authors.
2+
* Copyright 2015-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.
@@ -115,9 +115,7 @@ public void start() {
115115
this.lifecycleLock.lock();
116116
try {
117117
if (!this.running) {
118-
if (this.client != null) {
119-
this.client.start();
120-
}
118+
this.client.start();
121119
this.running = true;
122120
}
123121
}

spring-integration-zookeeper/src/main/java/org/springframework/integration/zookeeper/config/LeaderInitiatorFactoryBean.java

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2015-2023 the original author or authors.
2+
* Copyright 2015-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,6 +19,7 @@
1919
import java.util.UUID;
2020

2121
import org.apache.curator.framework.CuratorFramework;
22+
import org.jspecify.annotations.Nullable;
2223

2324
import org.springframework.beans.factory.FactoryBean;
2425
import org.springframework.beans.factory.InitializingBean;
@@ -31,6 +32,7 @@
3132
import org.springframework.integration.leader.event.LeaderEventPublisher;
3233
import org.springframework.integration.zookeeper.leader.LeaderInitiator;
3334
import org.springframework.util.Assert;
35+
import org.springframework.util.StringUtils;
3436

3537
/**
3638
* Creates a {@link LeaderInitiator}.
@@ -44,21 +46,22 @@
4446
public class LeaderInitiatorFactoryBean
4547
implements FactoryBean<LeaderInitiator>, SmartLifecycle, InitializingBean, ApplicationEventPublisherAware {
4648

47-
private CuratorFramework client;
49+
private @Nullable CuratorFramework client;
4850

49-
private Candidate candidate;
51+
private @Nullable Candidate candidate;
5052

51-
private String path;
53+
private @Nullable String path;
5254

53-
private LeaderInitiator leaderInitiator;
55+
private @Nullable LeaderInitiator leaderInitiator;
5456

5557
private boolean autoStartup = true;
5658

5759
private int phase = Integer.MAX_VALUE - 1000; // NOSONAR magic number
5860

61+
@SuppressWarnings("NullAway.Init")
5962
private ApplicationEventPublisher applicationEventPublisher;
6063

61-
private LeaderEventPublisher leaderEventPublisher;
64+
private @Nullable LeaderEventPublisher leaderEventPublisher;
6265

6366
public LeaderInitiatorFactoryBean() {
6467
}
@@ -164,21 +167,24 @@ public int getPhase() {
164167
@Override
165168
public void afterPropertiesSet() {
166169
if (this.leaderInitiator == null) {
167-
this.leaderInitiator = new LeaderInitiator(this.client, this.candidate, this.path);
170+
Assert.notNull(this.client, "The 'CuratorFramework' must be provided.");
171+
Assert.notNull(this.candidate, "The 'candidate' must be provided.");
172+
this.leaderInitiator =
173+
StringUtils.hasText(this.path)
174+
? new LeaderInitiator(this.client, this.candidate, this.path)
175+
: new LeaderInitiator(this.client, this.candidate);
168176
this.leaderInitiator.setPhase(this.phase);
169177
this.leaderInitiator.setAutoStartup(this.autoStartup);
170-
if (this.leaderEventPublisher != null) {
171-
this.leaderInitiator.setLeaderEventPublisher(this.leaderEventPublisher);
172-
}
173-
else if (this.applicationEventPublisher != null) {
174-
this.leaderInitiator.setLeaderEventPublisher(
175-
new DefaultLeaderEventPublisher(this.applicationEventPublisher));
178+
LeaderEventPublisher leaderEventPublisherToSet = this.leaderEventPublisher;
179+
if (leaderEventPublisherToSet == null) {
180+
leaderEventPublisherToSet = new DefaultLeaderEventPublisher(this.applicationEventPublisher);
176181
}
182+
this.leaderInitiator.setLeaderEventPublisher(leaderEventPublisherToSet);
177183
}
178184
}
179185

180186
@Override
181-
public LeaderInitiator getObject() {
187+
public @Nullable LeaderInitiator getObject() {
182188
return this.leaderInitiator;
183189
}
184190

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
/**
22
* Provides classes related to configuration.
33
*/
4+
@org.jspecify.annotations.NullMarked
45
package org.springframework.integration.zookeeper.config;
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
/**
22
* Base package for zookeeper configuration.
33
*/
4+
@org.jspecify.annotations.NullMarked
45
package org.springframework.integration.zookeeper.config.xml;

spring-integration-zookeeper/src/main/java/org/springframework/integration/zookeeper/leader/LeaderInitiator.java

Lines changed: 42 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2014-2023 the original author or authors.
2+
* Copyright 2014-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.
@@ -28,12 +28,12 @@
2828
import org.apache.curator.framework.recipes.leader.LeaderSelector;
2929
import org.apache.curator.framework.recipes.leader.LeaderSelectorListenerAdapter;
3030
import org.apache.curator.framework.recipes.leader.Participant;
31+
import org.jspecify.annotations.Nullable;
3132

3233
import org.springframework.context.SmartLifecycle;
3334
import org.springframework.integration.leader.Candidate;
3435
import org.springframework.integration.leader.Context;
3536
import org.springframework.integration.leader.event.LeaderEventPublisher;
36-
import org.springframework.util.StringUtils;
3737

3838
/**
3939
* Bootstrap leadership {@link Candidate candidates}
@@ -79,7 +79,7 @@ public class LeaderInitiator implements SmartLifecycle {
7979
/**
8080
* Leader event publisher if set
8181
*/
82-
private LeaderEventPublisher leaderEventPublisher;
82+
private @Nullable LeaderEventPublisher leaderEventPublisher;
8383

8484
/**
8585
* @see SmartLifecycle
@@ -94,7 +94,7 @@ public class LeaderInitiator implements SmartLifecycle {
9494
/**
9595
* Curator utility for selecting leaders.
9696
*/
97-
private volatile LeaderSelector leaderSelector;
97+
private volatile @Nullable LeaderSelector leaderSelector;
9898

9999
/**
100100
* Flag that indicates whether the leadership election for
@@ -167,15 +167,17 @@ public void start() {
167167
if (!this.running) {
168168
if (this.client.getState() != CuratorFrameworkState.STARTED) {
169169
// we want to do curator start here because it needs to
170-
// be started before leader selector and it gets a little
170+
// be started before leader selector, and it gets a little
171171
// complicated to control ordering via beans so that
172172
// curator is fully started.
173173
this.client.start();
174174
}
175-
this.leaderSelector = new LeaderSelector(this.client, buildLeaderPath(), new LeaderListener());
176-
this.leaderSelector.setId(this.candidate.getId());
177-
this.leaderSelector.autoRequeue();
178-
this.leaderSelector.start();
175+
LeaderSelector leaderSelectorToSet =
176+
new LeaderSelector(this.client, buildLeaderPath(), new LeaderListener());
177+
leaderSelectorToSet.setId(this.candidate.getId());
178+
leaderSelectorToSet.autoRequeue();
179+
leaderSelectorToSet.start();
180+
this.leaderSelector = leaderSelectorToSet;
179181

180182
this.running = true;
181183
LOGGER.debug("Started LeaderInitiator");
@@ -195,7 +197,10 @@ public void stop() {
195197
this.lifecycleMonitor.lock();
196198
try {
197199
if (this.running) {
198-
this.leaderSelector.close();
200+
LeaderSelector leaderSelectorToClose = this.leaderSelector;
201+
if (leaderSelectorToClose != null) {
202+
leaderSelectorToClose.close();
203+
}
199204
this.running = false;
200205
LOGGER.debug("Stopped LeaderInitiator");
201206
}
@@ -229,7 +234,7 @@ public CuratorContext getContext() {
229234
* @return the ZooKeeper path used for leadership election by Curator
230235
*/
231236
private String buildLeaderPath() {
232-
String ns = StringUtils.hasText(this.namespace) ? this.namespace : DEFAULT_NAMESPACE;
237+
String ns = this.namespace;
233238
if (ns.charAt(0) != '/') {
234239
ns = '/' + ns;
235240
}
@@ -294,12 +299,16 @@ public class CuratorContext implements Context {
294299

295300
@Override
296301
public boolean isLeader() {
297-
return LeaderInitiator.this.leaderSelector.hasLeadership();
302+
LeaderSelector leaderSelectorToCheck = LeaderInitiator.this.leaderSelector;
303+
return leaderSelectorToCheck != null && leaderSelectorToCheck.hasLeadership();
298304
}
299305

300306
@Override
301307
public void yield() {
302-
LeaderInitiator.this.leaderSelector.interruptLeadership();
308+
LeaderSelector leaderSelectorToInterrupt = LeaderInitiator.this.leaderSelector;
309+
if (leaderSelectorToInterrupt != null) {
310+
leaderSelectorToInterrupt.interruptLeadership();
311+
}
303312
}
304313

305314
@Override
@@ -312,13 +321,17 @@ public String getRole() {
312321
* @return the leader.
313322
* @since 6.0.3
314323
*/
315-
public Participant getLeader() {
316-
try {
317-
return LeaderInitiator.this.leaderSelector.getLeader();
318-
}
319-
catch (Exception ex) {
320-
throw new IllegalStateException(ex);
324+
public @Nullable Participant getLeader() {
325+
LeaderSelector leaderSelectorToUse = LeaderInitiator.this.leaderSelector;
326+
if (leaderSelectorToUse != null) {
327+
try {
328+
return leaderSelectorToUse.getLeader();
329+
}
330+
catch (Exception ex) {
331+
throw new IllegalStateException(ex);
332+
}
321333
}
334+
return null;
322335
}
323336

324337
/**
@@ -327,12 +340,16 @@ public Participant getLeader() {
327340
* @since 6.0.3
328341
*/
329342
public Collection<Participant> getParticipants() {
330-
try {
331-
return LeaderInitiator.this.leaderSelector.getParticipants();
332-
}
333-
catch (Exception ex) {
334-
throw new IllegalStateException(ex);
343+
LeaderSelector leaderSelectorToUse = LeaderInitiator.this.leaderSelector;
344+
if (leaderSelectorToUse != null) {
345+
try {
346+
return leaderSelectorToUse.getParticipants();
347+
}
348+
catch (Exception ex) {
349+
throw new IllegalStateException(ex);
350+
}
335351
}
352+
return List.of();
336353
}
337354

338355
@Override
@@ -352,12 +369,7 @@ public boolean isLeader() {
352369
}
353370

354371
@Override
355-
public String getRole() {
356-
return LeaderInitiator.this.candidate.getRole();
357-
}
358-
359-
@Override
360-
public Participant getLeader() {
372+
public @Nullable Participant getLeader() {
361373
return null;
362374
}
363375

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
/**
22
* Temporary package until s-c-c-zookeeper is released.
33
*/
4+
@org.jspecify.annotations.NullMarked
45
package org.springframework.integration.zookeeper.leader;

spring-integration-zookeeper/src/main/java/org/springframework/integration/zookeeper/lock/ZookeeperLockRegistry.java

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2015-2023 the original author or authors.
2+
* Copyright 2015-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,7 @@
1616

1717
package org.springframework.integration.zookeeper.lock;
1818

19+
import java.io.Serial;
1920
import java.util.LinkedHashMap;
2021
import java.util.Map;
2122
import java.util.Map.Entry;
@@ -63,7 +64,10 @@ public class ZookeeperLockRegistry implements ExpirableLockRegistry, DisposableB
6364
private final Lock locksLock = new ReentrantLock();
6465

6566
private final Map<String, ZkLock> locks =
66-
new LinkedHashMap<String, ZkLock>(16, 0.75F, true) {
67+
new LinkedHashMap<>(16, 0.75F, true) {
68+
69+
@Serial
70+
private static final long serialVersionUID = 7092378879531819061L;
6771

6872
@Override
6973
protected boolean removeEldestEntry(Entry<String, ZkLock> eldest) {
@@ -334,9 +338,7 @@ public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
334338
}
335339
}
336340
catch (@SuppressWarnings("unused") TimeoutException e) {
337-
if (future != null) {
338-
future.cancel(true);
339-
}
341+
future.cancel(true);
340342
return false;
341343
}
342344
catch (InterruptedException e) {
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
/**
22
* Provides classes related to locking.
33
*/
4+
@org.jspecify.annotations.NullMarked
45
package org.springframework.integration.zookeeper.lock;

0 commit comments

Comments
 (0)