diff --git a/spring-integration-zookeeper/src/main/java/org/springframework/integration/zookeeper/config/CuratorFrameworkFactoryBean.java b/spring-integration-zookeeper/src/main/java/org/springframework/integration/zookeeper/config/CuratorFrameworkFactoryBean.java index 4a2778de64..b05317dd7e 100644 --- a/spring-integration-zookeeper/src/main/java/org/springframework/integration/zookeeper/config/CuratorFrameworkFactoryBean.java +++ b/spring-integration-zookeeper/src/main/java/org/springframework/integration/zookeeper/config/CuratorFrameworkFactoryBean.java @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -115,9 +115,7 @@ public class CuratorFrameworkFactoryBean implements FactoryBean, SmartLifecycle, InitializingBean, ApplicationEventPublisherAware { - private CuratorFramework client; + private @Nullable CuratorFramework client; - private Candidate candidate; + private @Nullable Candidate candidate; - private String path; + private @Nullable String path; - private LeaderInitiator leaderInitiator; + private @Nullable LeaderInitiator leaderInitiator; private boolean autoStartup = true; private int phase = Integer.MAX_VALUE - 1000; // NOSONAR magic number + @SuppressWarnings("NullAway.Init") private ApplicationEventPublisher applicationEventPublisher; - private LeaderEventPublisher leaderEventPublisher; + private @Nullable LeaderEventPublisher leaderEventPublisher; public LeaderInitiatorFactoryBean() { } @@ -164,21 +167,24 @@ public class LeaderInitiatorFactoryBean @Override public void afterPropertiesSet() { if (this.leaderInitiator == null) { - this.leaderInitiator = new LeaderInitiator(this.client, this.candidate, this.path); + Assert.notNull(this.client, "The 'CuratorFramework' must be provided."); + Assert.notNull(this.candidate, "The 'candidate' must be provided."); + this.leaderInitiator = + StringUtils.hasText(this.path) + ? new LeaderInitiator(this.client, this.candidate, this.path) + : new LeaderInitiator(this.client, this.candidate); this.leaderInitiator.setPhase(this.phase); this.leaderInitiator.setAutoStartup(this.autoStartup); - if (this.leaderEventPublisher != null) { - this.leaderInitiator.setLeaderEventPublisher(this.leaderEventPublisher); - } - else if (this.applicationEventPublisher != null) { - this.leaderInitiator.setLeaderEventPublisher( - new DefaultLeaderEventPublisher(this.applicationEventPublisher)); + LeaderEventPublisher leaderEventPublisherToSet = this.leaderEventPublisher; + if (leaderEventPublisherToSet == null) { + leaderEventPublisherToSet = new DefaultLeaderEventPublisher(this.applicationEventPublisher); } + this.leaderInitiator.setLeaderEventPublisher(leaderEventPublisherToSet); } } @Override - public LeaderInitiator getObject() { + public @Nullable LeaderInitiator getObject() { return this.leaderInitiator; } diff --git a/spring-integration-zookeeper/src/main/java/org/springframework/integration/zookeeper/config/package-info.java b/spring-integration-zookeeper/src/main/java/org/springframework/integration/zookeeper/config/package-info.java index 0050579568..b99a64c410 100644 --- a/spring-integration-zookeeper/src/main/java/org/springframework/integration/zookeeper/config/package-info.java +++ b/spring-integration-zookeeper/src/main/java/org/springframework/integration/zookeeper/config/package-info.java @@ -1,4 +1,5 @@ /** * Provides classes related to configuration. */ +@org.jspecify.annotations.NullMarked package org.springframework.integration.zookeeper.config; diff --git a/spring-integration-zookeeper/src/main/java/org/springframework/integration/zookeeper/config/xml/package-info.java b/spring-integration-zookeeper/src/main/java/org/springframework/integration/zookeeper/config/xml/package-info.java index 6dcf881128..d462e8e8a9 100644 --- a/spring-integration-zookeeper/src/main/java/org/springframework/integration/zookeeper/config/xml/package-info.java +++ b/spring-integration-zookeeper/src/main/java/org/springframework/integration/zookeeper/config/xml/package-info.java @@ -1,4 +1,5 @@ /** * Base package for zookeeper configuration. */ +@org.jspecify.annotations.NullMarked package org.springframework.integration.zookeeper.config.xml; diff --git a/spring-integration-zookeeper/src/main/java/org/springframework/integration/zookeeper/leader/LeaderInitiator.java b/spring-integration-zookeeper/src/main/java/org/springframework/integration/zookeeper/leader/LeaderInitiator.java index bddf3a2f37..53847c0cb6 100644 --- a/spring-integration-zookeeper/src/main/java/org/springframework/integration/zookeeper/leader/LeaderInitiator.java +++ b/spring-integration-zookeeper/src/main/java/org/springframework/integration/zookeeper/leader/LeaderInitiator.java @@ -1,5 +1,5 @@ /* - * Copyright 2014-2023 the original author or authors. + * Copyright 2014-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,12 +28,12 @@ import org.apache.curator.framework.imps.CuratorFrameworkState; import org.apache.curator.framework.recipes.leader.LeaderSelector; import org.apache.curator.framework.recipes.leader.LeaderSelectorListenerAdapter; import org.apache.curator.framework.recipes.leader.Participant; +import org.jspecify.annotations.Nullable; import org.springframework.context.SmartLifecycle; import org.springframework.integration.leader.Candidate; import org.springframework.integration.leader.Context; import org.springframework.integration.leader.event.LeaderEventPublisher; -import org.springframework.util.StringUtils; /** * Bootstrap leadership {@link Candidate candidates} @@ -79,7 +79,7 @@ public class LeaderInitiator implements SmartLifecycle { /** * Leader event publisher if set */ - private LeaderEventPublisher leaderEventPublisher; + private @Nullable LeaderEventPublisher leaderEventPublisher; /** * @see SmartLifecycle @@ -94,7 +94,7 @@ public class LeaderInitiator implements SmartLifecycle { /** * Curator utility for selecting leaders. */ - private volatile LeaderSelector leaderSelector; + private volatile @Nullable LeaderSelector leaderSelector; /** * Flag that indicates whether the leadership election for @@ -167,15 +167,17 @@ public class LeaderInitiator implements SmartLifecycle { if (!this.running) { if (this.client.getState() != CuratorFrameworkState.STARTED) { // we want to do curator start here because it needs to - // be started before leader selector and it gets a little + // be started before leader selector, and it gets a little // complicated to control ordering via beans so that // curator is fully started. this.client.start(); } - this.leaderSelector = new LeaderSelector(this.client, buildLeaderPath(), new LeaderListener()); - this.leaderSelector.setId(this.candidate.getId()); - this.leaderSelector.autoRequeue(); - this.leaderSelector.start(); + LeaderSelector leaderSelectorToSet = + new LeaderSelector(this.client, buildLeaderPath(), new LeaderListener()); + leaderSelectorToSet.setId(this.candidate.getId()); + leaderSelectorToSet.autoRequeue(); + leaderSelectorToSet.start(); + this.leaderSelector = leaderSelectorToSet; this.running = true; LOGGER.debug("Started LeaderInitiator"); @@ -195,7 +197,10 @@ public class LeaderInitiator implements SmartLifecycle { this.lifecycleMonitor.lock(); try { if (this.running) { - this.leaderSelector.close(); + LeaderSelector leaderSelectorToClose = this.leaderSelector; + if (leaderSelectorToClose != null) { + leaderSelectorToClose.close(); + } this.running = false; LOGGER.debug("Stopped LeaderInitiator"); } @@ -229,7 +234,7 @@ public class LeaderInitiator implements SmartLifecycle { * @return the ZooKeeper path used for leadership election by Curator */ private String buildLeaderPath() { - String ns = StringUtils.hasText(this.namespace) ? this.namespace : DEFAULT_NAMESPACE; + String ns = this.namespace; if (ns.charAt(0) != '/') { ns = '/' + ns; } @@ -294,12 +299,16 @@ public class LeaderInitiator implements SmartLifecycle { @Override public boolean isLeader() { - return LeaderInitiator.this.leaderSelector.hasLeadership(); + LeaderSelector leaderSelectorToCheck = LeaderInitiator.this.leaderSelector; + return leaderSelectorToCheck != null && leaderSelectorToCheck.hasLeadership(); } @Override public void yield() { - LeaderInitiator.this.leaderSelector.interruptLeadership(); + LeaderSelector leaderSelectorToInterrupt = LeaderInitiator.this.leaderSelector; + if (leaderSelectorToInterrupt != null) { + leaderSelectorToInterrupt.interruptLeadership(); + } } @Override @@ -312,13 +321,17 @@ public class LeaderInitiator implements SmartLifecycle { * @return the leader. * @since 6.0.3 */ - public Participant getLeader() { - try { - return LeaderInitiator.this.leaderSelector.getLeader(); - } - catch (Exception ex) { - throw new IllegalStateException(ex); + public @Nullable Participant getLeader() { + LeaderSelector leaderSelectorToUse = LeaderInitiator.this.leaderSelector; + if (leaderSelectorToUse != null) { + try { + return leaderSelectorToUse.getLeader(); + } + catch (Exception ex) { + throw new IllegalStateException(ex); + } } + return null; } /** @@ -327,12 +340,16 @@ public class LeaderInitiator implements SmartLifecycle { * @since 6.0.3 */ public Collection getParticipants() { - try { - return LeaderInitiator.this.leaderSelector.getParticipants(); - } - catch (Exception ex) { - throw new IllegalStateException(ex); + LeaderSelector leaderSelectorToUse = LeaderInitiator.this.leaderSelector; + if (leaderSelectorToUse != null) { + try { + return leaderSelectorToUse.getParticipants(); + } + catch (Exception ex) { + throw new IllegalStateException(ex); + } } + return List.of(); } @Override @@ -352,12 +369,7 @@ public class LeaderInitiator implements SmartLifecycle { } @Override - public String getRole() { - return LeaderInitiator.this.candidate.getRole(); - } - - @Override - public Participant getLeader() { + public @Nullable Participant getLeader() { return null; } diff --git a/spring-integration-zookeeper/src/main/java/org/springframework/integration/zookeeper/leader/package-info.java b/spring-integration-zookeeper/src/main/java/org/springframework/integration/zookeeper/leader/package-info.java index 4e58a008b0..b36aae93c6 100644 --- a/spring-integration-zookeeper/src/main/java/org/springframework/integration/zookeeper/leader/package-info.java +++ b/spring-integration-zookeeper/src/main/java/org/springframework/integration/zookeeper/leader/package-info.java @@ -1,4 +1,5 @@ /** * Temporary package until s-c-c-zookeeper is released. */ +@org.jspecify.annotations.NullMarked package org.springframework.integration.zookeeper.leader; diff --git a/spring-integration-zookeeper/src/main/java/org/springframework/integration/zookeeper/lock/ZookeeperLockRegistry.java b/spring-integration-zookeeper/src/main/java/org/springframework/integration/zookeeper/lock/ZookeeperLockRegistry.java index fece7d598f..d3f5965209 100644 --- a/spring-integration-zookeeper/src/main/java/org/springframework/integration/zookeeper/lock/ZookeeperLockRegistry.java +++ b/spring-integration-zookeeper/src/main/java/org/springframework/integration/zookeeper/lock/ZookeeperLockRegistry.java @@ -1,5 +1,5 @@ /* - * Copyright 2015-2023 the original author or authors. + * Copyright 2015-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,6 +16,7 @@ package org.springframework.integration.zookeeper.lock; +import java.io.Serial; import java.util.LinkedHashMap; import java.util.Map; import java.util.Map.Entry; @@ -63,7 +64,10 @@ public class ZookeeperLockRegistry implements ExpirableLockRegistry, DisposableB private final Lock locksLock = new ReentrantLock(); private final Map locks = - new LinkedHashMap(16, 0.75F, true) { + new LinkedHashMap<>(16, 0.75F, true) { + + @Serial + private static final long serialVersionUID = 7092378879531819061L; @Override protected boolean removeEldestEntry(Entry eldest) { @@ -334,9 +338,7 @@ public class ZookeeperLockRegistry implements ExpirableLockRegistry, DisposableB } } catch (@SuppressWarnings("unused") TimeoutException e) { - if (future != null) { - future.cancel(true); - } + future.cancel(true); return false; } catch (InterruptedException e) { diff --git a/spring-integration-zookeeper/src/main/java/org/springframework/integration/zookeeper/lock/package-info.java b/spring-integration-zookeeper/src/main/java/org/springframework/integration/zookeeper/lock/package-info.java index 2222b30744..2fe28d1459 100644 --- a/spring-integration-zookeeper/src/main/java/org/springframework/integration/zookeeper/lock/package-info.java +++ b/spring-integration-zookeeper/src/main/java/org/springframework/integration/zookeeper/lock/package-info.java @@ -1,4 +1,5 @@ /** * Provides classes related to locking. */ +@org.jspecify.annotations.NullMarked package org.springframework.integration.zookeeper.lock; diff --git a/spring-integration-zookeeper/src/main/java/org/springframework/integration/zookeeper/metadata/ZookeeperMetadataStore.java b/spring-integration-zookeeper/src/main/java/org/springframework/integration/zookeeper/metadata/ZookeeperMetadataStore.java index 082ff4c472..d3a1bc655c 100644 --- a/spring-integration-zookeeper/src/main/java/org/springframework/integration/zookeeper/metadata/ZookeeperMetadataStore.java +++ b/spring-integration-zookeeper/src/main/java/org/springframework/integration/zookeeper/metadata/ZookeeperMetadataStore.java @@ -1,5 +1,5 @@ /* - * Copyright 2015-2024 the original author or authors. + * Copyright 2015-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,6 +18,7 @@ package org.springframework.integration.zookeeper.metadata; import java.nio.charset.StandardCharsets; import java.util.List; +import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.CopyOnWriteArrayList; @@ -31,6 +32,7 @@ import org.apache.curator.framework.recipes.cache.CuratorCacheListener; import org.apache.curator.utils.CloseableUtils; import org.apache.zookeeper.KeeperException; import org.apache.zookeeper.data.Stat; +import org.jspecify.annotations.Nullable; import org.springframework.context.SmartLifecycle; import org.springframework.integration.metadata.ListenableMetadataStore; @@ -67,7 +69,7 @@ public class ZookeeperMetadataStore implements ListenableMetadataStore, SmartLif private String encoding = StandardCharsets.UTF_8.name(); - private CuratorCache cache; + private @Nullable CuratorCache cache; private boolean autoStartup = true; @@ -79,7 +81,7 @@ public class ZookeeperMetadataStore implements ListenableMetadataStore, SmartLif public ZookeeperMetadataStore(CuratorFramework client) { Assert.notNull(client, "Client cannot be null"); - this.client = client; // NOSONAR + this.client = client; } /** @@ -115,7 +117,7 @@ public class ZookeeperMetadataStore implements ListenableMetadataStore, SmartLif } @Override - public String putIfAbsent(String key, String value) { + public @Nullable String putIfAbsent(String key, String value) { this.lock.lock(); try { Assert.notNull(key, KEY_MUST_NOT_BE_NULL); @@ -207,12 +209,13 @@ public class ZookeeperMetadataStore implements ListenableMetadataStore, SmartLif } @Override - public String get(String key) { + public @Nullable String get(String key) { this.lock.lock(); try { Assert.notNull(key, KEY_MUST_NOT_BE_NULL); Assert.state(isRunning(), "ZookeeperMetadataStore has to be started before using."); - return this.cache.get(getPath(key)) + return Objects.requireNonNull(this.cache) + .get(getPath(key)) .map(currentData -> { // our version is more recent than the cache if (this.updateMap.containsKey(key) && @@ -240,7 +243,7 @@ public class ZookeeperMetadataStore implements ListenableMetadataStore, SmartLif } @Override - public String remove(String key) { + public @Nullable String remove(String key) { this.lock.lock(); try { Assert.notNull(key, KEY_MUST_NOT_BE_NULL); @@ -276,7 +279,7 @@ public class ZookeeperMetadataStore implements ListenableMetadataStore, SmartLif } public String getPath(String key) { - return "".equals(key) ? this.root : this.root + '/' + key; + return key.isEmpty() ? this.root : this.root + '/' + key; } @Override @@ -344,7 +347,7 @@ public class ZookeeperMetadataStore implements ListenableMetadataStore, SmartLif return path.replace(this.root + '/', ""); } - private record LocalChildData(String value, int version) { + private record LocalChildData(@Nullable String value, int version) { } diff --git a/spring-integration-zookeeper/src/main/java/org/springframework/integration/zookeeper/metadata/package-info.java b/spring-integration-zookeeper/src/main/java/org/springframework/integration/zookeeper/metadata/package-info.java index d6f79ba203..ce5461ff8b 100644 --- a/spring-integration-zookeeper/src/main/java/org/springframework/integration/zookeeper/metadata/package-info.java +++ b/spring-integration-zookeeper/src/main/java/org/springframework/integration/zookeeper/metadata/package-info.java @@ -2,4 +2,5 @@ * Provides classes supporting the Zookeeper-based * {@link org.springframework.integration.metadata.ListenableMetadataStore} */ +@org.jspecify.annotations.NullMarked package org.springframework.integration.zookeeper.metadata;