diff --git a/metafix/src/main/java/org/metafacture/metafix/FixMethod.java b/metafix/src/main/java/org/metafacture/metafix/FixMethod.java index b9d7a00b..07554485 100644 --- a/metafix/src/main/java/org/metafacture/metafix/FixMethod.java +++ b/metafix/src/main/java/org/metafacture/metafix/FixMethod.java @@ -21,8 +21,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; -import java.util.HashMap; -import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.function.Function; @@ -37,7 +35,7 @@ enum FixMethod { set_field { public void apply(final Record record, final List params, final Map options) { record.remove(params.get(0)); - insert(InsertMode.REPLACE, record.temporarilyGetMap(), split(params.get(0)), params.get(1)); + insert(InsertMode.REPLACE, record, split(params.get(0)), params.get(1)); } }, set_array { @@ -45,7 +43,7 @@ public void apply(final Record record, final List params, final Map toAdd = params.subList(1, params.size()); if (key.endsWith(DOT_APPEND)) { - Metafix.addAll(record.temporarilyGetMap(), key.replace(DOT_APPEND, EMPTY), toAdd); + Metafix.addAll(record, key.replace(DOT_APPEND, EMPTY), toAdd); } else { record.put(key, toAdd); @@ -57,11 +55,15 @@ public void apply(final Record record, final List params, final Map params, final Map options) { final String key = params.get(0); final Object val = record.get(key.replace(DOT_APPEND, EMPTY)); + + final Mapping result = new Mapping(); + options.forEach(result::put); + if (key.endsWith(DOT_APPEND) && val instanceof List) { - ((List) val).add(options); + ((List) val).add(result); } else { - record.put(key, options); + record.put(key, result); } } }, @@ -69,11 +71,11 @@ public void apply(final Record record, final List params, final Map params, final Map options) { final String fieldName = params.get(0); Metafix.asList(record.get(fieldName)).forEach(recordEntry -> { - if (recordEntry instanceof Map) { + if (recordEntry instanceof Mapping) { record.remove(fieldName); - ((Map) recordEntry).entrySet().forEach(mapEntry -> { - Metafix.add(record.temporarilyGetMap(), fieldName, mapEntry.getKey()); - Metafix.add(record.temporarilyGetMap(), fieldName, mapEntry.getValue()); + ((Mapping) recordEntry).forEach((subFieldName, value) -> { + Metafix.add(record, fieldName, subFieldName); + Metafix.add(record, fieldName, value); }); } }); @@ -82,24 +84,22 @@ public void apply(final Record record, final List params, final Map params, final Map options) { final List values = Metafix.asList(record.get(params.get(0))); - final Map result = new HashMap<>(); - for (int i = 0; i < values.size(); i = i + 1) { - if (i % 2 == 1) { - result.put(values.get(i - 1).toString(), values.get(i)); - } + final Mapping result = new Mapping(); + for (int i = 1; i < values.size(); i = i + 2) { + result.put(values.get(i - 1).toString(), values.get(i)); } record.put(params.get(0), result); } }, add_field { public void apply(final Record record, final List params, final Map options) { - insert(InsertMode.APPEND, record.temporarilyGetMap(), split(params.get(0)), params.get(1)); + insert(InsertMode.APPEND, record, split(params.get(0)), params.get(1)); } }, move_field { public void apply(final Record record, final List params, final Map options) { copy(record, params); - remove(record.temporarilyGetMap(), split(params.get(0))); + remove(record, split(params.get(0))); } }, copy_field { @@ -109,7 +109,7 @@ public void apply(final Record record, final List params, final Map params, final Map options) { - params.forEach(p -> remove(record.temporarilyGetMap(), split(p))); + params.forEach(p -> remove(record, split(p))); } }, format { @@ -135,7 +135,7 @@ public void apply(final Record record, final List params, final Map result = new LinkedHashMap<>(); + final Mapping result = new Mapping(); while (groupMatcher.find()) { final String group = groupMatcher.group(1); @@ -143,11 +143,11 @@ public void apply(final Record record, final List params, final Map params, final Map params, final Map options) { final String joinChar = options.get("join_char"); - insert(InsertMode.REPLACE, record.temporarilyGetMap(), split(params.get(0)), - params.subList(1, params.size()).stream() - .filter(k -> literalString(k) || find(record.temporarilyGetMap(), split(k)) != null) - .map(k -> literalString(k) ? k.substring(1) : Metafix.asList(find(record.temporarilyGetMap(), split(k))).iterator().next()) - .map(Object::toString).collect(Collectors.joining(joinChar != null ? joinChar : " "))); + insert(InsertMode.REPLACE, record, split(params.get(0)), params.subList(1, params.size()).stream() + .filter(k -> literalString(k) || find(record, split(k)) != null) + .map(k -> literalString(k) ? k.substring(1) : Metafix.asList(find(record, split(k))).iterator().next()) + .map(Object::toString).collect(Collectors.joining(joinChar != null ? joinChar : " "))); } private boolean literalString(final String s) { @@ -247,20 +246,19 @@ private Map fileMap(final String location, final String separato private static void applyToFields(final Record record, final List params, final Function fun) { final String key = params.get(0); - final Object found = find(record.temporarilyGetMap(), split(key)); - final boolean containsKey = found != null; - if (containsKey) { - remove(record.temporarilyGetMap(), split(key)); + final Object found = find(record, split(key)); + if (found != null) { + remove(record, split(key)); new ArrayList<>(Metafix.asList(found)).forEach(old -> { if (fun != null && old != null) { final String val = fun.apply(old.toString()); - insert(InsertMode.APPEND, record.temporarilyGetMap(), split(key), val); + insert(InsertMode.APPEND, record, split(key), val); } }); } } - private static Object insert(final InsertMode mode, final Map record, final String[] keys, final String value) { + private static Object insert(final InsertMode mode, final Mapping record, final String[] keys, final String value) { final String currentKey = keys[0]; if (keys.length == 1) { mode.apply(record, currentKey, value); @@ -273,14 +271,14 @@ private static Object insert(final InsertMode mode, final Map re } @SuppressWarnings("unchecked") - private static Object insertNested(final InsertMode mode, final Map record, final String value, final String currentKey, final String[] remainingKeys) { - if (!record.containsKey(currentKey)) { - record.put(currentKey, new LinkedHashMap()); + private static Object insertNested(final InsertMode mode, final Mapping record, final String value, final String currentKey, final String[] remainingKeys) { + if (!record.containsField(currentKey)) { + record.put(currentKey, new Mapping()); } final Object nested = record.get(currentKey); final Object result; - if (nested instanceof Map) { - result = insert(mode, (Map) nested, remainingKeys, value); + if (nested instanceof Mapping) { + result = insert(mode, (Mapping) nested, remainingKeys, value); } else if (nested instanceof List) { processList(mode, value, remainingKeys, nested); @@ -293,85 +291,84 @@ else if (nested instanceof List) { } @SuppressWarnings("unchecked") - private static void processList(final InsertMode mode, final String value, final String[] remainingKeys, - final Object nested) { + private static void processList(final InsertMode mode, final String value, final String[] remainingKeys, final Object nested) { final List nestedList = (List) nested; - final Map nestedMap; + final Mapping nestedMap; switch (remainingKeys[0]) { case APPEND: - nestedMap = new LinkedHashMap<>(); + nestedMap = new Mapping(); nestedList.add(nestedMap); insert(mode, nestedMap, Arrays.copyOfRange(remainingKeys, 1, remainingKeys.length), value); break; case LAST: final Object last = nestedList.get(nestedList.size() - 1); - if (last instanceof Map) { - nestedMap = (Map) last; + if (last instanceof Mapping) { + nestedMap = (Mapping) last; insert(mode, nestedMap, Arrays.copyOfRange(remainingKeys, 1, remainingKeys.length), value); } break; default: - nestedMap = new LinkedHashMap<>(); + nestedMap = new Mapping(); nestedList.add(nestedMap); insert(mode, nestedMap, remainingKeys, value); break; } } - static Object find(final Map record, final String[] keys) { + static Object find(final Mapping record, final String[] keys) { final String currentKey = keys[0]; - if (!record.containsKey(currentKey) || keys.length == 1) { + if (!record.containsField(currentKey) || keys.length == 1) { return record.get(currentKey); } final String[] remainingKeys = Arrays.copyOfRange(keys, 1, keys.length); return findNested(record, currentKey, remainingKeys); } - private static Object findNested(final Map record, final String currentKey, final String[] remainingKeys) { + private static Object findNested(final Mapping record, final String currentKey, final String[] remainingKeys) { final Object nested = record.get(currentKey); // TODO: array of maps, like in insertNested if (nested instanceof List) { return ((List) nested).stream().map(o -> findNested(record, currentKey, remainingKeys)) .collect(Collectors.toList()); } - if (nested instanceof Map) { + if (nested instanceof Mapping) { @SuppressWarnings("unchecked") - final Object result = find((Map) nested, remainingKeys); + final Object result = find((Mapping) nested, remainingKeys); return result; } throw new IllegalStateException(NESTED + nested); } - private static Object remove(final Map record, final String[] keys) { + private static Object remove(final Mapping record, final String[] keys) { final String currentKey = keys[0]; if (keys.length == 1) { record.remove(currentKey); } - if (!record.containsKey(currentKey)) { + if (!record.containsField(currentKey)) { return record; } final String[] remainingKeys = Arrays.copyOfRange(keys, 1, keys.length); return removeNested(record, currentKey, remainingKeys); } - private static Object removeNested(final Map record, final String currentKey, final String[] remainingKeys) { + private static Object removeNested(final Mapping record, final String currentKey, final String[] remainingKeys) { final Object nested = record.get(currentKey); - if (!(nested instanceof Map)) { - throw new IllegalStateException(NESTED + nested); + if (nested instanceof Mapping) { + @SuppressWarnings("unchecked") + final Object result = remove((Mapping) nested, remainingKeys); + return result; } - @SuppressWarnings("unchecked") - final Object result = remove((Map) nested, remainingKeys); - return result; + throw new IllegalStateException(NESTED + nested); } private static void copy(final Record record, final List params) { final String oldName = params.get(0); final String newName = params.get(1); - final Object value = find(record.temporarilyGetMap(), split(oldName)); + final Object value = find(record, split(oldName)); if (value != null) { final List vs = Metafix.asList(value); for (final Object v : vs.stream().filter(v -> v != null).collect(Collectors.toList())) { - insert(InsertMode.APPEND, record.temporarilyGetMap(), split(newName), v.toString()); + insert(InsertMode.APPEND, record, split(newName), v.toString()); } } } @@ -383,18 +380,18 @@ static String[] split(final String s) { private enum InsertMode { REPLACE { @Override - void apply(final Map record, final String key, final String value) { + void apply(final Mapping record, final String key, final String value) { record.put(key, value); } }, APPEND { @Override - void apply(final Map record, final String key, final String value) { + void apply(final Mapping record, final String key, final String value) { final Object object = record.get(key); record.put(key, object == null ? value : Metafix.merged(object, value)); } }; - abstract void apply(Map record, String key, String value); + abstract void apply(Mapping record, String key, String value); } abstract void apply(Record record, List params, Map options); diff --git a/metafix/src/main/java/org/metafacture/metafix/FixPredicate.java b/metafix/src/main/java/org/metafacture/metafix/FixPredicate.java index d17b9597..b63ba956 100644 --- a/metafix/src/main/java/org/metafacture/metafix/FixPredicate.java +++ b/metafix/src/main/java/org/metafacture/metafix/FixPredicate.java @@ -58,14 +58,14 @@ public boolean test(final Record record, final FixPredicate p, final List params) { - final Object fieldValue = FixMethod.find(record.temporarilyGetMap(), FixMethod.split(params.get(0))); + final Object fieldValue = FixMethod.find(record, FixMethod.split(params.get(0))); final String valueToTest = params.get(1); return fieldValue == null || Metafix.asList(fieldValue).stream().noneMatch(p.of(valueToTest)); } }; boolean test(final Record record, final String fieldName, final Predicate> f) { - final Object value = FixMethod.find(record.temporarilyGetMap(), FixMethod.split(fieldName)); + final Object value = FixMethod.find(record, FixMethod.split(fieldName)); return value != null && f.test(Metafix.asList(value).stream()); } diff --git a/metafix/src/main/java/org/metafacture/metafix/Mapping.java b/metafix/src/main/java/org/metafacture/metafix/Mapping.java index ba846c7a..eb8dbcce 100644 --- a/metafix/src/main/java/org/metafacture/metafix/Mapping.java +++ b/metafix/src/main/java/org/metafacture/metafix/Mapping.java @@ -138,9 +138,4 @@ public String toString() { return map.toString(); } - // TODO: Replace map accesses with record operations! - public Map temporarilyGetMap() { - return map; - } - } diff --git a/metafix/src/main/java/org/metafacture/metafix/Metafix.java b/metafix/src/main/java/org/metafacture/metafix/Metafix.java index 779f8e90..010e2ae4 100644 --- a/metafix/src/main/java/org/metafacture/metafix/Metafix.java +++ b/metafix/src/main/java/org/metafacture/metafix/Metafix.java @@ -37,7 +37,6 @@ import java.util.Arrays; import java.util.Collections; import java.util.Deque; -import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -69,7 +68,7 @@ public class Metafix implements StreamPipe { private int entityCount; private StreamReceiver outputStreamReceiver; private String recordIdentifier; - private List> entities = new ArrayList<>(); + private List entities = new ArrayList<>(); public Metafix() { init(); @@ -158,12 +157,10 @@ private void emit(final Object key, final Object val) { } for (int i = 0; i < vals.size(); ++i) { final Object value = vals.get(i); - if (value instanceof Map) { - final Map nested = (Map) value; + if (value instanceof Mapping) { + final Mapping nested = (Mapping) value; outputStreamReceiver.startEntity(isMulti ? "" : key.toString()); - nested.entrySet().forEach(nestedEntry -> { - emit(nestedEntry.getKey(), nestedEntry.getValue()); - }); + nested.forEach(this::emit); outputStreamReceiver.endEntity(); } else { @@ -182,24 +179,24 @@ public void startEntity(final String name) { } ++entityCount; final Integer currentEntityIndex = entityCountStack.peek() - 1; - final Map previousEntity = currentEntityIndex < 0 || + final Mapping previousEntity = currentEntityIndex < 0 || entities.size() <= currentEntityIndex ? null : entities.get(currentEntityIndex); entityCountStack.push(Integer.valueOf(entityCount)); flattener.startEntity(name); - entities.add(currentEntity(name, previousEntity != null ? previousEntity : currentRecord.temporarilyGetMap())); + entities.add(currentEntity(name, previousEntity != null ? previousEntity : currentRecord)); } - private Map currentEntity(final String name, final Map previousEntity) { + private Mapping currentEntity(final String name, final Mapping previousEntity) { final Object existingValue = previousEntity != null ? previousEntity.get(name) : null; - final Map currentEntity; - if (existingValue != null && existingValue instanceof Map) { + final Mapping currentEntity; + if (existingValue instanceof Mapping) { @SuppressWarnings("unchecked") - final Map existingEntity = (Map) previousEntity.get(name); + final Mapping existingEntity = (Mapping) previousEntity.get(name); currentEntity = existingEntity; } else { - currentEntity = new LinkedHashMap<>(); - add(previousEntity != null ? previousEntity : currentRecord.temporarilyGetMap(), name, currentEntity); + currentEntity = new Mapping(); + add(previousEntity != null ? previousEntity : currentRecord, name, currentEntity); } return currentEntity; } @@ -214,9 +211,9 @@ public void endEntity() { public void literal(final String name, final String value) { LOG.debug("Putting '{}': '{}'", name, value); final Integer currentEntityIndex = entityCountStack.peek() - 1; - final Map currentEntity = currentEntityIndex < 0 || + final Mapping currentEntity = currentEntityIndex < 0 || entities.size() <= currentEntityIndex ? null : entities.get(currentEntityIndex); - add(currentEntity != null ? currentEntity : currentRecord.temporarilyGetMap(), name, value); + add(currentEntity != null ? currentEntity : currentRecord, name, value); // TODO: keep flattener as option? // flattener.literal(name, value); } @@ -255,36 +252,34 @@ public Record getCurrentRecord() { return currentRecord; } - static void addAll(final Map record, final String fieldName, final List values) { + static void addAll(final Mapping record, final String fieldName, final List values) { values.forEach(value -> add(record, fieldName, value)); } - static void addAll(final Map record, final Map values) { - values.entrySet().forEach(value -> add(record, value.getKey(), value.getValue())); + static void addAll(final Mapping record, final Mapping values) { + values.forEach((fieldName, value) -> add(record, fieldName, value)); } - static void add(final Map record, final String name, final Object newValue) { + static void add(final Mapping record, final String name, final Object newValue) { final Object oldValue = record.get(name); record.put(name, oldValue == null ? newValue : merged(oldValue, newValue)); } @SuppressWarnings("unchecked") static Object merged(final Object object1, final Object object2) { - if (object1 instanceof Map && object2 instanceof Map) { - ((Map) object1).putAll((Map) object2); - return object1; + if (object1 instanceof Mapping && object2 instanceof Mapping) { + final Mapping result = (Mapping) object1; + ((Mapping) object2).forEach(result::put); + return result; } final List list = asList(object1); - asList(object2).forEach(e -> { - list.add(e); - }); + asList(object2).forEach(list::add); return list; } @SuppressWarnings("unchecked") static List asList(final Object object) { - return new ArrayList<>( - object instanceof List ? (List) object : Arrays.asList(object)); + return new ArrayList<>(object instanceof List ? (List) object : Arrays.asList(object)); } } diff --git a/metafix/src/main/java/org/metafacture/metafix/RecordTransformer.java b/metafix/src/main/java/org/metafacture/metafix/RecordTransformer.java index b76b02a4..f38f4fa2 100644 --- a/metafix/src/main/java/org/metafacture/metafix/RecordTransformer.java +++ b/metafix/src/main/java/org/metafacture/metafix/RecordTransformer.java @@ -93,7 +93,7 @@ private void processBind(final Do theDo, final EList params) { if (theDo.getName().equals("list")) { // TODO impl multiple binds via FixBind enum final Map options = options(theDo.getOptions()); final Record fullRecord = record.shallowClone(); - final Object values = FixMethod.find(record.temporarilyGetMap(), FixMethod.split(options.get("path"))); + final Object values = FixMethod.find(record, FixMethod.split(options.get("path"))); Metafix.asList(values).stream().filter(val -> val != null).forEach(val -> { // for each val, bind the current record/scope/context to the given var name: @@ -104,7 +104,7 @@ record = new Record(); record.remove(options.get("var")); // and remember the things we added while bound (this probably needs some tweaking): - Metafix.addAll(fullRecord.temporarilyGetMap(), record.temporarilyGetMap()); + Metafix.addAll(fullRecord, record); }); record = fullRecord;