Skip to content

Commit

Permalink
added delegates to (de-)serialize any other properties that are not i…
Browse files Browse the repository at this point in the history
…n the property meta model
  • Loading branch information
dpnolte committed Oct 18, 2018
1 parent cc31e22 commit ef3ecbb
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,10 @@
import com.github.javaparser.metamodel.BaseNodeMetaModel;
import com.github.javaparser.metamodel.PropertyMetaModel;
import com.github.javaparser.utils.Log;
import com.github.javaparser.utils.Pair;

import javax.json.JsonArray;
import javax.json.JsonObject;
import javax.json.JsonReader;
import javax.json.JsonString;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Map;
import javax.json.*;
import java.util.*;
import java.util.stream.Collectors;

import static com.github.javaparser.ast.NodeList.toNodeList;
Expand All @@ -46,20 +42,30 @@
public class JavaParserJsonDeserializer {

public Node deserializeObject(JsonReader reader) {
return deserializeObject(reader, new HashMap<>());
}

public Node deserializeObject(JsonReader reader, Map<String, Delegate> delegates) {
Log.info("Deserializing JSON to Node.");
JsonObject jsonObject = reader.readObject();
return deserializeObject(jsonObject);
return deserializeObject(jsonObject, delegates);
}

private Node deserializeObject(JsonObject nodeJson) {
private Node deserializeObject(JsonObject nodeJson, Map<String, Delegate> delegates) {
try {
String serializedNodeType = nodeJson.getString(SERIALIZED_CLASS_KEY);
BaseNodeMetaModel nodeMetaModel = getNodeMetaModel(Class.forName(serializedNodeType))
.orElseThrow(() -> new IllegalStateException("Trying to deserialize an unknown node type: " + serializedNodeType));
Map<String, Object> parameters = new HashMap<>();
List<Pair<String, JsonValue>> jsonValuesForDelegates = new LinkedList<>();
for (String name : nodeJson.keySet()) {
if (name.equals(SERIALIZED_CLASS_KEY)) {
continue;
} else if (delegates.containsKey(name)) {
jsonValuesForDelegates.add(
new Pair<>(name, nodeJson.get(name))
);
continue;
}

PropertyMetaModel propertyMetaModel = nodeMetaModel.getAllPropertyMetaModels().stream()
Expand All @@ -68,12 +74,12 @@ private Node deserializeObject(JsonObject nodeJson) {

if (propertyMetaModel.isNodeList()) {
JsonArray nodeListJson = nodeJson.getJsonArray(name);
parameters.put(name, deserializeNodeList(nodeListJson));
parameters.put(name, deserializeNodeList(nodeListJson, delegates));
} else if (propertyMetaModel.isEnumSet()) {
JsonArray enumSetJson = nodeJson.getJsonArray(name);
parameters.put(name, deserializeEnumSet(enumSetJson));
} else if (propertyMetaModel.isNode()) {
parameters.put(name, deserializeObject(nodeJson.getJsonObject(name)));
parameters.put(name, deserializeObject(nodeJson.getJsonObject(name), delegates));
} else {
Class<?> type = propertyMetaModel.getType();
if (type == String.class) {
Expand All @@ -88,7 +94,12 @@ private Node deserializeObject(JsonObject nodeJson) {
}
}

return nodeMetaModel.construct(parameters);
Node node = nodeMetaModel.construct(parameters);
for (Pair<String, JsonValue> nameAndValue : jsonValuesForDelegates) {
delegates.get(nameAndValue.a).fromJson(nameAndValue.a, nameAndValue.b, node);
}

return node;
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
Expand All @@ -98,7 +109,11 @@ private EnumSet<?> deserializeEnumSet(JsonArray enumSetJson) {
return enumSetJson.stream().map(v -> (JsonString) v).map(s -> Modifier.valueOf(s.getString())).collect(Collectors.toCollection(() -> EnumSet.noneOf(Modifier.class)));
}

private NodeList<?> deserializeNodeList(JsonArray nodeListJson) {
return nodeListJson.stream().map(nodeJson -> deserializeObject((JsonObject) nodeJson)).collect(toNodeList());
private NodeList<?> deserializeNodeList(JsonArray nodeListJson, Map<String, Delegate> delegates) {
return nodeListJson.stream().map(nodeJson -> deserializeObject((JsonObject) nodeJson, delegates)).collect(toNodeList());
}

interface Delegate {
void fromJson(String propertyName, JsonValue jsonValue, Node node);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@

import javax.json.stream.JsonGenerator;
import java.util.EnumSet;
import java.util.LinkedList;
import java.util.List;

import static java.util.Objects.requireNonNull;

Expand All @@ -39,12 +41,16 @@ public class JavaParserJsonSerializer {
public static final String SERIALIZED_CLASS_KEY = "!";

public void serialize(Node node, JsonGenerator generator) {
serialize(node, generator, new LinkedList<>());
}

public void serialize(Node node, JsonGenerator generator, List<Delegate> delegates) {
requireNonNull(node);
Log.info("Serializing Node to JSON.");
serialize(null, node, generator);
serialize(null, node, generator, delegates);
}

private void serialize(String nodeName, Node node, JsonGenerator generator) {
private void serialize(String nodeName, Node node, JsonGenerator generator, List<Delegate> delegates) {
requireNonNull(node);
BaseNodeMetaModel nodeMetaModel = JavaParserMetaModel.getNodeMetaModel(node.getClass()).orElseThrow(() -> new IllegalStateException("Unknown Node: " + node.getClass()));

Expand All @@ -54,6 +60,9 @@ private void serialize(String nodeName, Node node, JsonGenerator generator) {
generator.writeStartObject(nodeName);
}
generator.write(SERIALIZED_CLASS_KEY, node.getClass().getName());
for (Delegate delegate : delegates) {
delegate.toJson(node, generator);
}
for (PropertyMetaModel propertyMetaModel : nodeMetaModel.getAllPropertyMetaModels()) {
String name = propertyMetaModel.getName();
Object value = propertyMetaModel.getValue(node);
Expand All @@ -62,7 +71,7 @@ private void serialize(String nodeName, Node node, JsonGenerator generator) {
NodeList<Node> list = (NodeList<Node>) value;
generator.writeStartArray(name);
for (Node n : list) {
serialize(null, n, generator);
serialize(null, n, generator, delegates);
}
generator.writeEnd();
} else if (propertyMetaModel.isEnumSet()) {
Expand All @@ -73,12 +82,16 @@ private void serialize(String nodeName, Node node, JsonGenerator generator) {
}
generator.writeEnd();
} else if (propertyMetaModel.isNode()) {
serialize(name, (Node) value, generator);
serialize(name, (Node) value, generator, delegates);
} else {
generator.write(name, value.toString());
}
}
}
generator.writeEnd();
}

interface Delegate {
void toJson(Node node, JsonGenerator generator);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,23 @@
package com.github.javaparser.serialization;

import com.github.javaparser.JavaParser;
import com.github.javaparser.Position;
import com.github.javaparser.Range;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.Node;
import com.github.javaparser.ast.expr.Expression;
import com.github.javaparser.ast.type.Type;
import org.junit.jupiter.api.Test;

import javax.json.Json;
import javax.json.JsonObject;
import javax.json.stream.JsonGenerator;

import java.io.StringReader;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import static com.github.javaparser.serialization.JavaParserJsonSerializerTest.*;
import static com.github.javaparser.utils.Utils.EOL;
Expand Down Expand Up @@ -105,6 +113,44 @@ void testPrimitiveType() {
assertEquals(type.hashCode(), deserialized.hashCode());
}

@Test
void testDelegate() {
CompilationUnit cu = JavaParser.parse("public class X{} class Z{}");
List<JavaParserJsonSerializer.Delegate> serializerDelegates = new LinkedList<>();
JavaParserJsonSerializer.Delegate rangeSerializerDelegate = (node, generator) -> {
if (node.getRange().isPresent()) {
Range range = node.getRange().get();
generator.writeStartObject("range");
generator.write("beginLine", range.begin.line);
generator.write("beginColumn", range.begin.column);
generator.write("endLine", range.end.line);
generator.write("endColumn", range.end.column);
generator.writeEnd();
}
};
serializerDelegates.add(rangeSerializerDelegate);
String serialized = serialize(cu, false, serializerDelegates);

Map<String, JavaParserJsonDeserializer.Delegate> deserializerDelegates = new HashMap<>();
JavaParserJsonDeserializer.Delegate rangeDeserializerDelegate = (propertyName, jsonValue, node) -> {
JsonObject jsonNode = (JsonObject)jsonValue;
Position begin = new Position(jsonNode.getInt("beginLine"), jsonNode.getInt("beginColumn"));
Position end = new Position(jsonNode.getInt("endLine"), jsonNode.getInt("endColumn"));
node.setRange(new Range(begin, end));
};
deserializerDelegates.put("range", rangeDeserializerDelegate);

Node deserialized = deserializer.deserializeObject(
Json.createReader(new StringReader(serialized)),
deserializerDelegates
);
Range range = deserialized.getRange().get();
assertEquals(range.begin.line, 1);
assertEquals(range.begin.line, 1);
assertEquals(range.end.line, 1);
assertEquals(range.end.column, 26);
}

/**
* Assert that "actual" equals "expected", and that any EOL characters in "actual" are correct for the platform.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
import javax.json.stream.JsonGeneratorFactory;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import static org.junit.jupiter.api.Assertions.assertEquals;
Expand All @@ -45,6 +47,9 @@ void test() {
}

static String serialize(Node node, boolean prettyPrint) {
return serialize(node, prettyPrint, new LinkedList<>());
}
static String serialize(Node node, boolean prettyPrint, List<JavaParserJsonSerializer.Delegate> delegates) {
Map<String, ?> config = new HashMap<>();
if (prettyPrint) {
config.put(JsonGenerator.PRETTY_PRINTING, null);
Expand All @@ -53,7 +58,7 @@ static String serialize(Node node, boolean prettyPrint) {
JavaParserJsonSerializer serializer = new JavaParserJsonSerializer();
StringWriter jsonWriter = new StringWriter();
try (JsonGenerator generator = generatorFactory.createGenerator(jsonWriter)) {
serializer.serialize(node, generator);
serializer.serialize(node, generator, delegates);
}
return jsonWriter.toString();
}
Expand Down

0 comments on commit ef3ecbb

Please sign in to comment.