diff --git a/.github/workflows/maven-ci.yml b/.github/workflows/maven-ci.yml
index c9599684d1..9218fb9923 100644
--- a/.github/workflows/maven-ci.yml
+++ b/.github/workflows/maven-ci.yml
@@ -86,7 +86,11 @@ jobs:
run: mvn -B -V -Dstyle.color=always --file webconsole/pom.xml clean install verify
- name: Felix Framework
if: steps.changes.outputs.framework == 'true'
- run: mvn -B -V -Dstyle.color=always --file framework/pom.xml clean verify
+ # install, not verify: the TCK below is a separate Maven invocation and resolves
+ # the framework from the repository, so without installing it silently tests
+ # whatever org.apache.felix.framework is published rather than the build under
+ # test.
+ run: mvn -B -V -Dstyle.color=always --file framework/pom.xml clean install
- name: OSGi-TCK Framework
if: steps.changes.outputs.framework == 'true'
run: mvn -B -V -Dstyle.color=always --file framework.tck/pom.xml clean verify
diff --git a/framework.tck/pom.xml b/framework.tck/pom.xml
index 35cd65a10d..b0369c0279 100644
--- a/framework.tck/pom.xml
+++ b/framework.tck/pom.xml
@@ -105,7 +105,7 @@
net.bytebuddy
byte-buddy
- 1.17.5
+ 1.18.12
test
@@ -120,12 +120,6 @@
4.13.2_1
test
-
- org.junit.platform
- junit-platform-launcher
- 1.12.1
- test
-
org.junit.platform
junit-platform-engine
diff --git a/framework.tck/tck.bndrun b/framework.tck/tck.bndrun
index 541ec5ddb6..72a7a22274 100644
--- a/framework.tck/tck.bndrun
+++ b/framework.tck/tck.bndrun
@@ -30,7 +30,7 @@
junit-platform-engine;version='[1.12.1,1.12.2)',\
org.opentest4j;version='[1.3.0,1.3.1)',\
junit-platform-launcher;version='[1.12.1,1.12.2)',\
- assertj-core;version='[3.27.3,3.27.4)',\
+ assertj-core;version='[3.27.7,3.27.8)',\
biz.aQute.junit;version='[6.4.1,6.4.2)',\
junit-vintage-engine;version='[5.7.1,5.7.2)',\
- net.bytebuddy.byte-buddy;version='[1.17.5,1.17.6)'
\ No newline at end of file
+ net.bytebuddy.byte-buddy;version='[1.18.12,1.18.13)'
\ No newline at end of file
diff --git a/framework/src/main/java/org/apache/felix/framework/FilterImpl.java b/framework/src/main/java/org/apache/felix/framework/FilterImpl.java
index 2dddad0e25..5ff4982215 100644
--- a/framework/src/main/java/org/apache/felix/framework/FilterImpl.java
+++ b/framework/src/main/java/org/apache/felix/framework/FilterImpl.java
@@ -104,13 +104,11 @@ static class WrapperCapability extends BundleCapabilityImpl
{
private final Map m_map;
+ @SuppressWarnings("unchecked")
public WrapperCapability(Map map)
{
super(null, null, Collections.emptyMap(), Collections.emptyMap());
- m_map = Collections.emptyMap();
- if(map != null ) {
- }
- m_map.putAll(map);
+ m_map = (map == null) ? Collections.emptyMap() : (Map) map;
}
public WrapperCapability(Dictionary dict, boolean caseSensitive)
@@ -122,7 +120,14 @@ public WrapperCapability(Dictionary dict, boolean caseSensitive)
public WrapperCapability(ServiceReference> sr)
{
super(null, null, Collections.emptyMap(), Collections.emptyMap());
- m_map = new DictionaryToMap(sr.getProperties(), false);
+ // Read the properties one by one rather than via getProperties(): that
+ // method was only added in OSGi Core 1.10 and is not implemented by every
+ // ServiceReference, whereas getPropertyKeys()/getProperty() always are.
+ m_map = new StringMap();
+ for (String key : sr.getPropertyKeys())
+ {
+ m_map.put(key, sr.getProperty(key));
+ }
}
@Override
diff --git a/framework/src/test/java/org/apache/felix/framework/FilterTest.java b/framework/src/test/java/org/apache/felix/framework/FilterTest.java
index 6397ce85b9..e1746267e1 100644
--- a/framework/src/test/java/org/apache/felix/framework/FilterTest.java
+++ b/framework/src/test/java/org/apache/felix/framework/FilterTest.java
@@ -23,10 +23,12 @@
import java.util.Collection;
import java.util.Collections;
import java.util.Dictionary;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.LinkedList;
import java.util.List;
+import java.util.Map;
import java.util.Set;
import org.junit.jupiter.api.Test;
@@ -104,4 +106,36 @@ private static Dictionary createTestDict(Object o)
return dictionary;
}
+ /**
+ * Filter.matches(Map) used to throw UnsupportedOperationException for any
+ * non-empty map, because WrapperCapability assigned an immutable empty map and
+ * then called putAll on it. See FELIX-6759 discussion; regression from
+ * 466eb93f1c.
+ */
+ @Test
+ void matchesNonEmptyMap() throws InvalidSyntaxException
+ {
+ Filter filter = new FilterImpl("(one=one-value)");
+
+ Map map = new HashMap<>();
+ map.put("one", "one-value");
+
+ assertThat(filter.matches(map)).isTrue();
+ assertThat(filter.matches(Collections.singletonMap("one", "other-value"))).isFalse();
+ }
+
+ /**
+ * The same constructor threw NullPointerException for a null map, where it used
+ * to fall back to an empty one.
+ */
+ @Test
+ void matchesEmptyAndUnmodifiableMap() throws InvalidSyntaxException
+ {
+ Filter filter = new FilterImpl("(one=one-value)");
+
+ assertThat(filter.matches(Collections.emptyMap())).isFalse();
+ assertThat(filter.matches(
+ Collections.unmodifiableMap(Collections.singletonMap("one", (Object) "one-value")))).isTrue();
+ }
+
}