Skip to content

Commit

Permalink
Config now supports merging of objects and lists (#2448)
Browse files Browse the repository at this point in the history
Signed-off-by: David Kral <david.k.kral@oracle.com>
  • Loading branch information
Verdent committed Oct 15, 2020
1 parent 1cb9fbd commit 80909a0
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 41 deletions.
26 changes: 20 additions & 6 deletions config/config/src/main/java/io/helidon/config/ObjectNodeImpl.java
Expand Up @@ -20,14 +20,13 @@
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;

import io.helidon.config.AbstractNodeBuilderImpl.MergingKey;
import io.helidon.config.spi.ConfigNode;
import io.helidon.config.spi.ConfigNode.ObjectNode;

import static io.helidon.config.AbstractNodeBuilderImpl.formatFrom;

/**
* Implements {@link ObjectNode}.
*/
Expand Down Expand Up @@ -98,10 +97,7 @@ public MergeableNode merge(MergeableNode node) {
case OBJECT:
return mergeWithObjectNode((ObjectNodeImpl) node);
case LIST:
throw new ConfigException(
String.format("Cannot merge a LIST node%s with an OBJECT node%s.",
formatFrom(((ListNodeImpl) node).description()),
formatFrom(description)));
return mergeWithListNode((ListNodeImpl) node);
case VALUE:
return mergeWithValueNode((ValueNodeImpl) node);
default:
Expand All @@ -126,6 +122,24 @@ private MergeableNode mergeWithObjectNode(ObjectNodeImpl node) {
return builder.build();
}

private MergeableNode mergeWithListNode(ListNodeImpl node) {
final ObjectNodeBuilderImpl builder = ObjectNodeBuilderImpl.create(members, resolveTokenFunction);

if (node.hasValue()) {
builder.value(node.value());
} else if (hasValue()) {
builder.value(value);
}

AtomicInteger index = new AtomicInteger(0);
node.forEach(configNode -> {
int i = index.getAndIncrement();
builder.merge(String.valueOf(i), (MergeableNode) configNode);
});

return builder.build();
}

@Override
public String toString() {
if (null == value) {
Expand Down
Expand Up @@ -195,26 +195,25 @@ public void testMergeListToList() {

@Test
public void testMergeListToObjectWithNonNumberKey() {
ConfigException ex = assertThrows(ConfigException.class, () -> {
new ObjectNodeBuilderImpl()
.addValue("top1.prop1.sub1", "2")
.addList("top1.prop1", ListNode.builder().addValue("1").build())
.build();
});
assertThat(ex.getMessage(),
stringContainsInOrder(List.of("top1", "prop1", "merge", "LIST", "OBJECT")));
ObjectNode rootNode = new ObjectNodeBuilderImpl()
.addValue("top1.prop1.sub1", "2")
.addList("top1.prop1", ListNode.builder().addValue("1").build())
.build();
ObjectNode listNode = (ObjectNode) ((ObjectNode) rootNode.get("top1")).get("prop1");
assertThat(listNode.entrySet(), hasSize(2));
assertThat(listNode.get("0"), valueNode("1"));
assertThat(listNode.get("sub1"), valueNode("2"));
}

@Test
public void testMergeListToObjectWithNumberKey() {
ConfigException ex = assertThrows(ConfigException.class, () -> {
new ObjectNodeBuilderImpl()
.addValue("top1.prop1.0", "2")
.addList("top1.prop1", ListNode.builder().addValue("1").build())
.build();
});
assertThat(ex.getMessage(),
stringContainsInOrder(List.of("top1", "prop1", "merge", "LIST", "OBJECT")));
ObjectNode rootNode = new ObjectNodeBuilderImpl()
.addValue("top1.prop1.0", "2")
.addList("top1.prop1", ListNode.builder().addValue("1").build())
.build();
ObjectNode listNode = (ObjectNode) ((ObjectNode) rootNode.get("top1")).get("prop1");
assertThat(listNode.entrySet(), hasSize(1));
assertThat(listNode.get("0"), valueNode("1"));
}

@Test
Expand Down
Expand Up @@ -192,29 +192,28 @@ public void testMergeListToList() {

@Test
public void testMergeListToObjectWithNonNumberKey() {
ConfigException ex = assertThrows(ConfigException.class, () -> {
mergeLoads(
ObjectNode.builder().addList("top1.prop1", ListNode.builder()
.addValue("1").build())
.build(),
ObjectNode.builder().addValue("top1.prop1.sub1", "2").build());
});
assertThat(ex.getMessage(),
stringContainsInOrder(List.of("top1", "prop1", "merge", "LIST", "OBJECT")));
ObjectNode rootNode = mergeLoads(
ObjectNode.builder().addList("top1.prop1", ListNode.builder()
.addValue("1").build())
.build(),
ObjectNode.builder().addValue("top1.prop1.sub1", "2").build());
ObjectNode listNode = (ObjectNode) ((ObjectNode) rootNode.get("top1")).get("prop1");
assertThat(listNode.entrySet(), hasSize(2));
assertThat(listNode.get("0"), valueNode("1"));
assertThat(listNode.get("sub1"), valueNode("2"));
}

@Test
public void testMergeListToObjectWithNumberKey() {
ConfigException ex = assertThrows(ConfigException.class, () -> {
mergeLoads(
ObjectNode.builder()
.addList("top1.prop1", ListNode.builder()
.addValue("1").build())
.build(),
ObjectNode.builder().addValue("top1.prop1.0", "2").build());
});
assertThat(ex.getMessage(),
stringContainsInOrder(List.of("top1", "prop1", "merge", "LIST", "OBJECT")));
ObjectNode rootNode = mergeLoads(
ObjectNode.builder()
.addList("top1.prop1", ListNode.builder()
.addValue("1").build())
.build(),
ObjectNode.builder().addValue("top1.prop1.0", "2").build());
ObjectNode listNode = (ObjectNode) ((ObjectNode) rootNode.get("top1")).get("prop1");
assertThat(listNode.entrySet(), hasSize(1));
assertThat(listNode.get("0"), valueNode("1"));
}

@Test
Expand Down

0 comments on commit 80909a0

Please sign in to comment.