• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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