[PAN-2946] refactor normalizeKeys method (#1826)

Move the `normalizeKeys` method into JsonUtil as Retesteth will re-use it.


Signed-off-by: Adrian Sutton <adrian.sutton@consensys.net>
pull/2/head
Danno Ferrin 5 years ago committed by GitHub
parent eee210b26a
commit 68934e69a2
  1. 24
      config/src/main/java/tech/pegasys/pantheon/config/GenesisConfigFile.java
  2. 35
      config/src/main/java/tech/pegasys/pantheon/config/JsonUtil.java
  3. 39
      config/src/test/java/tech/pegasys/pantheon/config/JsonUtilTest.java

@ -13,13 +13,12 @@
package tech.pegasys.pantheon.config;
import static java.nio.charset.StandardCharsets.UTF_8;
import static tech.pegasys.pantheon.config.JsonUtil.normalizeKeys;
import java.io.IOException;
import java.util.Locale;
import java.util.Optional;
import java.util.stream.Stream;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.collect.Streams;
import com.google.common.io.Resources;
@ -133,25 +132,4 @@ public class GenesisConfigFile {
+ "'");
}
}
/* Converts all to lowercase for easier lookup since the keys in a 'genesis.json' file are assumed
* case insensitive.
*/
private static ObjectNode normalizeKeys(final ObjectNode genesis) {
final ObjectNode normalized = JsonUtil.createEmptyObjectNode();
genesis
.fields()
.forEachRemaining(
entry -> {
final String key = entry.getKey();
final JsonNode value = entry.getValue();
final String normalizedKey = key.toLowerCase(Locale.US);
if (value instanceof ObjectNode) {
normalized.set(normalizedKey, normalizeKeys((ObjectNode) value));
} else {
normalized.set(normalizedKey, value);
}
});
return normalized;
}
}

@ -13,6 +13,7 @@
package tech.pegasys.pantheon.config;
import java.io.IOException;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
import java.util.OptionalInt;
@ -28,6 +29,32 @@ import com.fasterxml.jackson.databind.node.ObjectNode;
public class JsonUtil {
/**
* Converts all the object keys (but none of the string values) to lowercase for easier lookup.
* This is useful in cases such as the 'genesis.json' file where all keys are assumed to be case
* insensitive.
*
* @param objectNode The ObjectNode to be normalized
* @return a copy of the json object with all keys in lower case.
*/
public static ObjectNode normalizeKeys(final ObjectNode objectNode) {
final ObjectNode normalized = JsonUtil.createEmptyObjectNode();
objectNode
.fields()
.forEachRemaining(
entry -> {
final String key = entry.getKey();
final JsonNode value = entry.getValue();
final String normalizedKey = key.toLowerCase(Locale.US);
if (value instanceof ObjectNode) {
normalized.set(normalizedKey, normalizeKeys((ObjectNode) value));
} else {
normalized.set(normalizedKey, value);
}
});
return normalized;
}
/**
* Get the string representation of the value at {@code key}. For example, a numeric value like 5
* will be returned as "5".
@ -120,7 +147,7 @@ public class JsonUtil {
}
public static ObjectNode createEmptyObjectNode() {
ObjectMapper mapper = getObjectMapper();
final ObjectMapper mapper = getObjectMapper();
return mapper.createObjectNode();
}
@ -140,7 +167,7 @@ public class JsonUtil {
final JsonNode jsonNode = objectMapper.readTree(jsonData);
validateType(jsonNode, JsonNodeType.OBJECT);
return (ObjectNode) jsonNode;
} catch (IOException e) {
} catch (final IOException e) {
// Reading directly from a string should not raise an IOException, just catch and rethrow
throw new RuntimeException(e);
}
@ -152,7 +179,7 @@ public class JsonUtil {
public static String getJson(final Object objectNode, final boolean prettyPrint)
throws JsonProcessingException {
ObjectMapper mapper = getObjectMapper();
final ObjectMapper mapper = getObjectMapper();
if (prettyPrint) {
return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(objectNode);
} else {
@ -209,7 +236,7 @@ public class JsonUtil {
}
private static Optional<JsonNode> getValue(final ObjectNode node, final String key) {
JsonNode jsonNode = node.get(key);
final JsonNode jsonNode = node.get(key);
if (jsonNode == null || jsonNode.isNull()) {
return Optional.empty();
}

@ -15,6 +15,8 @@ package tech.pegasys.pantheon.config;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
import java.util.OptionalInt;
@ -29,7 +31,40 @@ import com.fasterxml.jackson.databind.node.ObjectNode;
import org.junit.Test;
public class JsonUtilTest {
private ObjectMapper mapper = new ObjectMapper();
private final ObjectMapper mapper = new ObjectMapper();
@Test
public void normalizeKeys_cases() {
final List<String> cases =
List.of(
"lower",
"CAPS",
"Proper",
"camelCase",
"snake_case",
"SHOUT_CASE",
"dash-case",
"!@#$%^&*(){}[]\\|-=_+;':\",.<>/?`~");
final ObjectNode base = mapper.createObjectNode();
for (final String s : cases) {
base.put(s, s);
}
final ObjectNode normalized = JsonUtil.normalizeKeys(base);
for (final String s : cases) {
assertThat(base.get(s).asText()).isEqualTo(normalized.get(s.toLowerCase(Locale.US)).asText());
}
}
@Test
public void normalizeKeys_depth() {
final ObjectNode base = mapper.createObjectNode();
base.putObject("DEEP").putObject("deeper").put("deeperER", "DEEPEST");
final ObjectNode normalized = JsonUtil.normalizeKeys(base);
assertThat(base.get("DEEP").get("deeper").get("deeperER").asText())
.isEqualTo(normalized.get("deep").get("deeper").get("deeperer").asText());
}
@Test
public void getLong_nonExistentKey() {
@ -413,7 +448,7 @@ public class JsonUtilTest {
subMap.put("d", 2L);
map.put("subtree", subMap);
ObjectNode node = JsonUtil.objectNodeFromMap(map);
final ObjectNode node = JsonUtil.objectNodeFromMap(map);
assertThat(node.get("a").asInt()).isEqualTo(1);
assertThat(node.get("b").asInt()).isEqualTo(2);
assertThat(node.get("subtree").get("c").asText()).isEqualTo("bla");

Loading…
Cancel
Save