Skip to content

Commit

Permalink
Merge pull request #106 from connorhartley/master
Browse files Browse the repository at this point in the history
Parse and write configs inside collections correctly for yaml
  • Loading branch information
TheElectronWill committed Feb 14, 2022
2 parents 54a20a6 + 80b0731 commit 1d67875
Show file tree
Hide file tree
Showing 9 changed files with 204 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@
*/
@SuppressWarnings("unchecked")
public class TransformingCollection<InternalV, ExternalV> implements Collection<ExternalV> {
private final Function<? super InternalV, ? extends ExternalV> readTransformation;
private final Function<? super ExternalV, ? extends InternalV> writeTransformation;
private final Function<Object, Object> searchTransformation;
private final Collection<InternalV> internalCollection;
protected final Function<? super InternalV, ? extends ExternalV> readTransformation;
protected final Function<? super ExternalV, ? extends InternalV> writeTransformation;
protected final Function<Object, Object> searchTransformation;
protected final Collection<InternalV> internalCollection;

public TransformingCollection(Collection<InternalV> internalCollection,
Function<? super InternalV, ? extends ExternalV> readTransformation,
Expand Down Expand Up @@ -86,20 +86,20 @@ public boolean remove(Object o) {
@Override
public boolean containsAll(Collection<?> c) {
return internalCollection.containsAll(
new TransformingCollection(c, searchTransformation, o -> o, searchTransformation));
new TransformingCollection(c, searchTransformation, o -> o, searchTransformation));
}

@Override
public boolean addAll(Collection<? extends ExternalV> c) {
return internalCollection.addAll(
new TransformingCollection(c, writeTransformation, readTransformation,
searchTransformation));
new TransformingCollection(c, writeTransformation, readTransformation,
searchTransformation));
}

@Override
public boolean removeAll(Collection<?> c) {
return internalCollection.removeAll(
new TransformingCollection(c, searchTransformation, o -> o, searchTransformation));
new TransformingCollection(c, searchTransformation, o -> o, searchTransformation));
}

@Override
Expand All @@ -111,7 +111,7 @@ public boolean removeIf(Predicate<? super ExternalV> filter) {
@Override
public boolean retainAll(Collection<?> c) {
return internalCollection.retainAll(
new TransformingCollection(c, searchTransformation, o -> o, searchTransformation));
new TransformingCollection(c, searchTransformation, o -> o, searchTransformation));
}

