This is an automated email from the ASF dual-hosted git repository.
oscerd pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel-kamelets.git
The following commit(s) were added to refs/heads/main by this push:
new 2f25f63c9 chore: make KameletsCatalog lookup methods null-safe (#2892)
2f25f63c9 is described below
commit 2f25f63c93ca79300175c09435709291ce9cc193
Author: Andrea Cosentino <[email protected]>
AuthorDate: Tue Jun 30 13:43:38 2026 +0200
chore: make KameletsCatalog lookup methods null-safe (#2892)
* chore: make KameletsCatalog lookup methods null-safe
getKameletsByType/getKameletsByNamespace/getKameletsByGroups/
getKameletByProvider dereferenced getMetadata().getLabels()/getAnnotations()
.get(key) directly, so a Kamelet missing the queried label/annotation would
NPE and break the entire call. Guard the access through small helpers
(labelValue/annotationValue). Behaviour is unchanged for the shipped catalog
(the validator guarantees the labels); this is defense-in-depth for the
public API. Also drop the dead if/else in getKameletByProvider (it already
returns an empty list on no match) and add a test pinning the
non-null / empty-on-no-match contract.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Signed-off-by: Andrea Cosentino <[email protected]>
* chore: strengthen KameletsCatalog lookup contract test
Address review feedback on the lookup null-safety test:
- also assert the populated (non-empty) case for known label/annotation
values, so the test covers both the populated and empty/no-match
contracts;
- add descriptive failure messages that print the actual list on the
empty-on-no-match checks, keeping the module's JUnit Jupiter style (no new
AssertJ dependency).
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Signed-off-by: Andrea Cosentino <[email protected]>
---------
Signed-off-by: Andrea Cosentino <[email protected]>
Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>
---
.../camel/kamelets/catalog/KameletsCatalog.java | 50 +++++++++++++++-------
.../kamelets/catalog/KameletsCatalogTest.java | 22 ++++++++++
2 files changed, 56 insertions(+), 16 deletions(-)
diff --git
a/library/camel-kamelets-catalog/src/main/java/org/apache/camel/kamelets/catalog/KameletsCatalog.java
b/library/camel-kamelets-catalog/src/main/java/org/apache/camel/kamelets/catalog/KameletsCatalog.java
index e95260e15..845fd091b 100644
---
a/library/camel-kamelets-catalog/src/main/java/org/apache/camel/kamelets/catalog/KameletsCatalog.java
+++
b/library/camel-kamelets-catalog/src/main/java/org/apache/camel/kamelets/catalog/KameletsCatalog.java
@@ -96,6 +96,20 @@ public class KameletsCatalog {
return fileName.substring(9);
}
+ private static String labelValue(Kamelet kamelet, String key) {
+ if (kamelet.getMetadata() != null && kamelet.getMetadata().getLabels()
!= null) {
+ return kamelet.getMetadata().getLabels().get(key);
+ }
+ return null;
+ }
+
+ private static String annotationValue(Kamelet kamelet, String key) {
+ if (kamelet.getMetadata() != null &&
kamelet.getMetadata().getAnnotations() != null) {
+ return kamelet.getMetadata().getAnnotations().get(key);
+ }
+ return null;
+ }
+
public Map<String, Kamelet> getKamelets() {
return kameletModels;
@@ -114,27 +128,33 @@ public class KameletsCatalog {
}
public List<Kamelet> getKameletsByType(String type) {
- List<Kamelet> collect = kameletModels.entrySet().stream()
- .filter(x ->
x.getValue().getMetadata().getLabels().get(KameletLabelNames.KAMELET_LABEL_TYPE).contains(type))
+ return kameletModels.entrySet().stream()
+ .filter(x -> {
+ String value = labelValue(x.getValue(),
KameletLabelNames.KAMELET_LABEL_TYPE);
+ return value != null && value.contains(type);
+ })
.map(Map.Entry::getValue)
.collect(Collectors.toList());
- return collect;
}
public List<Kamelet> getKameletsByNamespace(String namespace) {
- List<Kamelet> collect = kameletModels.entrySet().stream()
- .filter(x ->
x.getValue().getMetadata().getAnnotations().get(KameletAnnotationsNames.KAMELET_ANNOTATION_NAMESPACE).contains(namespace))
+ return kameletModels.entrySet().stream()
+ .filter(x -> {
+ String value = annotationValue(x.getValue(),
KameletAnnotationsNames.KAMELET_ANNOTATION_NAMESPACE);
+ return value != null && value.contains(namespace);
+ })
.map(Map.Entry::getValue)
.collect(Collectors.toList());
- return collect;
}
public List<Kamelet> getKameletsByGroups(String group) {
- List<Kamelet> collect = kameletModels.entrySet().stream()
- .filter(x ->
x.getValue().getMetadata().getAnnotations().get(KameletAnnotationsNames.KAMELET_ANNOTATION_GROUP).contains(group))
+ return kameletModels.entrySet().stream()
+ .filter(x -> {
+ String value = annotationValue(x.getValue(),
KameletAnnotationsNames.KAMELET_ANNOTATION_GROUP);
+ return value != null && value.contains(group);
+ })
.map(Map.Entry::getValue)
.collect(Collectors.toList());
- return collect;
}
public Definition getKameletDefinition(String name) {
@@ -147,15 +167,13 @@ public class KameletsCatalog {
}
public List<Kamelet> getKameletByProvider(String provider) {
- List<Kamelet> collect = kameletModels.entrySet().stream()
- .filter(x ->
x.getValue().getMetadata().getAnnotations().get(KameletAnnotationsNames.KAMELET_ANNOTATION_PROVIDER).equalsIgnoreCase(provider))
+ return kameletModels.entrySet().stream()
+ .filter(x -> {
+ String value = annotationValue(x.getValue(),
KameletAnnotationsNames.KAMELET_ANNOTATION_PROVIDER);
+ return value != null && value.equalsIgnoreCase(provider);
+ })
.map(Map.Entry::getValue)
.collect(Collectors.toList());
- if (!collect.isEmpty()) {
- return collect;
- } else {
- return Collections.emptyList();
- }
}
public List<String> getKameletRequiredProperties(String name) {
diff --git
a/library/camel-kamelets-catalog/src/test/java/org/apache/camel/kamelets/catalog/KameletsCatalogTest.java
b/library/camel-kamelets-catalog/src/test/java/org/apache/camel/kamelets/catalog/KameletsCatalogTest.java
index 811085e03..aa1a67f65 100644
---
a/library/camel-kamelets-catalog/src/test/java/org/apache/camel/kamelets/catalog/KameletsCatalogTest.java
+++
b/library/camel-kamelets-catalog/src/test/java/org/apache/camel/kamelets/catalog/KameletsCatalogTest.java
@@ -126,6 +126,28 @@ public class KameletsCatalogTest {
assertTrue(c.isEmpty());
}
+ @Test
+ void testLookupMethodsContract() throws Exception {
+ // Positive case: a known label/annotation value returns a populated
list.
+
assertFalse(catalog.getKameletsByType(KameletTypeEnum.SOURCE.type()).isEmpty());
+ assertFalse(catalog.getKameletsByNamespace("AWS").isEmpty());
+ assertFalse(catalog.getKameletsByGroups("AWS S3").isEmpty());
+ assertFalse(catalog.getKameletByProvider("Apache Software
Foundation").isEmpty());
+
+ // Hardened contract: the lookups return a non-null (possibly empty)
list
+ // and never NPE on a Kamelet that lacks the queried label/annotation;
an
+ // unknown value yields an empty list.
+ assertNotNull(catalog.getKameletsByName("does-not-exist"));
+ List<Kamelet> byType = catalog.getKameletsByType("does-not-exist");
+ assertTrue(byType.isEmpty(), () -> "expected an empty list for an
unknown type but got " + byType);
+ List<Kamelet> byNamespace =
catalog.getKameletsByNamespace("does-not-exist");
+ assertTrue(byNamespace.isEmpty(), () -> "expected an empty list for an
unknown namespace but got " + byNamespace);
+ List<Kamelet> byGroup = catalog.getKameletsByGroups("does-not-exist");
+ assertTrue(byGroup.isEmpty(), () -> "expected an empty list for an
unknown group but got " + byGroup);
+ List<Kamelet> byProvider =
catalog.getKameletByProvider("does-not-exist");
+ assertTrue(byProvider.isEmpty(), () -> "expected an empty list for an
unknown provider but got " + byProvider);
+ }
+
@Test
void testGetKameletsDependencies() throws Exception {
List<String> deps = catalog.getKameletDependencies("aws-sqs-source");