### Question:
FeatureServiceImpl { public Feature mergeFeatures(ID targetID, Feature f1, Feature f2, MergeContext ctx) { FeatureBuilder fb = builderFactory.newFeatureBuilder(targetID); copyAttrs(f1, fb); copyAttrs(f2, fb); fb.addBundles(mergeBundles(f1, f2, ctx)); fb.addConfigurations(mergeConfigs(f1, f2, ctx)); fb.addExtensions(mergeExtensions(f1, f2, ctx)); return fb.build(); }  BuilderFactory getBuilderFactory(); Feature readFeature(Reader jsonReader); void writeFeature(Feature feature, Writer jsonWriter); Feature mergeFeatures(ID targetID, Feature f1, Feature f2, MergeContext ctx);  }### Answer:
@Test public void testMergeFeatures() throws IOException { BuilderFactory bf = Features.getBuilderFactory(); URL res1 = getClass().getResource("/features/test-feature.json"); Feature f1; try (Reader r = new InputStreamReader(res1.openStream())) { f1 = Features.readFeature(r); } URL res2 = getClass().getResource("/features/test-feature2.json"); Feature f2; try (Reader r = new InputStreamReader(res2.openStream())) { f2 = Features.readFeature(r); } MergeContext ctx = bf.newMergeContextBuilder() .bundleConflictHandler((cf1, b1, cf2, b2) -> Arrays.asList(b1, b2)) .configConflictHandler((cf1, c1, cf2, c2) -> new ConfigurationBuilderImpl(c1) .addValues(c2.getValues()).build()) .build(); ID tid = new ID("foo", "bar", "1.2.3"); Feature f3 = Features.mergeFeatures(tid, f1, f2, ctx); assertEquals(tid, f3.getID()); List<FeatureBundle> bundles = f3.getBundles(); assertEquals(5, bundles.size()); assertTrue(bundles.contains(bf.newBundleBuilder(new ID("org.slf4j", "slf4j-api", "1.7.29")).build())); assertTrue(bundles.contains(bf.newBundleBuilder(new ID("org.slf4j", "slf4j-api", "1.7.30")).build())); assertTrue(bundles.contains(bf.newBundleBuilder(new ID("org.slf4j", "slf4j-nop", "1.7.30")).build())); Map<String, FeatureConfiguration> configs = f3.getConfigurations(); assertEquals(2, configs.size()); FeatureConfiguration cfg1 = configs.get("my.factory.pid~name"); assertEquals("my.factory.pid~name", cfg1.getPid()); assertEquals("my.factory.pid", cfg1.getFactoryPid()); assertEquals(Collections.singletonMap("a.value", "yeah"), cfg1.getValues()); FeatureConfiguration cfg2 = configs.get("my.pid"); assertEquals("my.pid", cfg2.getPid()); assertNull(cfg2.getFactoryPid()); Map<String,Object> expected = new HashMap<>(); expected.put("foo", 5L); expected.put("bar", "toast"); expected.put("number:Integer", 7L); assertEquals(expected, cfg2.getValues()); }