This is an automated email from the ASF dual-hosted git repository.
Aias00 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shenyu.git
The following commit(s) were added to refs/heads/master by this push:
new 69399fe5af fix: avoid NPE when selector/rule sync data is null
(#6890) (#6925)
69399fe5af is described below
commit 69399fe5af8ddddf55fbc863d4c6c428de8ac4f6
Author: Southern <[email protected]>
AuthorDate: Fri Aug 21 10:18:58 2026 +0800
fix: avoid NPE when selector/rule sync data is null (#6890) (#6925)
When the http sync data is null, CollectionUtils.isEmpty(null) is true and
the original code called data.forEach
(pluginDataSubscriber::unSelectorSubscribe),
which threw a NullPointerException. The forEach on the empty/null data
was dead
code in the empty-list case and the NPE trigger in the null case.
Restructure refresh() to clear the cache unconditionally first, following
the
same implementation as PluginDataRefresh, and return early when the data
is
empty, so a null payload clears the cache instead of crashing. Behavior
for
empty and non-empty data is unchanged.
Add regression tests covering refresh with null data for both refreshers.
Co-authored-by: aias00 <[email protected]>
---
.../shenyu/sync/data/http/refresh/RuleDataRefresh.java | 9 +++------
.../sync/data/http/refresh/SelectorDataRefresh.java | 9 +++------
.../sync/data/http/refresh/RuleDataRefreshTest.java | 15 +++++++++++++++
.../sync/data/http/refresh/SelectorDataRefreshTest.java | 15 +++++++++++++++
4 files changed, 36 insertions(+), 12 deletions(-)
diff --git
a/shenyu-sync-data-center/shenyu-sync-data-http/src/main/java/org/apache/shenyu/sync/data/http/refresh/RuleDataRefresh.java
b/shenyu-sync-data-center/shenyu-sync-data-http/src/main/java/org/apache/shenyu/sync/data/http/refresh/RuleDataRefresh.java
index 08b7542d74..f85dc69cb7 100644
---
a/shenyu-sync-data-center/shenyu-sync-data-http/src/main/java/org/apache/shenyu/sync/data/http/refresh/RuleDataRefresh.java
+++
b/shenyu-sync-data-center/shenyu-sync-data-http/src/main/java/org/apache/shenyu/sync/data/http/refresh/RuleDataRefresh.java
@@ -69,14 +69,11 @@ public class RuleDataRefresh extends
AbstractDataRefresh<RuleData> {
@Override
protected void refresh(final List<RuleData> data) {
+ pluginDataSubscriber.refreshRuleDataAll();
if (CollectionUtils.isEmpty(data)) {
LOG.info("clear all rule cache, old cache");
- data.forEach(pluginDataSubscriber::unRuleSubscribe);
- pluginDataSubscriber.refreshRuleDataAll();
- } else {
- // update cache for UpstreamCacheManager
- pluginDataSubscriber.refreshRuleDataAll();
- data.forEach(pluginDataSubscriber::onRuleSubscribe);
+ return;
}
+ data.forEach(pluginDataSubscriber::onRuleSubscribe);
}
}
diff --git
a/shenyu-sync-data-center/shenyu-sync-data-http/src/main/java/org/apache/shenyu/sync/data/http/refresh/SelectorDataRefresh.java
b/shenyu-sync-data-center/shenyu-sync-data-http/src/main/java/org/apache/shenyu/sync/data/http/refresh/SelectorDataRefresh.java
index 7d6fecd93b..29cce1b63e 100644
---
a/shenyu-sync-data-center/shenyu-sync-data-http/src/main/java/org/apache/shenyu/sync/data/http/refresh/SelectorDataRefresh.java
+++
b/shenyu-sync-data-center/shenyu-sync-data-http/src/main/java/org/apache/shenyu/sync/data/http/refresh/SelectorDataRefresh.java
@@ -69,14 +69,11 @@ public class SelectorDataRefresh extends
AbstractDataRefresh<SelectorData> {
@Override
protected void refresh(final List<SelectorData> data) {
+ pluginDataSubscriber.refreshSelectorDataAll();
if (CollectionUtils.isEmpty(data)) {
LOG.info("clear all selector cache, old cache");
- data.forEach(pluginDataSubscriber::unSelectorSubscribe);
- pluginDataSubscriber.refreshSelectorDataAll();
- } else {
- // update cache for UpstreamCacheManager
- pluginDataSubscriber.refreshSelectorDataAll();
- data.forEach(pluginDataSubscriber::onSelectorSubscribe);
+ return;
}
+ data.forEach(pluginDataSubscriber::onSelectorSubscribe);
}
}
diff --git
a/shenyu-sync-data-center/shenyu-sync-data-http/src/test/java/org/apache/shenyu/sync/data/http/refresh/RuleDataRefreshTest.java
b/shenyu-sync-data-center/shenyu-sync-data-http/src/test/java/org/apache/shenyu/sync/data/http/refresh/RuleDataRefreshTest.java
index 29f0729782..6536bfb0a3 100644
---
a/shenyu-sync-data-center/shenyu-sync-data-http/src/test/java/org/apache/shenyu/sync/data/http/refresh/RuleDataRefreshTest.java
+++
b/shenyu-sync-data-center/shenyu-sync-data-http/src/test/java/org/apache/shenyu/sync/data/http/refresh/RuleDataRefreshTest.java
@@ -32,6 +32,10 @@ import java.util.List;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
public final class RuleDataRefreshTest {
@@ -78,4 +82,15 @@ public final class RuleDataRefreshTest {
ruleDataList.add(ruleData);
ruleDataRefresh.refresh(ruleDataList);
}
+
+ @Test
+ public void testRefreshWithNullData() {
+ final PluginDataSubscriber subscriber =
mock(PluginDataSubscriber.class);
+ final RuleDataRefresh ruleDataRefresh = new
RuleDataRefresh(subscriber);
+ // data is null, should not throw NPE; cache is still refreshed
unconditionally, then return early
+ ruleDataRefresh.refresh((List<RuleData>) null);
+ verify(subscriber).refreshRuleDataAll();
+ verify(subscriber, never()).unRuleSubscribe(any(RuleData.class));
+ verify(subscriber, never()).onRuleSubscribe(any(RuleData.class));
+ }
}
diff --git
a/shenyu-sync-data-center/shenyu-sync-data-http/src/test/java/org/apache/shenyu/sync/data/http/refresh/SelectorDataRefreshTest.java
b/shenyu-sync-data-center/shenyu-sync-data-http/src/test/java/org/apache/shenyu/sync/data/http/refresh/SelectorDataRefreshTest.java
index 854a4a766b..d2ca4c2d85 100644
---
a/shenyu-sync-data-center/shenyu-sync-data-http/src/test/java/org/apache/shenyu/sync/data/http/refresh/SelectorDataRefreshTest.java
+++
b/shenyu-sync-data-center/shenyu-sync-data-http/src/test/java/org/apache/shenyu/sync/data/http/refresh/SelectorDataRefreshTest.java
@@ -28,6 +28,10 @@ import org.junit.jupiter.api.Test;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
import java.util.ArrayList;
import java.util.Collections;
@@ -78,4 +82,15 @@ public final class SelectorDataRefreshTest {
selectorDataList.add(selectorData);
selectorDataRefresh.refresh(selectorDataList);
}
+
+ @Test
+ public void testRefreshWithNullData() {
+ final PluginDataSubscriber subscriber =
mock(PluginDataSubscriber.class);
+ final SelectorDataRefresh selectorDataRefresh = new
SelectorDataRefresh(subscriber);
+ // data is null, should not throw NPE; cache is still refreshed
unconditionally, then return early
+ selectorDataRefresh.refresh((List<SelectorData>) null);
+ verify(subscriber).refreshSelectorDataAll();
+ verify(subscriber,
never()).unSelectorSubscribe(any(SelectorData.class));
+ verify(subscriber,
never()).onSelectorSubscribe(any(SelectorData.class));
+ }
}