Skip to content

Commit

Permalink
Implement DataSource's new methods: hasList, hasNested, getListOf, an…
Browse files Browse the repository at this point in the history
…d toMap

Some methods have been added in Embulk SPI's DataSource: embulk/embulk#1534

It implements them in embulk-util-config's DataSourceImpl.
  • Loading branch information
dmikurube committed Oct 27, 2023
1 parent e9ec2f6 commit a44173b
Showing 1 changed file with 92 additions and 3 deletions.
95 changes: 92 additions & 3 deletions src/main/java/org/embulk/util/config/DataSourceImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.embulk.config.ConfigDiff;
Expand Down Expand Up @@ -63,6 +64,22 @@ public boolean has(final String attrName) {
return this.data.has(attrName);
}

@Override
public boolean hasList(final String attrName) {
if (!this.data.has(attrName)) {
return false;
}
return this.data.get(attrName).isArray();
}

@Override
public boolean hasNested(final String attrName) {
if (!this.data.has(attrName)) {
return false;
}
return this.data.get(attrName).isObject();
}

@Override
public <E> E get(final Class<E> type, final String attrName) {
final JsonNode json = this.data.get(attrName);
Expand All @@ -89,6 +106,28 @@ public <E> E get(final Class<E> type, final String attrName, final E defaultValu
}
}

@Override
public <E> List<E> getListOf(final Class<E> type, final String attrName) {
final JsonNode json = this.data.get(attrName);
if (json == null) {
throw new ConfigException("Attribute " + attrName + " is required but not set.");
}
if (!json.isArray()) {
throw new ConfigException("Attribute " + attrName + " must be an array.");
}

final ArrayList<E> list = new ArrayList<>();
for (final JsonNode element : json) { // |json| should be ArrayNode.
try {
list.add(this.objectMapper.readValue(element.traverse(), type));
} catch (final IOException ex) {
throw new ConfigException(ex);
}
}

return Collections.unmodifiableList(list);
}

@Override
public DataSourceImpl getNested(final String attrName) {
final JsonNode json = this.data.get(attrName);
Expand Down Expand Up @@ -237,10 +276,9 @@ public DataSourceImpl merge(final DataSource other) {
/**
* Implements {@code DataSource#toJson} for Embulk v0.10.3+.
*
* <p>Embulk v0.10.2 or earlier does not have {@code DataSource#toJson} -- it should not {@code @Override} for the time being.
* <p>Embulk v0.10.2 or earlier does not have {@code DataSource#toJson}.
*/
// TODO: Enable @Override after most plugins start using embulk-util-config.
// @Override
@Override
public String toJson() {
try {
return this.objectMapper.writeValueAsString(this.data);
Expand All @@ -249,6 +287,16 @@ public String toJson() {
}
}

/**
* Implements {@code DataSource#toMap} for Embulk v0.10.41+.
*
* <p>Embulk v0.10.40 or earlier does not have {@code DataSource#toMap}.
*/
@Override
public Map<String, Object> toMap() {
return nodeToMap(this.data);
}

/**
* Implemented for compatibility with older {@code ConfigSource#loadConfig}.
*/
Expand Down Expand Up @@ -406,6 +454,47 @@ private static void mergeJsonArray(final ArrayNode src, final ArrayNode other) {
}
}

private static Map<String, Object> nodeToMap(final ObjectNode object) {
final LinkedHashMap<String, Object> map = new LinkedHashMap<>();
for (final Map.Entry<String, JsonNode> field : (Iterable<Map.Entry<String, JsonNode>>) () -> object.fields()) {
map.put(field.getKey(), nodeToJavaObject(field.getValue()));
}
return Collections.unmodifiableMap(map);
}

private static List<Object> nodeToList(final ArrayNode array) {
final ArrayList<Object> list = new ArrayList<>();
for (final JsonNode element : (Iterable<JsonNode>) () -> array.elements()) {
list.add(nodeToJavaObject(element));
}
return Collections.unmodifiableList(list);
}

private static Object nodeToJavaObject(final JsonNode json) {
switch (json.getNodeType()) {
case ARRAY:
return nodeToList((ArrayNode) json);
case BINARY:
return json.asText();
case BOOLEAN:
return json.booleanValue();
case MISSING:
throw new ConfigException("Unexpected JSON node type MISSING in DataSouce.");
case NULL:
return null; // LinkedHashMap accepts null as a value.
case NUMBER:
return json.numberValue();
case OBJECT:
return nodeToMap((ObjectNode) json);
case POJO:
throw new ConfigException("Unexpected JSON node type POJO in DataSouce.");
case STRING:
return json.asText();
default:
throw new ConfigException("Unknown JSON node type in DataSouce.");
}
}

private final ObjectNode data;
private final ObjectMapper objectMapper;
}

0 comments on commit a44173b

Please sign in to comment.