JavaParserJsonSerializer.java
/*
* Copyright (C) 2007-2010 J��lio Vilmar Gesser.
* Copyright (C) 2011, 2013-2024 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 static com.github.javaparser.utils.Utils.decapitalize;
import static java.util.Objects.requireNonNull;
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 jakarta.json.stream.JsonGenerator;
/**
* 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.hasRange()) {
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;
}
}
}