@Override
Expand Down Expand Up @@ -139,4 +139,19 @@ public Stream<ExternalV> parallelStream() {
public void forEach(Consumer<? super ExternalV> action) {
internalCollection.forEach(internalV -> action.accept(readTransformation.apply(internalV)));
}

@Override
public int hashCode() {
return internalCollection.hashCode();
}

@Override
public boolean equals(Object obj) {
return internalCollection.equals(obj);
}

@Override
public String toString() {
return internalCollection.toString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@
* @author TheElectronWill
* @see TransformingMap
*/
public final class TransformingIterator<InternalV, ExternalV> implements Iterator<ExternalV> {
private final Function<? super InternalV, ? extends ExternalV> readTransformation;
private final Iterator<InternalV> internalIterator;
public class TransformingIterator<InternalV, ExternalV> implements Iterator<ExternalV> {
protected final Function<? super InternalV, ? extends ExternalV> readTransformation;
protected final Iterator<InternalV> internalIterator;

public TransformingIterator(Iterator<InternalV> internalIterator,
Function<? super InternalV, ? extends ExternalV> readTransformation) {
Expand Down Expand Up @@ -44,4 +44,19 @@ public void forEachRemaining(Consumer<? super ExternalV> action) {
internalIterator.forEachRemaining(
internalV -> action.accept(readTransformation.apply(internalV)));
}

@Override
public int hashCode() {
return internalIterator.hashCode();
}

@Override
public boolean equals(Object obj) {
return internalIterator.equals(obj);
}

@Override
public String toString() {
return internalIterator.toString();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package com.electronwill.nightconfig.core.utils;

import java.util.Collection;
import java.util.List;
import java.util.ListIterator;
import java.util.function.Function;

public final class TransformingList<InternalV, ExternalV>
extends TransformingCollection<InternalV, ExternalV> implements List<ExternalV> {
public TransformingList(List<InternalV> internalList,
Function<? super InternalV, ? extends ExternalV> readTransformation,
Function<? super ExternalV, ? extends InternalV> writeTransformation,
Function<Object, Object> searchTransformation) {
super(internalList, readTransformation, writeTransformation, searchTransformation);
}

@Override
public boolean addAll(int index, Collection<? extends ExternalV> c) {
return ((List<InternalV>) internalCollection).addAll(index,
new TransformingCollection(c, writeTransformation, readTransformation, searchTransformation));
}

@Override
public ExternalV get(int index) {
return readTransformation.apply(((List<InternalV>) internalCollection).get(index));
}

@Override
public ExternalV set(int index, ExternalV element) {
return readTransformation.apply(((List<InternalV>) internalCollection).set(index, writeTransformation.apply(element)));
}

@Override
public void add(int index, ExternalV element) {
((List<InternalV>) internalCollection).add(index, writeTransformation.apply(element));
}

@Override
public ExternalV remove(int index) {
return readTransformation.apply(((List<InternalV>) internalCollection).remove(index));
}

@Override
public int indexOf(Object o) {
return ((List<InternalV>) internalCollection).indexOf(searchTransformation.apply(o));
}

@Override
public int lastIndexOf(Object o) {
return ((List<InternalV>) internalCollection).lastIndexOf(searchTransformation.apply(o));
}

@Override
public ListIterator<ExternalV> listIterator() {
return new TransformingListIterator<>(((List<InternalV>) internalCollection).listIterator(), readTransformation, writeTransformation);
}

@Override
public ListIterator<ExternalV> listIterator(int index) {
return new TransformingListIterator<>(((List<InternalV>) internalCollection).listIterator(index), readTransformation, writeTransformation);
}

@Override
public List<ExternalV> subList(int fromIndex, int toIndex) {
return new TransformingList<>(((List<InternalV>) internalCollection).subList(fromIndex, toIndex),
readTransformation, writeTransformation, searchTransformation);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package com.electronwill.nightconfig.core.utils;

import java.util.ListIterator;
import java.util.function.Function;

public final class TransformingListIterator<InternalV, ExternalV>
extends TransformingIterator<InternalV, ExternalV> implements ListIterator<ExternalV> {
private final Function<? super ExternalV, ? extends InternalV> writeTransformation;

public TransformingListIterator(ListIterator<InternalV> internalIterator,
Function<? super InternalV, ? extends ExternalV> readTransformation,
Function<? super ExternalV, ? extends InternalV> writeTransformation) {
super(internalIterator, readTransformation);
this.writeTransformation = writeTransformation;
}

@Override
public boolean hasPrevious() {
return ((ListIterator<InternalV>) internalIterator).hasPrevious();
}

@Override
public ExternalV previous() {
return readTransformation.apply(((ListIterator<InternalV>) internalIterator).previous());
}

@Override
public int nextIndex() {
return ((ListIterator<InternalV>) internalIterator).nextIndex();
}

@Override
public int previousIndex() {
return ((ListIterator<InternalV>) internalIterator).previousIndex();
}

@Override
public void set(ExternalV externalV) {
((ListIterator<InternalV>) internalIterator).set(writeTransformation.apply(externalV));
}

@Override
public void add(ExternalV externalV) {
((ListIterator<InternalV>) internalIterator).add(writeTransformation.apply(externalV));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -72,4 +72,19 @@ public Comparator<? super ExternalV> getComparator() {
.compare(writeTransformation.apply(o1),
writeTransformation.apply(o2));
}

@Override
public int hashCode() {
return internalSpliterator.hashCode();
}

@Override
public boolean equals(Object obj) {
return internalSpliterator.equals(obj);
}

@Override
public String toString() {
return internalSpliterator.toString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@
import com.electronwill.nightconfig.core.io.ConfigParser;
import com.electronwill.nightconfig.core.io.ParsingException;
import com.electronwill.nightconfig.core.io.ParsingMode;
import com.electronwill.nightconfig.core.utils.TransformingList;
import com.electronwill.nightconfig.core.utils.TransformingMap;
import org.yaml.snakeyaml.LoaderOptions;
import org.yaml.snakeyaml.Yaml;

import java.io.Reader;
import java.util.List;
import java.util.Map;

import static com.electronwill.nightconfig.core.NullObject.NULL_OBJECT;
Expand Down Expand Up @@ -70,11 +72,18 @@ private Map<String, Object> wrap(Map<String, Object> map) {
return new TransformingMap<>(map, this::wrap, v -> v, v -> v);
}

private List<Object> wrapList(List<Object> list) {
return new TransformingList<>(list, this::wrap, v -> v, v -> v);
}

private Object wrap(Object value) {
if (value instanceof Map) {
Map<String, Object> map = wrap((Map)value);
return Config.wrap(map, configFormat);
}
if (value instanceof List) {
return (List<Object>) wrapList((List)value);
}
if (value == null) {
return NULL_OBJECT;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@
import com.electronwill.nightconfig.core.UnmodifiableConfig;
import com.electronwill.nightconfig.core.io.ConfigWriter;
import com.electronwill.nightconfig.core.io.WritingException;
import com.electronwill.nightconfig.core.utils.TransformingList;
import com.electronwill.nightconfig.core.utils.TransformingMap;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.Yaml;

import java.io.Writer;
import java.util.List;
import java.util.Map;

import static com.electronwill.nightconfig.core.NullObject.NULL_OBJECT;
Expand Down Expand Up @@ -46,10 +48,17 @@ private static Map<String, Object> unwrap(UnmodifiableConfig config) {
return new TransformingMap<>(config.valueMap(), YamlWriter::unwrap, v -> v, v -> v);
}

private static List<Object> unwrapList(List<Object> list) {
return new TransformingList<>(list, YamlWriter::unwrap, v -> v, v -> v);
}

private static Object unwrap(Object value) {
if (value instanceof UnmodifiableConfig) {
return unwrap((UnmodifiableConfig)value);
}
if (value instanceof List) {
return unwrapList((List<Object>)value);
}
if (value == NULL_OBJECT) {
return null;
}
Expand Down
15 changes: 11 additions & 4 deletions yaml/src/test/java/yaml/YamlTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,16 @@

import com.electronwill.nightconfig.core.BasicTestEnum;
import com.electronwill.nightconfig.core.Config;
import com.electronwill.nightconfig.core.TestEnum;
import com.electronwill.nightconfig.core.file.FileNotFoundAction;
import com.electronwill.nightconfig.core.UnmodifiableConfig;
import com.electronwill.nightconfig.core.io.ParsingMode;
import com.electronwill.nightconfig.core.io.WritingMode;
import com.electronwill.nightconfig.yaml.YamlFormat;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.yaml.snakeyaml.TypeDescription;
import org.yaml.snakeyaml.representer.Representer;

import java.io.File;
import java.util.Arrays;
import java.util.List;

import static com.electronwill.nightconfig.core.NullObject.NULL_OBJECT;
import static com.electronwill.nightconfig.core.file.FileNotFoundAction.THROW_ERROR;
Expand All @@ -25,12 +24,18 @@ public class YamlTest {
@Test
public void testReadWrite() {
Config config = Config.inMemory();
Config config1 = Config.inMemory();
Config config2 = Config.inMemory();
config1.set("foo", "bar");
config2.set("baz", true);
config.set("null", null);
config.set("nullObject", NULL_OBJECT);
config.set("string", "this is a string");
config.set("sub.null", null);
config.set("sub.nullObject", NULL_OBJECT);
config.set("enum", BasicTestEnum.A); // complex enums doesn't appear to work with SnakeYAML
config.set("list", Arrays.asList(10, 12));
config.set("objectList", Arrays.asList(config1, config2));

System.out.println("Config: " + config);
System.out.println("classOf[sub] = " + config.get("sub").getClass());
Expand All @@ -48,6 +53,8 @@ public void testReadWrite() {
assertSame(NULL_OBJECT, parsed.valueMap().get("null"));
assertSame(NULL_OBJECT, parsed.valueMap().get("nullObject"));
assertEquals(BasicTestEnum.A, parsed.getEnum("enum", BasicTestEnum.class));
assertEquals(12, parsed.<List<Integer>>get("list").get(1));
assertEquals(Boolean.TRUE, parsed.<List<UnmodifiableConfig>>get("objectList").get(1).get("baz"));

Assertions.assertEquals(config, parsed, "Error: written != parsed");
}
Expand Down
4 changes: 4 additions & 0 deletions yaml/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,8 @@ sub: {'null': null, nullObject: null}
'null': null
string: this is a string
nullObject: null
list: [10, 12]
enum: !!com.electronwill.nightconfig.core.BasicTestEnum 'A'
objectList:
- {foo: bar}
- {baz: true}

0 comments on commit 1d67875

Please sign in to comment.