added traversal library
fixed bug with missing .equals method implementation on net.woggioni.worth.value.ObjectEntry fixed multithreaded testing
This commit is contained in:
@@ -16,10 +16,9 @@ scalacOptions ++= Seq(
|
|||||||
|
|
||||||
git.useGitDescribe := true
|
git.useGitDescribe := true
|
||||||
fork := true
|
fork := true
|
||||||
//javaOptions in Test += "-Dnet.woggioni.worth.value.ObjectValue.listBasedImplementation=true"
|
|
||||||
//javaOptions in Test += "-Xmx14G"
|
//javaOptions in Test += "-Xmx14G"
|
||||||
//scalafmtOnCompile := true
|
//scalafmtOnCompile := true
|
||||||
libraryDependencies += "org.projectlombok" % "lombok" % "1.18.2"
|
libraryDependencies += "org.projectlombok" % "lombok" % "1.18.8"
|
||||||
libraryDependencies += "com.novocode" % "junit-interface" % "0.11" % Test
|
libraryDependencies += "com.novocode" % "junit-interface" % "0.11" % Test
|
||||||
libraryDependencies += "com.fasterxml.jackson.core" % "jackson-databind" % "2.9.6" % Test
|
libraryDependencies += "com.fasterxml.jackson.core" % "jackson-databind" % "2.9.6" % Test
|
||||||
|
|
||||||
@@ -33,4 +32,6 @@ artifactName := { (sv: ScalaVersion, module: ModuleID, artifact: Artifact) =>
|
|||||||
|
|
||||||
enablePlugins(Antlr4Plugin)
|
enablePlugins(Antlr4Plugin)
|
||||||
antlr4Version in Antlr4 := "4.7.1"
|
antlr4Version in Antlr4 := "4.7.1"
|
||||||
antlr4PackageName in Antlr4 := Some("net.woggioni.worth.antlr")
|
antlr4PackageName in Antlr4 := Some("net.woggioni.worth.antlr")
|
||||||
|
|
||||||
|
testOptions += Tests.Argument(TestFrameworks.JUnit, "-q", "-a")
|
@@ -116,7 +116,6 @@ public class JBONDumper extends ValueDumper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SneakyThrows
|
|
||||||
protected void endObject() {
|
protected void endObject() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -134,7 +133,6 @@ public class JBONDumper extends ValueDumper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SneakyThrows
|
|
||||||
protected void endArray() {
|
protected void endArray() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -0,0 +1,42 @@
|
|||||||
|
package net.woggioni.worth.traversal;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import net.woggioni.worth.value.ArrayValue;
|
||||||
|
import net.woggioni.worth.xface.Value;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
public class ArrayStackElement extends StackElement {
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private final ArrayValue value;
|
||||||
|
|
||||||
|
private final Iterator<Value> it;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private int currentIndex;
|
||||||
|
|
||||||
|
private Value currentValue = null;
|
||||||
|
|
||||||
|
ArrayStackElement(ArrayValue av) {
|
||||||
|
this.value = av;
|
||||||
|
it = av.iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
Value current() {
|
||||||
|
return currentValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
Value next() {
|
||||||
|
currentValue = it.next();
|
||||||
|
currentIndex++;
|
||||||
|
return currentValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
boolean hasNext() {
|
||||||
|
return it.hasNext();
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,49 @@
|
|||||||
|
package net.woggioni.worth.traversal;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import net.woggioni.worth.value.ObjectValue;
|
||||||
|
import net.woggioni.worth.xface.Value;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class ObjectStackElement extends StackElement {
|
||||||
|
|
||||||
|
private final Iterator<Map.Entry<String, Value>> it;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private final ObjectValue value;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private int currentIndex;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private String currentKey;
|
||||||
|
|
||||||
|
private Value currentValue;
|
||||||
|
|
||||||
|
public ObjectStackElement(ObjectValue ov) {
|
||||||
|
value = ov;
|
||||||
|
it = ov.iterator();
|
||||||
|
currentIndex = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
Value current() {
|
||||||
|
return currentValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
Value next() {
|
||||||
|
Map.Entry<String, Value> result = it.next();
|
||||||
|
currentKey = result.getKey();
|
||||||
|
currentIndex++;
|
||||||
|
currentValue = result.getValue();
|
||||||
|
return currentValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
boolean hasNext() {
|
||||||
|
return it.hasNext();
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,9 @@
|
|||||||
|
package net.woggioni.worth.traversal;
|
||||||
|
|
||||||
|
import net.woggioni.worth.xface.Value;
|
||||||
|
|
||||||
|
abstract class StackElement {
|
||||||
|
abstract Value current();
|
||||||
|
abstract Value next();
|
||||||
|
abstract boolean hasNext();
|
||||||
|
}
|
@@ -0,0 +1,11 @@
|
|||||||
|
package net.woggioni.worth.traversal;
|
||||||
|
|
||||||
|
import net.woggioni.worth.xface.Value;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface TraversalContext {
|
||||||
|
Value getRoot();
|
||||||
|
List<StackElement> getStack();
|
||||||
|
String getPath();
|
||||||
|
}
|
14
src/main/java/net/woggioni/worth/traversal/ValueVisitor.java
Normal file
14
src/main/java/net/woggioni/worth/traversal/ValueVisitor.java
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
package net.woggioni.worth.traversal;
|
||||||
|
|
||||||
|
import net.woggioni.worth.value.*;
|
||||||
|
|
||||||
|
public interface ValueVisitor {
|
||||||
|
|
||||||
|
void visit(ObjectValue value, TraversalContext ctx);
|
||||||
|
void visit(ArrayValue value, TraversalContext ctx);
|
||||||
|
void visit(BooleanValue value, TraversalContext ctx);
|
||||||
|
void visit(StringValue value, TraversalContext ctx);
|
||||||
|
void visit(IntegerValue value, TraversalContext ctx);
|
||||||
|
void visit(FloatValue value, TraversalContext ctx);
|
||||||
|
void visit(NullValue value, TraversalContext ctx);
|
||||||
|
}
|
153
src/main/java/net/woggioni/worth/traversal/ValueWalker.java
Normal file
153
src/main/java/net/woggioni/worth/traversal/ValueWalker.java
Normal file
@@ -0,0 +1,153 @@
|
|||||||
|
package net.woggioni.worth.traversal;
|
||||||
|
|
||||||
|
import net.woggioni.worth.value.*;
|
||||||
|
import net.woggioni.worth.xface.Value;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
import static net.woggioni.worth.utils.WorthUtils.dynamicCast;
|
||||||
|
|
||||||
|
public class ValueWalker {
|
||||||
|
|
||||||
|
private Value parent;
|
||||||
|
|
||||||
|
public ValueWalker(Value root) {
|
||||||
|
parent = root;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ValueWalker get(String key) {
|
||||||
|
if(parent.type() == Value.Type.OBJECT) {
|
||||||
|
parent = parent.get(key);
|
||||||
|
} else {
|
||||||
|
parent = Value.Null;
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ValueWalker get(int index) {
|
||||||
|
if(parent.type() == Value.Type.ARRAY) {
|
||||||
|
parent = parent.get(index);
|
||||||
|
} else {
|
||||||
|
parent = Value.Null;
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Value get() {
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> Optional<T> map(Function<Value, T> callback) {
|
||||||
|
if(isPresent()) {
|
||||||
|
return Optional.of(callback.apply(parent));
|
||||||
|
} else {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> Optional<T> flatMap(Function<Value, Optional<T>> callback) {
|
||||||
|
if(isPresent()) {
|
||||||
|
return callback.apply(parent);
|
||||||
|
} else {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isPresent() {
|
||||||
|
return !isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return parent.type() == Value.Type.NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void walk(Value root, ValueVisitor visitor) {
|
||||||
|
List<StackElement> stack = new ArrayList<>();
|
||||||
|
List<StackElement> immutableStack = Collections.unmodifiableList(stack);
|
||||||
|
|
||||||
|
TraversalContext ctx = new TraversalContext() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Value getRoot() {
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<StackElement> getStack() {
|
||||||
|
return immutableStack;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPath() {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for(StackElement se : stack) {
|
||||||
|
ArrayStackElement ase;
|
||||||
|
ObjectStackElement ose;
|
||||||
|
if((ase = dynamicCast(se, ArrayStackElement.class)) != null) {
|
||||||
|
sb.append("[");
|
||||||
|
sb.append(ase.getCurrentIndex());
|
||||||
|
sb.append("]");
|
||||||
|
} else if((ose = dynamicCast(se, ObjectStackElement.class)) != null) {
|
||||||
|
sb.append("[\"");
|
||||||
|
sb.append(ose.getCurrentKey());
|
||||||
|
sb.append("\"]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ObjectValue ov;
|
||||||
|
ArrayValue av = new ArrayValue();
|
||||||
|
av.add(root);
|
||||||
|
ArrayStackElement ase = new ArrayStackElement(av);
|
||||||
|
stack.add(ase);
|
||||||
|
while(true) {
|
||||||
|
Value currentValue = stack.get(stack.size() - 1).next();
|
||||||
|
if((av = dynamicCast(currentValue, ArrayValue.class)) != null) {
|
||||||
|
ase = new ArrayStackElement(av);
|
||||||
|
stack.add(ase);
|
||||||
|
} else if((ov = dynamicCast(currentValue, ObjectValue.class)) != null) {
|
||||||
|
ObjectStackElement ose = new ObjectStackElement(ov);
|
||||||
|
stack.add(ose);
|
||||||
|
} else {
|
||||||
|
IntegerValue iv;
|
||||||
|
BooleanValue bv;
|
||||||
|
NullValue nv;
|
||||||
|
FloatValue fv;
|
||||||
|
StringValue sv;
|
||||||
|
if((iv = dynamicCast(currentValue, IntegerValue.class)) != null) {
|
||||||
|
visitor.visit(iv, ctx);
|
||||||
|
} else if((fv = dynamicCast(currentValue, FloatValue.class)) != null) {
|
||||||
|
visitor.visit(fv, ctx);
|
||||||
|
} else if((bv = dynamicCast(currentValue, BooleanValue.class)) != null) {
|
||||||
|
visitor.visit(bv, ctx);
|
||||||
|
} else if ((sv = dynamicCast(currentValue, StringValue.class)) != null) {
|
||||||
|
visitor.visit(sv, ctx);
|
||||||
|
} else if ((nv = dynamicCast(currentValue, NullValue.class)) != null) {
|
||||||
|
visitor.visit(nv, ctx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while(true) {
|
||||||
|
if(stack.size() == 1) return;
|
||||||
|
int lastIndex = stack.size() - 1;
|
||||||
|
StackElement se = stack.get(lastIndex);
|
||||||
|
if(!se.hasNext()) {
|
||||||
|
ObjectStackElement ose;
|
||||||
|
if((ase = dynamicCast(se, ArrayStackElement.class)) != null) {
|
||||||
|
visitor.visit(ase.getValue(), ctx);
|
||||||
|
} else if((ose = dynamicCast(se, ObjectStackElement.class)) != null) {
|
||||||
|
visitor.visit(ose.getValue(), ctx);
|
||||||
|
}
|
||||||
|
stack.remove(lastIndex);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -1,61 +0,0 @@
|
|||||||
package net.woggioni.worth.utils;
|
|
||||||
|
|
||||||
import net.woggioni.worth.xface.Value;
|
|
||||||
|
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.function.Function;
|
|
||||||
|
|
||||||
public class ValueWalker {
|
|
||||||
|
|
||||||
private Value parent;
|
|
||||||
|
|
||||||
public ValueWalker(Value root) {
|
|
||||||
parent = root;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ValueWalker get(String key) {
|
|
||||||
if(parent.type() == Value.Type.OBJECT) {
|
|
||||||
parent = parent.get(key);
|
|
||||||
} else {
|
|
||||||
parent = Value.Null;
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ValueWalker get(int index) {
|
|
||||||
if(parent.type() == Value.Type.ARRAY) {
|
|
||||||
parent = parent.get(index);
|
|
||||||
} else {
|
|
||||||
parent = Value.Null;
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Value get() {
|
|
||||||
return parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
public <T> Optional<T> map(Function<Value, T> callback) {
|
|
||||||
if(isPresent()) {
|
|
||||||
return Optional.of(callback.apply(parent));
|
|
||||||
} else {
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public <T> Optional<T> flatMap(Function<Value, Optional<T>> callback) {
|
|
||||||
if(isPresent()) {
|
|
||||||
return callback.apply(parent);
|
|
||||||
} else {
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isPresent() {
|
|
||||||
return !isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isEmpty() {
|
|
||||||
return parent.type() == Value.Type.NULL;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -47,6 +47,7 @@ public interface ObjectValue extends Value, Iterable<Map.Entry<String, Value>> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@EqualsAndHashCode
|
||||||
final class ObjectEntry<K, V> implements Map.Entry<K, V> {
|
final class ObjectEntry<K, V> implements Map.Entry<K, V> {
|
||||||
private final K key;
|
private final K key;
|
||||||
private V value;
|
private V value;
|
||||||
@@ -130,7 +131,7 @@ abstract class MapObjectValue implements ObjectValue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@EqualsAndHashCode
|
@EqualsAndHashCode(callSuper = true)
|
||||||
class HashMapObjectValue extends MapObjectValue {
|
class HashMapObjectValue extends MapObjectValue {
|
||||||
|
|
||||||
public HashMapObjectValue() {
|
public HashMapObjectValue() {
|
||||||
@@ -138,7 +139,7 @@ class HashMapObjectValue extends MapObjectValue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@EqualsAndHashCode
|
@EqualsAndHashCode(callSuper = true)
|
||||||
class LinkedHashMapObjectValue extends MapObjectValue {
|
class LinkedHashMapObjectValue extends MapObjectValue {
|
||||||
|
|
||||||
public LinkedHashMapObjectValue() {
|
public LinkedHashMapObjectValue() {
|
||||||
@@ -146,7 +147,7 @@ class LinkedHashMapObjectValue extends MapObjectValue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@EqualsAndHashCode
|
@EqualsAndHashCode(callSuper = true)
|
||||||
class TreeMapObjectValue extends MapObjectValue {
|
class TreeMapObjectValue extends MapObjectValue {
|
||||||
|
|
||||||
public TreeMapObjectValue() {
|
public TreeMapObjectValue() {
|
||||||
@@ -159,6 +160,7 @@ class TreeMapObjectValue extends MapObjectValue {
|
|||||||
@EqualsAndHashCode
|
@EqualsAndHashCode
|
||||||
class ListObjectValue implements ObjectValue {
|
class ListObjectValue implements ObjectValue {
|
||||||
|
|
||||||
|
@EqualsAndHashCode.Include
|
||||||
private final List<Map.Entry<String, Value>> value = new ArrayList<>();
|
private final List<Map.Entry<String, Value>> value = new ArrayList<>();
|
||||||
|
|
||||||
public ListObjectValue(Map<String, Value> map) {
|
public ListObjectValue(Map<String, Value> map) {
|
||||||
|
@@ -26,11 +26,12 @@ public class JBONTest {
|
|||||||
@Test
|
@Test
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
public void consistencyTest() {
|
public void consistencyTest() {
|
||||||
System.setProperty(ObjectValue.class.getName() + ".implementation", "TreeMap");
|
Value.Configuration cfg = Value.Configuration.builder()
|
||||||
|
.objectValueImplementation(ObjectValue.Implementation.TreeMap).build();
|
||||||
for (String testFile : testFiles) {
|
for (String testFile : testFiles) {
|
||||||
Value parsedValue;
|
Value parsedValue;
|
||||||
try(InputStream is = getTestSource(testFile)) {
|
try(InputStream is = getTestSource(testFile)) {
|
||||||
Parser parser = new JSONParser();
|
Parser parser = new JSONParser(cfg);
|
||||||
parsedValue = parser.parse(is);
|
parsedValue = parser.parse(is);
|
||||||
}
|
}
|
||||||
byte[] dumpedJBON;
|
byte[] dumpedJBON;
|
||||||
@@ -40,7 +41,7 @@ public class JBONTest {
|
|||||||
}
|
}
|
||||||
Value reParsedValue;
|
Value reParsedValue;
|
||||||
try(InputStream is = new ByteArrayInputStream(dumpedJBON)) {
|
try(InputStream is = new ByteArrayInputStream(dumpedJBON)) {
|
||||||
Parser parser = new JBONParser();
|
Parser parser = new JBONParser(cfg);
|
||||||
reParsedValue = parser.parse(is);
|
reParsedValue = parser.parse(is);
|
||||||
}
|
}
|
||||||
Assert.assertEquals(parsedValue, reParsedValue);
|
Assert.assertEquals(parsedValue, reParsedValue);
|
||||||
|
@@ -25,8 +25,8 @@ public class JSONTest {
|
|||||||
|
|
||||||
private String[] testFiles = new String[]{"/test.json", "/wordpress.json"};
|
private String[] testFiles = new String[]{"/test.json", "/wordpress.json"};
|
||||||
|
|
||||||
private InputStream getTestSource(String filename) {
|
public static InputStream getTestSource(String filename) {
|
||||||
return getClass().getResourceAsStream(filename);
|
return JSONTest.class.getResourceAsStream(filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean compareValueAndJsonNode(Value value, JsonNode jsonNode) {
|
private boolean compareValueAndJsonNode(Value value, JsonNode jsonNode) {
|
||||||
@@ -186,16 +186,17 @@ public class JSONTest {
|
|||||||
@Test
|
@Test
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
public void consistencyTest() {
|
public void consistencyTest() {
|
||||||
System.setProperty(ObjectValue.class.getName() + ".implementation", "ArrayList");
|
Value.Configuration cfg = Value.Configuration.builder()
|
||||||
|
.objectValueImplementation(ObjectValue.Implementation.ArrayList).build();
|
||||||
for (String testFile : testFiles) {
|
for (String testFile : testFiles) {
|
||||||
Parser parser = new JSONParser();
|
Parser parser = new JSONParser(cfg);
|
||||||
Value parsedValue = parser.parse(getTestSource(testFile));
|
Value parsedValue = parser.parse(getTestSource(testFile));
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
JSONDumper.newInstance().dump(parsedValue, baos);
|
JSONDumper.newInstance().dump(parsedValue, baos);
|
||||||
String dumpedJSON = new String(baos.toByteArray());
|
String dumpedJSON = new String(baos.toByteArray());
|
||||||
byte[] barray = baos.toByteArray();
|
byte[] barray = baos.toByteArray();
|
||||||
ByteArrayInputStream bais = new ByteArrayInputStream(barray);
|
ByteArrayInputStream bais = new ByteArrayInputStream(barray);
|
||||||
parser = new JSONParser();
|
parser = new JSONParser(cfg);
|
||||||
Value reParsedValue = parser.parse(bais);
|
Value reParsedValue = parser.parse(bais);
|
||||||
Assert.assertEquals(parsedValue, reParsedValue);
|
Assert.assertEquals(parsedValue, reParsedValue);
|
||||||
baos = new ByteArrayOutputStream();
|
baos = new ByteArrayOutputStream();
|
||||||
|
105
src/test/java/net/woggioni/worth/traversal/ValueWalkerTest.java
Normal file
105
src/test/java/net/woggioni/worth/traversal/ValueWalkerTest.java
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
package net.woggioni.worth.traversal;
|
||||||
|
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
import net.woggioni.worth.serialization.json.JSONParser;
|
||||||
|
import net.woggioni.worth.serialization.json.JSONTest;
|
||||||
|
import net.woggioni.worth.utils.WorthUtils;
|
||||||
|
import net.woggioni.worth.value.*;
|
||||||
|
import net.woggioni.worth.xface.Parser;
|
||||||
|
import net.woggioni.worth.xface.Value;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.io.BufferedInputStream;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
public class ValueWalkerTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@SneakyThrows
|
||||||
|
public void test() {
|
||||||
|
Value value;
|
||||||
|
try(InputStream is = new BufferedInputStream(getClass().getResourceAsStream("/test.json"))) {
|
||||||
|
Parser parser = JSONParser.newInstance();
|
||||||
|
value = parser.parse(is);
|
||||||
|
}
|
||||||
|
ValueWalker valueWalker = new ValueWalker(value);
|
||||||
|
Optional<String> text = valueWalker.get("widget").get("image").get("tags").get(1).map(Value::asString);
|
||||||
|
Assert.assertTrue(text.isPresent());
|
||||||
|
Assert.assertEquals("Amazon", text.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class TestVisitor implements ValueVisitor {
|
||||||
|
|
||||||
|
public List<Value> values = new ArrayList<>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(ObjectValue value, TraversalContext ctx) {
|
||||||
|
values.add(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(ArrayValue value, TraversalContext ctx) {
|
||||||
|
values.add(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(BooleanValue value, TraversalContext ctx) {
|
||||||
|
values.add(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(StringValue value, TraversalContext ctx) {
|
||||||
|
values.add(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(IntegerValue value, TraversalContext ctx) {
|
||||||
|
values.add(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(FloatValue value, TraversalContext ctx) {
|
||||||
|
values.add(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visit(NullValue value, TraversalContext ctx) {
|
||||||
|
values.add(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void walk(List<Value> result, Value value) {
|
||||||
|
ObjectValue ov;
|
||||||
|
ArrayValue av;
|
||||||
|
if((av = WorthUtils.dynamicCast(value, ArrayValue.class)) != null) {
|
||||||
|
for(Value v : av) {
|
||||||
|
walk(result, v);
|
||||||
|
}
|
||||||
|
} else if((ov = WorthUtils.dynamicCast(value, ObjectValue.class)) != null) {
|
||||||
|
for(Map.Entry<String, Value> entry : ov) {
|
||||||
|
walk(result, entry.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result.add(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Value> recursiveWalk(Value root) {
|
||||||
|
List<Value> result = new ArrayList<>();
|
||||||
|
walk(result, root);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testWalk() {
|
||||||
|
Value v = JSONParser.newInstance().parse(JSONTest.getTestSource("/test.json"));
|
||||||
|
TestVisitor visitor = new TestVisitor();
|
||||||
|
ValueWalker.walk(v, visitor);
|
||||||
|
Assert.assertFalse(visitor.values.isEmpty());
|
||||||
|
Assert.assertEquals(recursiveWalk(v), visitor.values);
|
||||||
|
}
|
||||||
|
}
|
@@ -1,29 +0,0 @@
|
|||||||
package net.woggioni.worth.utils;
|
|
||||||
|
|
||||||
import lombok.SneakyThrows;
|
|
||||||
import net.woggioni.worth.serialization.json.JSONParser;
|
|
||||||
import net.woggioni.worth.xface.Parser;
|
|
||||||
import net.woggioni.worth.xface.Value;
|
|
||||||
import org.junit.Assert;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import java.io.BufferedInputStream;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
public class ValueWalkerTest {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@SneakyThrows
|
|
||||||
public void test() {
|
|
||||||
Value value;
|
|
||||||
try(InputStream is = new BufferedInputStream(getClass().getResourceAsStream("/test.json"))) {
|
|
||||||
Parser parser = JSONParser.newInstance();
|
|
||||||
value = parser.parse(is);
|
|
||||||
}
|
|
||||||
ValueWalker valueWalker = new ValueWalker(value);
|
|
||||||
Optional<String> text = valueWalker.get("widget").get("image").get("tags").get(1).map(Value::asString);
|
|
||||||
Assert.assertTrue(text.isPresent());
|
|
||||||
Assert.assertEquals("Amazon", text.get());
|
|
||||||
}
|
|
||||||
}
|
|
@@ -23,10 +23,8 @@ public class ObjectValueImplementationTest {
|
|||||||
public void test() {
|
public void test() {
|
||||||
List<Tuple2<ObjectValue.Implementation, Class<? extends ObjectValue>>> mapping =
|
List<Tuple2<ObjectValue.Implementation, Class<? extends ObjectValue>>> mapping =
|
||||||
getImplementationMapping();
|
getImplementationMapping();
|
||||||
System.setProperty(ObjectValue.class.getName() + ".implementation",
|
|
||||||
ObjectValue.Implementation.ArrayList.toString());
|
|
||||||
ObjectValue.Implementation expectedImplementation =
|
ObjectValue.Implementation expectedImplementation =
|
||||||
ObjectValue.Implementation.valueOf(System.getProperty(ObjectValue.class.getName() + ".implementation"));
|
ObjectValue.Implementation.valueOf(System.getProperty(ObjectValue.class.getName() + ".implementation", "TreeMap"));
|
||||||
Class<? extends ObjectValue> expectedClass =
|
Class<? extends ObjectValue> expectedClass =
|
||||||
mapping.stream().filter(t -> t._1 == expectedImplementation).findFirst().get()._2;
|
mapping.stream().filter(t -> t._1 == expectedImplementation).findFirst().get()._2;
|
||||||
ObjectValue obj = ObjectValue.newInstance();
|
ObjectValue obj = ObjectValue.newInstance();
|
||||||
|
@@ -6,7 +6,7 @@
|
|||||||
"title": "Sample Konfabulator Widget",
|
"title": "Sample Konfabulator Widget",
|
||||||
"name": "main_window",
|
"name": "main_window",
|
||||||
"width": 500,
|
"width": 500,
|
||||||
"height": 500
|
"height": 501
|
||||||
},
|
},
|
||||||
"image": {
|
"image": {
|
||||||
"src": "Images/Sun.png",
|
"src": "Images/Sun.png",
|
||||||
|
Reference in New Issue
Block a user