aboutsummaryrefslogtreecommitdiff
path: root/javaparser-core-serialization
diff options
context:
space:
mode:
authorEugene Susla <eugenesusla@google.com>2019-07-31 15:12:54 -0700
committerEugene Susla <eugenesusla@google.com>2019-07-31 15:12:54 -0700
commit1410e008c8ea196afec98d7766e6dca5c9d555b4 (patch)
tree68586f4fd910c3b08a9608d7be5e186c9df572c6 /javaparser-core-serialization
parent1b2211eaf2fa78358abe0b16f82ccf0b689aa56a (diff)
downloadjavaparser-1410e008c8ea196afec98d7766e6dca5c9d555b4.tar.gz
Pull commits from upstream for java 11 compatibility!
Change-Id: I27826ba60af5c54848e2eae40930d8fb8a302919
Diffstat (limited to 'javaparser-core-serialization')
-rw-r--r--javaparser-core-serialization/pom.xml71
-rw-r--r--javaparser-core-serialization/src/main/java/com/github/javaparser/serialization/JavaParserJsonDeserializer.java202
-rw-r--r--javaparser-core-serialization/src/main/java/com/github/javaparser/serialization/JavaParserJsonSerializer.java203
-rw-r--r--javaparser-core-serialization/src/test/java/com/github/javaparser/serialization/JavaParserJsonDeserializerTest.java221
-rw-r--r--javaparser-core-serialization/src/test/java/com/github/javaparser/serialization/JavaParserJsonSerializerTest.java60
5 files changed, 757 insertions, 0 deletions
diff --git a/javaparser-core-serialization/pom.xml b/javaparser-core-serialization/pom.xml
new file mode 100644
index 000000000..23e7655b2
--- /dev/null
+++ b/javaparser-core-serialization/pom.xml
@@ -0,0 +1,71 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <parent>
+ <artifactId>javaparser-parent</artifactId>
+ <groupId>com.github.javaparser</groupId>
+ <version>3.14.10-SNAPSHOT</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>javaparser-core-serialization</artifactId>
+ <description>Serializers for the JavaParser AST.</description>
+
+ <licenses>
+ <license>
+ <name>GNU Lesser General Public License</name>
+ <url>http://www.gnu.org/licenses/lgpl-3.0.html</url>
+ <distribution>repo</distribution>
+ </license>
+ <license>
+ <name>Apache License, Version 2.0</name>
+ <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
+ <distribution>repo</distribution>
+ <comments>A business-friendly OSS license</comments>
+ </license>
+ </licenses>
+
+ <properties>
+ <java.version>1.8</java.version>
+ <build.timestamp>${maven.build.timestamp}</build.timestamp>
+ </properties>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-jar-plugin</artifactId>
+ <configuration>
+ <archive>
+ <manifestEntries>
+ <Automatic-Module-Name>com.github.javaparser.core.serialization</Automatic-Module-Name>
+ </manifestEntries>
+ </archive>
+ </configuration>
+ </plugin>
+
+ </plugins>
+ </build>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.junit.jupiter</groupId>
+ <artifactId>junit-jupiter-engine</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.github.javaparser</groupId>
+ <artifactId>javaparser-core</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>javax.json</groupId>
+ <artifactId>javax.json-api</artifactId>
+ <version>1.1.4</version>
+ </dependency>
+ <dependency>
+ <groupId>org.glassfish</groupId>
+ <artifactId>javax.json</artifactId>
+ <version>1.1.4</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+</project>
diff --git a/javaparser-core-serialization/src/main/java/com/github/javaparser/serialization/JavaParserJsonDeserializer.java b/javaparser-core-serialization/src/main/java/com/github/javaparser/serialization/JavaParserJsonDeserializer.java
new file mode 100644
index 000000000..d77e127ae
--- /dev/null
+++ b/javaparser-core-serialization/src/main/java/com/github/javaparser/serialization/JavaParserJsonDeserializer.java
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2007-2010 Júlio Vilmar Gesser.
+ * Copyright (C) 2011, 2013-2018 The JavaParser Team.
+ *
+ * This file is part of JavaParser.
+ *
+ * JavaParser can be used either under the terms of
+ * a) the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * b) the terms of the Apache License
+ *
+ * You should have received a copy of both licenses in LICENCE.LGPL and
+ * LICENCE.APACHE. Please refer to those files for details.
+ *
+ * JavaParser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ */
+package com.github.javaparser.serialization;
+
+import com.github.javaparser.*;
+import com.github.javaparser.ast.CompilationUnit;
+import com.github.javaparser.ast.Node;
+import com.github.javaparser.ast.NodeList;
+import com.github.javaparser.ast.comments.Comment;
+import com.github.javaparser.metamodel.BaseNodeMetaModel;
+import com.github.javaparser.metamodel.PropertyMetaModel;
+import com.github.javaparser.utils.Log;
+
+import javax.json.*;
+import java.util.*;
+
+import static com.github.javaparser.ast.NodeList.toNodeList;
+import static com.github.javaparser.metamodel.JavaParserMetaModel.getNodeMetaModel;
+import static com.github.javaparser.serialization.JavaParserJsonSerializer.*;
+
+/**
+ * Deserializes the JSON file that was built by {@link JavaParserJsonSerializer}.
+ */
+public class JavaParserJsonDeserializer {
+ /**
+ * Deserializes json, contained by JsonReader, into AST node.
+ * The root node and all its child nodes will be deserialized.
+ * @param reader json-p reader (object-level reader, <a href="https://javaee.github.io/jsonp/">see their docs</a>)
+ * @return the root level deserialized node
+ */
+ public Node deserializeObject(JsonReader reader) {
+ Log.info("Deserializing JSON to Node.");
+ JsonObject jsonObject = reader.readObject();
+ return deserializeObject(jsonObject);
+ }
+
+ /**
+ * Recursive depth-first deserializing method that creates a Node instance from JsonObject.
+ *
+ * @param nodeJson json object at current level containg values as properties
+ * @return deserialized node including all children.
+ * @implNote the Node instance will be constructed by the properties defined in the meta model.
+ * Non meta properties will be set after Node is instantiated.
+ * @implNote comment is included in the propertyKey meta model, but not set when constructing the Node instance.
+ * That is, comment is not included in the constructor propertyKey list, and therefore needs to be set
+ * after constructing the node.
+ * See {@link com.github.javaparser.metamodel.BaseNodeMetaModel#construct(Map)} how the node is contructed
+ */
+ private Node deserializeObject(JsonObject nodeJson) {
+ try {
+ String serializedNodeType = nodeJson.getString(JsonNode.CLASS.propertyKey);
+ BaseNodeMetaModel nodeMetaModel = getNodeMetaModel(Class.forName(serializedNodeType))
+ .orElseThrow(() -> new IllegalStateException("Trying to deserialize an unknown node type: " + serializedNodeType));
+ Map<String, Object> parameters = new HashMap<>();
+ Map<String, JsonValue> deferredJsonValues = new HashMap<>();
+
+ for (String name : nodeJson.keySet()) {
+ if (name.equals(JsonNode.CLASS.propertyKey)) {
+ continue;
+ }
+
+ Optional<PropertyMetaModel> optionalPropertyMetaModel = nodeMetaModel.getAllPropertyMetaModels().stream()
+ .filter(mm -> mm.getName().equals(name))
+ .findFirst();
+ if (!optionalPropertyMetaModel.isPresent()) {
+ deferredJsonValues.put(name, nodeJson.get(name));
+ continue;
+ }
+
+ PropertyMetaModel propertyMetaModel = optionalPropertyMetaModel.get();
+ if (propertyMetaModel.isNodeList()) {
+ JsonArray nodeListJson = nodeJson.getJsonArray(name);
+ parameters.put(name, deserializeNodeList(nodeListJson));
+ } else if (propertyMetaModel.isNode()) {
+ parameters.put(name, deserializeObject(nodeJson.getJsonObject(name)));
+ } else {
+ Class<?> type = propertyMetaModel.getType();
+ if (type == String.class) {
+ parameters.put(name, nodeJson.getString(name));
+ } else if (type == boolean.class) {
+ parameters.put(name, Boolean.parseBoolean(nodeJson.getString(name)));
+ } else if (Enum.class.isAssignableFrom(type)) {
+ parameters.put(name, Enum.valueOf((Class<? extends Enum>) type, nodeJson.getString(name)));
+ } else {
+ throw new IllegalStateException("Don't know how to convert: " + type);
+ }
+ }
+ }
+
+ Node node = nodeMetaModel.construct(parameters);
+ // COMMENT is in the propertyKey meta model, but not required as constructor parameter.
+ // Set it after construction
+ if (parameters.containsKey(JsonNode.COMMENT.propertyKey)) {
+ node.setComment((Comment)parameters.get(JsonNode.COMMENT.propertyKey));
+ }
+
+ for (String name : deferredJsonValues.keySet()) {
+ if (!readNonMetaProperties(name, deferredJsonValues.get(name), node)) {
+ throw new IllegalStateException("Unknown propertyKey: " + nodeMetaModel.getQualifiedClassName() + "." + name);
+ }
+ }
+ setSymbolResolverIfCompilationUnit(node);
+
+ return node;
+ } catch (ClassNotFoundException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private NodeList<?> deserializeNodeList(JsonArray nodeListJson) {
+ return nodeListJson.stream().map(nodeJson -> deserializeObject((JsonObject) nodeJson)).collect(toNodeList());
+ }
+
+ /**
+ * Reads properties from json not included in meta model (i.e., RANGE and TOKEN_RANGE).
+ * When read, it sets the deserialized value to the node instance.
+ * @param name propertyKey name for json value
+ * @param jsonValue json value that needs to be deserialized for this propertyKey
+ * @param node instance to which the deserialized value will be set to
+ * @return true if propertyKey is read from json and set to Node instance
+ */
+ protected boolean readNonMetaProperties(String name, JsonValue jsonValue, Node node) {
+ return readRange(name, jsonValue, node)
+ || readTokenRange(name, jsonValue, node);
+ }
+
+ protected boolean readRange(String name, JsonValue jsonValue, Node node) {
+ if (name.equals(JsonNode.RANGE.propertyKey)) {
+ JsonObject jsonObject = (JsonObject)jsonValue;
+ Position begin = new Position(
+ jsonObject.getInt(JsonRange.BEGIN_LINE.propertyKey),
+ jsonObject.getInt(JsonRange.BEGIN_COLUMN.propertyKey)
+ );
+ Position end = new Position(
+ jsonObject.getInt(JsonRange.END_LINE.propertyKey),
+ jsonObject.getInt(JsonRange.END_COLUMN.propertyKey)
+ );
+ node.setRange(new Range(begin, end));
+ return true;
+ }
+ return false;
+ }
+
+ protected boolean readTokenRange(String name, JsonValue jsonValue, Node node) {
+ if (name.equals(JsonNode.TOKEN_RANGE.propertyKey)) {
+ JsonObject jsonObject = (JsonObject)jsonValue;
+ JavaToken begin = readToken(
+ JsonTokenRange.BEGIN_TOKEN.propertyKey, jsonObject
+ );
+ JavaToken end = readToken(
+ JsonTokenRange.END_TOKEN.propertyKey, jsonObject
+ );
+ node.setTokenRange(new TokenRange(begin, end));
+ return true;
+ }
+ return false;
+ }
+
+ protected JavaToken readToken(String name, JsonObject jsonObject) {
+ JsonObject tokenJson = jsonObject.getJsonObject(name);
+ return new JavaToken(
+ tokenJson.getInt(JsonToken.KIND.propertyKey),
+ tokenJson.getString(JsonToken.TEXT.propertyKey)
+ );
+ }
+
+ /**
+ * This method sets symbol resolver to Node if it is an instance of CompilationUnit
+ * and a SymbolResolver is configured in the static configuration. This is necessary to be able to resolve symbols
+ * within the cu after deserialization. Normally, when parsing java with JavaParser, the symbol resolver is injected
+ * to the cu as a data element with key SYMBOL_RESOLVER_KEY.
+ * @param node instance to which symbol resolver will be set to when instance of a Compilation Unit
+ * @see com.github.javaparser.ast.Node#SYMBOL_RESOLVER_KEY
+ * @see com.github.javaparser.ParserConfiguration#ParserConfiguration()
+ */
+ private void setSymbolResolverIfCompilationUnit(Node node) {
+ if (node instanceof CompilationUnit && StaticJavaParser.getConfiguration().getSymbolResolver().isPresent()) {
+ CompilationUnit cu = (CompilationUnit)node;
+ cu.setData(Node.SYMBOL_RESOLVER_KEY, StaticJavaParser.getConfiguration().getSymbolResolver().get());
+ }
+ }
+
+
+}
diff --git a/javaparser-core-serialization/src/main/java/com/github/javaparser/serialization/JavaParserJsonSerializer.java b/javaparser-core-serialization/src/main/java/com/github/javaparser/serialization/JavaParserJsonSerializer.java
new file mode 100644
index 000000000..743b57ddd
--- /dev/null
+++ b/javaparser-core-serialization/src/main/java/com/github/javaparser/serialization/JavaParserJsonSerializer.java
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 2007-2010 Júlio Vilmar Gesser.
+ * Copyright (C) 2011, 2013-2018 The JavaParser Team.
+ *
+ * This file is part of JavaParser.
+ *
+ * JavaParser can be used either under the terms of
+ * a) the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * b) the terms of the Apache License
+ *
+ * You should have received a copy of both licenses in LICENCE.LGPL and
+ * LICENCE.APACHE. Please refer to those files for details.
+ *
+ * JavaParser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ */
+package com.github.javaparser.serialization;
+
+import com.github.javaparser.JavaToken;
+import com.github.javaparser.Range;
+import com.github.javaparser.TokenRange;
+import com.github.javaparser.ast.Node;
+import com.github.javaparser.ast.NodeList;
+import com.github.javaparser.metamodel.BaseNodeMetaModel;
+import com.github.javaparser.metamodel.JavaParserMetaModel;
+import com.github.javaparser.metamodel.PropertyMetaModel;
+import com.github.javaparser.utils.Log;
+
+import javax.json.stream.JsonGenerator;
+
+import static com.github.javaparser.utils.Utils.decapitalize;
+import static java.util.Objects.requireNonNull;
+
+/**
+ * Serializes an AST or a partial AST to JSON.
+ */
+public class JavaParserJsonSerializer {
+
+ /**
+ * Serializes node and all its children into json. Any node siblings will be ignored.
+ *
+ * @param node the node that will be the root level json object
+ * @param generator the json-p generator for writing the json
+ * @see <a href="https://javaee.github.io/jsonp/">json-p</a>
+ */
+ public void serialize(Node node, JsonGenerator generator) {
+ requireNonNull(node);
+ Log.info("Serializing Node to JSON.");
+ try {
+ serialize(null, node, generator);
+ } finally {
+ generator.close();
+ }
+ }
+
+ /**
+ * Recursive depth-first method that serializes nodes into json
+ *
+ * @param nodeName nullable String. If null, it is the root object, otherwise it is the property key for the object
+ * @param node the current node to be serialized
+ * @param generator the json-p generator for writing the json
+ */
+
+ private void serialize(String nodeName, Node node, JsonGenerator generator) {
+ requireNonNull(node);
+ BaseNodeMetaModel nodeMetaModel = JavaParserMetaModel.getNodeMetaModel(node.getClass()).orElseThrow(() -> new IllegalStateException("Unknown Node: " + node.getClass()));
+
+ if (nodeName == null) {
+ generator.writeStartObject();
+ } else {
+ generator.writeStartObject(nodeName);
+ }
+ generator.write(JsonNode.CLASS.propertyKey, node.getClass().getName());
+ this.writeNonMetaProperties(node, generator);
+ for (PropertyMetaModel propertyMetaModel : nodeMetaModel.getAllPropertyMetaModels()) {
+ String name = propertyMetaModel.getName();
+ Object value = propertyMetaModel.getValue(node);
+ if (value != null) {
+ if (propertyMetaModel.isNodeList()) {
+ NodeList<Node> list = (NodeList<Node>) value;
+ generator.writeStartArray(name);
+ for (Node n : list) {
+ serialize(null, n, generator);
+ }
+ generator.writeEnd();
+ } else if (propertyMetaModel.isNode()) {
+ serialize(name, (Node) value, generator);
+ } else {
+ generator.write(name, value.toString());
+ }
+ }
+ }
+ generator.writeEnd();
+ }
+
+ /***
+ * This method writes json for properties not included in meta model (i.e., RANGE and TOKEN_RANGE).
+ * This method could be overriden so that - for example - tokens are not written to json to save space
+ *
+ * @see com.github.javaparser.metamodel.BaseNodeMetaModel#getAllPropertyMetaModels()
+ */
+
+ protected void writeNonMetaProperties(Node node, JsonGenerator generator) {
+ this.writeRange(node, generator);
+ this.writeTokens(node, generator);
+ }
+
+ protected void writeRange(Node node, JsonGenerator generator) {
+ if (node.getRange().isPresent()) {
+ Range range = node.getRange().get();
+ generator.writeStartObject(JsonNode.RANGE.propertyKey);
+ generator.write(JsonRange.BEGIN_LINE.propertyKey, range.begin.line);
+ generator.write(JsonRange.BEGIN_COLUMN.propertyKey, range.begin.column);
+ generator.write(JsonRange.END_LINE.propertyKey, range.end.line);
+ generator.write(JsonRange.END_COLUMN.propertyKey, range.end.column);
+ generator.writeEnd();
+ }
+ }
+
+ protected void writeTokens(Node node, JsonGenerator generator) {
+ if (node.getTokenRange().isPresent()) {
+ TokenRange tokenRange = node.getTokenRange().get();
+ generator.writeStartObject(JsonNode.TOKEN_RANGE.propertyKey);
+ writeToken(JsonTokenRange.BEGIN_TOKEN.propertyKey, tokenRange.getBegin(), generator);
+ writeToken(JsonTokenRange.END_TOKEN.propertyKey, tokenRange.getEnd(), generator);
+ generator.writeEnd();
+ }
+ }
+
+ protected void writeToken(String name, JavaToken token, JsonGenerator generator) {
+ generator.writeStartObject(name);
+ generator.write(JsonToken.KIND.propertyKey, token.getKind());
+ generator.write(JsonToken.TEXT.propertyKey, token.getText());
+ generator.writeEnd();
+ }
+
+ /**
+ * excludes properties from meta model (except comment)
+ **/
+ public enum JsonNode {
+ RANGE("range"),
+ TOKEN_RANGE("tokenRange"),
+ COMMENT(decapitalize(JavaParserMetaModel.commentMetaModel.getTypeName())),
+ CLASS("!");
+ final String propertyKey;
+
+ JsonNode(String p) {
+ this.propertyKey = p;
+ }
+
+ public String toString() {
+ return this.propertyKey;
+ }
+ }
+
+ public enum JsonRange {
+ BEGIN_LINE("beginLine"),
+ BEGIN_COLUMN("beginColumn"),
+ END_LINE("endLine"),
+ END_COLUMN("endColumn");
+ final String propertyKey;
+
+ JsonRange(String p) {
+ this.propertyKey = p;
+ }
+
+ public String toString() {
+ return this.propertyKey;
+ }
+ }
+
+ public enum JsonTokenRange {
+ BEGIN_TOKEN("beginToken"),
+ END_TOKEN("endToken");
+ final String propertyKey;
+
+ JsonTokenRange(String p) {
+ this.propertyKey = p;
+ }
+
+ public String toString() {
+ return this.propertyKey;
+ }
+ }
+
+ public enum JsonToken {
+ TEXT("text"),
+ KIND("kind");
+ final String propertyKey;
+
+ JsonToken(String p) {
+ this.propertyKey = p;
+ }
+
+ public String toString() {
+ return this.propertyKey;
+ }
+ }
+}
diff --git a/javaparser-core-serialization/src/test/java/com/github/javaparser/serialization/JavaParserJsonDeserializerTest.java b/javaparser-core-serialization/src/test/java/com/github/javaparser/serialization/JavaParserJsonDeserializerTest.java
new file mode 100644
index 000000000..4c7f0001f
--- /dev/null
+++ b/javaparser-core-serialization/src/test/java/com/github/javaparser/serialization/JavaParserJsonDeserializerTest.java
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 2007-2010 Júlio Vilmar Gesser.
+ * Copyright (C) 2011, 2013-2018 The JavaParser Team.
+ *
+ * This file is part of JavaParser.
+ *
+ * JavaParser can be used either under the terms of
+ * a) the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * b) the terms of the Apache License
+ *
+ * You should have received a copy of both licenses in LICENCE.LGPL and
+ * LICENCE.APACHE. Please refer to those files for details.
+ *
+ * JavaParser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ */
+package com.github.javaparser.serialization;
+
+import com.github.javaparser.*;
+import com.github.javaparser.ast.CompilationUnit;
+import com.github.javaparser.ast.Node;
+import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
+import com.github.javaparser.ast.body.MethodDeclaration;
+import com.github.javaparser.ast.comments.Comment;
+import com.github.javaparser.ast.expr.Expression;
+import com.github.javaparser.ast.type.Type;
+import com.github.javaparser.javadoc.Javadoc;
+import com.github.javaparser.javadoc.JavadocBlockTag;
+import com.github.javaparser.resolution.SymbolResolver;
+import com.github.javaparser.resolution.types.ResolvedType;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.Test;
+
+import javax.json.Json;
+import java.io.StringReader;
+
+import static com.github.javaparser.StaticJavaParser.*;
+import static com.github.javaparser.serialization.JavaParserJsonSerializerTest.serialize;
+import static com.github.javaparser.utils.Utils.EOL;
+import static com.github.javaparser.utils.Utils.normalizeEolInTextBlock;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+class JavaParserJsonDeserializerTest {
+ private final JavaParserJsonDeserializer deserializer = new JavaParserJsonDeserializer();
+
+ @Test
+ void simpleTest() {
+ CompilationUnit cu = parse("public class X{} class Z{}");
+ String serialized = serialize(cu, false);
+
+ Node deserialized = deserializer.deserializeObject(Json.createReader(new StringReader(serialized)));
+
+ assertEqualsNoEol("public class X {\n}\n\nclass Z {\n}\n", deserialized.toString());
+ assertEquals(cu.hashCode(), deserialized.hashCode());
+ }
+
+ @Test
+ void testRawType() {
+ Type type = parseType("Blub");
+ String serialized = serialize(type, false);
+
+ Node deserialized = deserializer.deserializeObject(Json.createReader(new StringReader(serialized)));
+
+ assertEqualsNoEol("Blub", deserialized.toString());
+ assertEquals(type.hashCode(), deserialized.hashCode());
+ }
+
+ @Test
+ void testDiamondType() {
+ Type type = parseType("Blub<>");
+ String serialized = serialize(type, false);
+
+ Node deserialized = deserializer.deserializeObject(Json.createReader(new StringReader(serialized)));
+
+ assertEqualsNoEol("Blub<>", deserialized.toString());
+ assertEquals(type.hashCode(), deserialized.hashCode());
+ }
+
+ @Test
+ void testGenerics() {
+ Type type = parseType("Blub<Blab, Bleb>");
+ String serialized = serialize(type, false);
+
+ Node deserialized = deserializer.deserializeObject(Json.createReader(new StringReader(serialized)));
+
+ assertEqualsNoEol("Blub<Blab, Bleb>", deserialized.toString());
+ assertEquals(type.hashCode(), deserialized.hashCode());
+ }
+
+ @Test
+ void testOperator() {
+ Expression expr = parseExpression("1+1");
+ String serialized = serialize(expr, false);
+
+ Node deserialized = deserializer.deserializeObject(Json.createReader(new StringReader(serialized)));
+
+ assertEqualsNoEol("1 + 1", deserialized.toString());
+ assertEquals(expr.hashCode(), deserialized.hashCode());
+ }
+
+ @Test
+ void testPrimitiveType() {
+ Type type = parseType("int");
+ String serialized = serialize(type, false);
+
+ Node deserialized = deserializer.deserializeObject(Json.createReader(new StringReader(serialized)));
+
+ assertEqualsNoEol("int", deserialized.toString());
+ assertEquals(type.hashCode(), deserialized.hashCode());
+ }
+
+ @Test
+ void testComment() {
+ CompilationUnit cu = parse("/* block comment */\npublic class X{ \n // line comment\npublic void test() {}\n}");
+ String serialized = serialize(cu, false);
+
+ CompilationUnit deserialized = (CompilationUnit) deserializer.deserializeObject(Json.createReader(new StringReader(serialized)));
+ ClassOrInterfaceDeclaration classXDeclaration = deserialized.getClassByName("X").get();
+ assertTrue(classXDeclaration.getComment().isPresent());
+
+ Comment comment = classXDeclaration.getComment().get();
+ assertEquals("com.github.javaparser.ast.comments.BlockComment", comment.getClass().getName());
+ assertEquals(" block comment ", comment.getContent());
+
+ MethodDeclaration methodDeclaration = classXDeclaration.getMethods().get(0);
+ assertTrue(methodDeclaration.getComment().isPresent());
+ assertEquals("com.github.javaparser.ast.comments.LineComment", methodDeclaration.getComment().get().getClass().getName());
+ assertEquals(" line comment", methodDeclaration.getComment().get().getContent());
+ }
+
+ @Test
+ void testJavaDocComment() {
+ CompilationUnit cu = parse("public class X{ " +
+ " /**\n" +
+ " * Woke text.\n" +
+ " * @param a blub\n" +
+ " * @return true \n" +
+ " */" +
+ " public boolean test(int a) { return true; }\n" +
+ "}");
+ String serialized = serialize(cu, false);
+
+ CompilationUnit deserialized = (CompilationUnit) deserializer.deserializeObject(Json.createReader(new StringReader(serialized)));
+ ClassOrInterfaceDeclaration classDeclaration = deserialized.getClassByName("X").get();
+ MethodDeclaration methodDeclaration = classDeclaration.getMethods().get(0);
+ assertTrue(methodDeclaration.getJavadoc().isPresent());
+ Javadoc javadoc = methodDeclaration.getJavadoc().get();
+
+ JavadocBlockTag paramBlockTag = javadoc.getBlockTags().get(0);
+ assertEquals("param", paramBlockTag.getTagName());
+ assertEquals("blub", paramBlockTag.getContent().toText());
+
+ JavadocBlockTag returnBlockTag = javadoc.getBlockTags().get(1);
+ assertEquals("return", returnBlockTag.getTagName());
+ assertEquals("true", returnBlockTag.getContent().toText());
+ }
+
+ @Test
+ void testNonMetaProperties() {
+ CompilationUnit cu = parse("public class X{} class Z{}");
+ String serialized = serialize(cu, false);
+
+ CompilationUnit deserialized = (CompilationUnit) deserializer.deserializeObject(Json.createReader(new StringReader(serialized)));
+
+ assertTrue(deserialized.getRange().isPresent());
+ Range range = deserialized.getRange().get();
+ assertEquals(1, range.begin.line);
+ assertEquals(1, range.begin.line);
+ assertEquals(26, range.end.column);
+
+ assertTrue(deserialized.getTokenRange().isPresent());
+ TokenRange tokenRange = deserialized.getTokenRange().get();
+ assertEquals("public", tokenRange.getBegin().getText());
+ assertEquals("", tokenRange.getEnd().getText());
+ }
+
+ @Test
+ void testAttachingSymbolResolver() {
+ SymbolResolver stubResolver = new SymbolResolver() {
+ @Override
+ public <T> T resolveDeclaration(Node node, Class<T> resultClass) {
+ return null;
+ }
+
+ @Override
+ public <T> T toResolvedType(Type javaparserType, Class<T> resultClass) {
+ return null;
+ }
+
+ @Override
+ public ResolvedType calculateType(Expression expression) {
+ return null;
+ }
+ };
+ StaticJavaParser.getConfiguration().setSymbolResolver(stubResolver);
+ CompilationUnit cu = parse("public class X{} class Z{}");
+ String serialized = serialize(cu, false);
+
+ CompilationUnit deserialized = (CompilationUnit) deserializer.deserializeObject(Json.createReader(new StringReader(serialized)));
+ assertTrue(deserialized.containsData(Node.SYMBOL_RESOLVER_KEY));
+ assertEquals(stubResolver, deserialized.getData(Node.SYMBOL_RESOLVER_KEY));
+ }
+
+ @AfterAll
+ static void clearConfiguration() {
+ StaticJavaParser.setConfiguration(new ParserConfiguration());
+ }
+
+ /**
+ * Assert that "actual" equals "expected", and that any EOL characters in "actual" are correct for the platform.
+ */
+ private static void assertEqualsNoEol(String expected, String actual) {
+ assertEquals(normalizeEolInTextBlock(expected, EOL), actual);
+ }
+
+}
diff --git a/javaparser-core-serialization/src/test/java/com/github/javaparser/serialization/JavaParserJsonSerializerTest.java b/javaparser-core-serialization/src/test/java/com/github/javaparser/serialization/JavaParserJsonSerializerTest.java
new file mode 100644
index 000000000..078a11cf3
--- /dev/null
+++ b/javaparser-core-serialization/src/test/java/com/github/javaparser/serialization/JavaParserJsonSerializerTest.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2007-2010 Júlio Vilmar Gesser.
+ * Copyright (C) 2011, 2013-2018 The JavaParser Team.
+ *
+ * This file is part of JavaParser.
+ *
+ * JavaParser can be used either under the terms of
+ * a) the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * b) the terms of the Apache License
+ *
+ * You should have received a copy of both licenses in LICENCE.LGPL and
+ * LICENCE.APACHE. Please refer to those files for details.
+ *
+ * JavaParser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ */
+package com.github.javaparser.serialization;
+
+import com.github.javaparser.ast.CompilationUnit;
+import com.github.javaparser.ast.Node;
+import org.junit.jupiter.api.Test;
+
+import javax.json.Json;
+import javax.json.stream.JsonGenerator;
+import javax.json.stream.JsonGeneratorFactory;
+import java.io.StringWriter;
+import java.util.HashMap;
+import java.util.Map;
+
+import static com.github.javaparser.StaticJavaParser.parse;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+class JavaParserJsonSerializerTest {
+ @Test
+ void test() {
+ CompilationUnit cu = parse("class X{java.util.Y y;}");
+
+ String serialized = serialize(cu, false);
+
+ assertEquals("{\"!\":\"com.github.javaparser.ast.CompilationUnit\",\"range\":{\"beginLine\":1,\"beginColumn\":1,\"endLine\":1,\"endColumn\":23},\"tokenRange\":{\"beginToken\":{\"kind\":19,\"text\":\"class\"},\"endToken\":{\"kind\":0,\"text\":\"\"}},\"imports\":[],\"types\":[{\"!\":\"com.github.javaparser.ast.body.ClassOrInterfaceDeclaration\",\"range\":{\"beginLine\":1,\"beginColumn\":1,\"endLine\":1,\"endColumn\":23},\"tokenRange\":{\"beginToken\":{\"kind\":19,\"text\":\"class\"},\"endToken\":{\"kind\":95,\"text\":\"}\"}},\"extendedTypes\":[],\"implementedTypes\":[],\"isInterface\":\"false\",\"typeParameters\":[],\"members\":[{\"!\":\"com.github.javaparser.ast.body.FieldDeclaration\",\"range\":{\"beginLine\":1,\"beginColumn\":9,\"endLine\":1,\"endColumn\":22},\"tokenRange\":{\"beginToken\":{\"kind\":89,\"text\":\"java\"},\"endToken\":{\"kind\":98,\"text\":\";\"}},\"modifiers\":[],\"variables\":[{\"!\":\"com.github.javaparser.ast.body.VariableDeclarator\",\"range\":{\"beginLine\":1,\"beginColumn\":21,\"endLine\":1,\"endColumn\":21},\"tokenRange\":{\"beginToken\":{\"kind\":89,\"text\":\"y\"},\"endToken\":{\"kind\":89,\"text\":\"y\"}},\"name\":{\"!\":\"com.github.javaparser.ast.expr.SimpleName\",\"range\":{\"beginLine\":1,\"beginColumn\":21,\"endLine\":1,\"endColumn\":21},\"tokenRange\":{\"beginToken\":{\"kind\":89,\"text\":\"y\"},\"endToken\":{\"kind\":89,\"text\":\"y\"}},\"identifier\":\"y\"},\"type\":{\"!\":\"com.github.javaparser.ast.type.ClassOrInterfaceType\",\"range\":{\"beginLine\":1,\"beginColumn\":9,\"endLine\":1,\"endColumn\":19},\"tokenRange\":{\"beginToken\":{\"kind\":89,\"text\":\"java\"},\"endToken\":{\"kind\":89,\"text\":\"Y\"}},\"name\":{\"!\":\"com.github.javaparser.ast.expr.SimpleName\",\"range\":{\"beginLine\":1,\"beginColumn\":19,\"endLine\":1,\"endColumn\":19},\"tokenRange\":{\"beginToken\":{\"kind\":89,\"text\":\"Y\"},\"endToken\":{\"kind\":89,\"text\":\"Y\"}},\"identifier\":\"Y\"},\"scope\":{\"!\":\"com.github.javaparser.ast.type.ClassOrInterfaceType\",\"range\":{\"beginLine\":1,\"beginColumn\":9,\"endLine\":1,\"endColumn\":17},\"tokenRange\":{\"beginToken\":{\"kind\":89,\"text\":\"java\"},\"endToken\":{\"kind\":89,\"text\":\"util\"}},\"name\":{\"!\":\"com.github.javaparser.ast.expr.SimpleName\",\"range\":{\"beginLine\":1,\"beginColumn\":14,\"endLine\":1,\"endColumn\":17},\"tokenRange\":{\"beginToken\":{\"kind\":89,\"text\":\"util\"},\"endToken\":{\"kind\":89,\"text\":\"util\"}},\"identifier\":\"util\"},\"scope\":{\"!\":\"com.github.javaparser.ast.type.ClassOrInterfaceType\",\"range\":{\"beginLine\":1,\"beginColumn\":9,\"endLine\":1,\"endColumn\":12},\"tokenRange\":{\"beginToken\":{\"kind\":89,\"text\":\"java\"},\"endToken\":{\"kind\":89,\"text\":\"java\"}},\"name\":{\"!\":\"com.github.javaparser.ast.expr.SimpleName\",\"range\":{\"beginLine\":1,\"beginColumn\":9,\"endLine\":1,\"endColumn\":12},\"tokenRange\":{\"beginToken\":{\"kind\":89,\"text\":\"java\"},\"endToken\":{\"kind\":89,\"text\":\"java\"}},\"identifier\":\"java\"},\"annotations\":[]},\"annotations\":[]},\"annotations\":[]}}],\"annotations\":[]}],\"modifiers\":[],\"name\":{\"!\":\"com.github.javaparser.ast.expr.SimpleName\",\"range\":{\"beginLine\":1,\"beginColumn\":7,\"endLine\":1,\"endColumn\":7},\"tokenRange\":{\"beginToken\":{\"kind\":89,\"text\":\"X\"},\"endToken\":{\"kind\":89,\"text\":\"X\"}},\"identifier\":\"X\"},\"annotations\":[]}]}", serialized);
+ }
+
+ static String serialize(Node node, boolean prettyPrint) {
+ Map<String, ?> config = new HashMap<>();
+ if (prettyPrint) {
+ config.put(JsonGenerator.PRETTY_PRINTING, null);
+ }
+ JsonGeneratorFactory generatorFactory = Json.createGeneratorFactory(config);
+ JavaParserJsonSerializer serializer = new JavaParserJsonSerializer();
+ StringWriter jsonWriter = new StringWriter();
+ try (JsonGenerator generator = generatorFactory.createGenerator(jsonWriter)) {
+ serializer.serialize(node, generator);
+ }
+ return jsonWriter.toString();
+ }
+}