1 /* 2 * Copyright (C) 2007-2010 Júlio Vilmar Gesser. 3 * Copyright (C) 2011, 2013-2018 The JavaParser Team. 4 * 5 * This file is part of JavaParser. 6 * 7 * JavaParser can be used either under the terms of 8 * a) the GNU Lesser General Public License as published by 9 * the Free Software Foundation, either version 3 of the License, or 10 * (at your option) any later version. 11 * b) the terms of the Apache License 12 * 13 * You should have received a copy of both licenses in LICENCE.LGPL and 14 * LICENCE.APACHE. Please refer to those files for details. 15 * 16 * JavaParser is distributed in the hope that it will be useful, 17 * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 * GNU Lesser General Public License for more details. 20 */ 21 package com.github.javaparser.serialization; 22 23 import com.github.javaparser.JavaToken; 24 import com.github.javaparser.Range; 25 import com.github.javaparser.TokenRange; 26 import com.github.javaparser.ast.Node; 27 import com.github.javaparser.ast.NodeList; 28 import com.github.javaparser.metamodel.BaseNodeMetaModel; 29 import com.github.javaparser.metamodel.JavaParserMetaModel; 30 import com.github.javaparser.metamodel.PropertyMetaModel; 31 import com.github.javaparser.utils.Log; 32 33 import javax.json.stream.JsonGenerator; 34 35 import static com.github.javaparser.utils.Utils.decapitalize; 36 import static java.util.Objects.requireNonNull; 37 38 /** 39 * Serializes an AST or a partial AST to JSON. 40 */ 41 public class JavaParserJsonSerializer { 42 43 /** 44 * Serializes node and all its children into json. Any node siblings will be ignored. 45 * 46 * @param node the node that will be the root level json object 47 * @param generator the json-p generator for writing the json 48 * @see <a href="https://javaee.github.io/jsonp/">json-p</a> 49 */ serialize(Node node, JsonGenerator generator)50 public void serialize(Node node, JsonGenerator generator) { 51 requireNonNull(node); 52 Log.info("Serializing Node to JSON."); 53 try { 54 serialize(null, node, generator); 55 } finally { 56 generator.close(); 57 } 58 } 59 60 /** 61 * Recursive depth-first method that serializes nodes into json 62 * 63 * @param nodeName nullable String. If null, it is the root object, otherwise it is the property key for the object 64 * @param node the current node to be serialized 65 * @param generator the json-p generator for writing the json 66 */ 67 serialize(String nodeName, Node node, JsonGenerator generator)68 private void serialize(String nodeName, Node node, JsonGenerator generator) { 69 requireNonNull(node); 70 BaseNodeMetaModel nodeMetaModel = JavaParserMetaModel.getNodeMetaModel(node.getClass()).orElseThrow(() -> new IllegalStateException("Unknown Node: " + node.getClass())); 71 72 if (nodeName == null) { 73 generator.writeStartObject(); 74 } else { 75 generator.writeStartObject(nodeName); 76 } 77 generator.write(JsonNode.CLASS.propertyKey, node.getClass().getName()); 78 this.writeNonMetaProperties(node, generator); 79 for (PropertyMetaModel propertyMetaModel : nodeMetaModel.getAllPropertyMetaModels()) { 80 String name = propertyMetaModel.getName(); 81 Object value = propertyMetaModel.getValue(node); 82 if (value != null) { 83 if (propertyMetaModel.isNodeList()) { 84 NodeList<Node> list = (NodeList<Node>) value; 85 generator.writeStartArray(name); 86 for (Node n : list) { 87 serialize(null, n, generator); 88 } 89 generator.writeEnd(); 90 } else if (propertyMetaModel.isNode()) { 91 serialize(name, (Node) value, generator); 92 } else { 93 generator.write(name, value.toString()); 94 } 95 } 96 } 97 generator.writeEnd(); 98 } 99 100 /*** 101 * This method writes json for properties not included in meta model (i.e., RANGE and TOKEN_RANGE). 102 * This method could be overriden so that - for example - tokens are not written to json to save space 103 * 104 * @see com.github.javaparser.metamodel.BaseNodeMetaModel#getAllPropertyMetaModels() 105 */ 106 writeNonMetaProperties(Node node, JsonGenerator generator)107 protected void writeNonMetaProperties(Node node, JsonGenerator generator) { 108 this.writeRange(node, generator); 109 this.writeTokens(node, generator); 110 } 111 writeRange(Node node, JsonGenerator generator)112 protected void writeRange(Node node, JsonGenerator generator) { 113 if (node.getRange().isPresent()) { 114 Range range = node.getRange().get(); 115 generator.writeStartObject(JsonNode.RANGE.propertyKey); 116 generator.write(JsonRange.BEGIN_LINE.propertyKey, range.begin.line); 117 generator.write(JsonRange.BEGIN_COLUMN.propertyKey, range.begin.column); 118 generator.write(JsonRange.END_LINE.propertyKey, range.end.line); 119 generator.write(JsonRange.END_COLUMN.propertyKey, range.end.column); 120 generator.writeEnd(); 121 } 122 } 123 writeTokens(Node node, JsonGenerator generator)124 protected void writeTokens(Node node, JsonGenerator generator) { 125 if (node.getTokenRange().isPresent()) { 126 TokenRange tokenRange = node.getTokenRange().get(); 127 generator.writeStartObject(JsonNode.TOKEN_RANGE.propertyKey); 128 writeToken(JsonTokenRange.BEGIN_TOKEN.propertyKey, tokenRange.getBegin(), generator); 129 writeToken(JsonTokenRange.END_TOKEN.propertyKey, tokenRange.getEnd(), generator); 130 generator.writeEnd(); 131 } 132 } 133 writeToken(String name, JavaToken token, JsonGenerator generator)134 protected void writeToken(String name, JavaToken token, JsonGenerator generator) { 135 generator.writeStartObject(name); 136 generator.write(JsonToken.KIND.propertyKey, token.getKind()); 137 generator.write(JsonToken.TEXT.propertyKey, token.getText()); 138 generator.writeEnd(); 139 } 140 141 /** 142 * excludes properties from meta model (except comment) 143 **/ 144 public enum JsonNode { 145 RANGE("range"), 146 TOKEN_RANGE("tokenRange"), 147 COMMENT(decapitalize(JavaParserMetaModel.commentMetaModel.getTypeName())), 148 CLASS("!"); 149 final String propertyKey; 150 JsonNode(String p)151 JsonNode(String p) { 152 this.propertyKey = p; 153 } 154 toString()155 public String toString() { 156 return this.propertyKey; 157 } 158 } 159 160 public enum JsonRange { 161 BEGIN_LINE("beginLine"), 162 BEGIN_COLUMN("beginColumn"), 163 END_LINE("endLine"), 164 END_COLUMN("endColumn"); 165 final String propertyKey; 166 JsonRange(String p)167 JsonRange(String p) { 168 this.propertyKey = p; 169 } 170 toString()171 public String toString() { 172 return this.propertyKey; 173 } 174 } 175 176 public enum JsonTokenRange { 177 BEGIN_TOKEN("beginToken"), 178 END_TOKEN("endToken"); 179 final String propertyKey; 180 JsonTokenRange(String p)181 JsonTokenRange(String p) { 182 this.propertyKey = p; 183 } 184 toString()185 public String toString() { 186 return this.propertyKey; 187 } 188 } 189 190 public enum JsonToken { 191 TEXT("text"), 192 KIND("kind"); 193 final String propertyKey; 194 JsonToken(String p)195 JsonToken(String p) { 196 this.propertyKey = p; 197 } 198 toString()199 public String toString() { 200 return this.propertyKey; 201 } 202 } 203 } 204