1   
2   
3   
4   
5   
6   
7   
8   
9   
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  package org.apache.maven.plugins.dependency.tree;
20  
21  import java.io.IOException;
22  import java.io.UncheckedIOException;
23  import java.io.Writer;
24  import java.util.HashSet;
25  import java.util.Set;
26  
27  import org.apache.maven.artifact.Artifact;
28  import org.apache.maven.shared.dependency.graph.DependencyNode;
29  import org.apache.maven.shared.dependency.graph.traversal.DependencyNodeVisitor;
30  
31  
32  
33  
34  public class JsonDependencyNodeVisitor extends AbstractSerializingVisitor implements DependencyNodeVisitor {
35  
36      private String indentChar = " ";
37  
38      
39  
40  
41  
42  
43      public JsonDependencyNodeVisitor(Writer writer) {
44          super(writer);
45      }
46  
47      @Override
48      public boolean visit(DependencyNode node) {
49          try {
50              if (node.getParent() == null || node.getParent() == node) {
51                  writeRootNode(node);
52              }
53              return true;
54          } catch (IOException e) {
55              throw new UncheckedIOException("Failed to write JSON format output", e);
56          }
57      }
58  
59      
60  
61  
62  
63  
64  
65      private void writeRootNode(DependencyNode node) throws IOException {
66          Set<DependencyNode> visited = new HashSet<>();
67          int indent = 2;
68          StringBuilder sb = new StringBuilder();
69          sb.append("{").append(System.lineSeparator());
70          writeNode(indent, node, sb, visited);
71          sb.append("}").append(System.lineSeparator());
72          writer.write(sb.toString());
73          writer.flush();
74      }
75      
76  
77  
78  
79  
80  
81  
82      private void writeNode(int indent, DependencyNode node, StringBuilder sb, Set<DependencyNode> visited) {
83          if (visited.contains(node)) {
84              
85              
86              return;
87          }
88          visited.add(node);
89          appendNodeValues(sb, indent, node.getArtifact(), !node.getChildren().isEmpty());
90          if (!node.getChildren().isEmpty()) {
91              writeChildren(indent, node, sb, visited);
92          }
93      }
94      
95  
96  
97  
98  
99  
100 
101     private void writeChildren(int indent, DependencyNode node, StringBuilder sb, Set<DependencyNode> visited) {
102         sb.append(indent(indent)).append("\"children\": [").append(System.lineSeparator());
103         indent += 2;
104         for (int i = 0; i < node.getChildren().size(); i++) {
105             DependencyNode child = node.getChildren().get(i);
106             sb.append(indent(indent));
107             sb.append("{").append(System.lineSeparator());
108             writeNode(indent + 2, child, sb, visited);
109             sb.append(indent(indent)).append("}");
110             
111             if (i != node.getChildren().size() - 1) {
112                 sb.append(",");
113             }
114             sb.append(System.lineSeparator());
115         }
116         sb.append(indent(indent)).append("]").append(System.lineSeparator());
117     }
118 
119     @Override
120     public boolean endVisit(DependencyNode node) {
121         return true;
122     }
123     
124 
125 
126 
127 
128 
129 
130 
131     private void appendNodeValues(StringBuilder sb, int indent, Artifact artifact, boolean hasChildren) {
132         appendKeyValue(sb, indent, "groupId", artifact.getGroupId());
133         appendKeyValue(sb, indent, "artifactId", artifact.getArtifactId());
134         appendKeyValue(sb, indent, "version", artifact.getVersion());
135         appendKeyValue(sb, indent, "type", artifact.getType());
136         appendKeyValue(sb, indent, "scope", artifact.getScope());
137         appendKeyValue(sb, indent, "classifier", artifact.getClassifier());
138         if (hasChildren) {
139             appendKeyValue(sb, indent, "optional", String.valueOf(artifact.isOptional()));
140         } else {
141             appendKeyWithoutComma(sb, indent, "optional", String.valueOf(artifact.isOptional()));
142         }
143     }
144     
145 
146 
147 
148 
149 
150 
151 
152     private void appendKeyValue(StringBuilder sb, int indent, String key, String value) {
153         if (value == null) {
154             value = "";
155         }
156 
157         sb.append(indent(indent))
158                 .append("\"")
159                 .append(key)
160                 .append("\"")
161                 .append(":")
162                 .append(indentChar)
163                 .append("\"")
164                 .append(value)
165                 .append("\"")
166                 .append(",")
167                 .append(System.lineSeparator());
168     }
169     
170 
171 
172 
173 
174 
175 
176 
177     private void appendKeyWithoutComma(StringBuilder sb, int indent, String key, String value) {
178         if (value == null) {
179             value = "";
180         }
181 
182         sb.append(indent(indent))
183                 .append("\"")
184                 .append(key)
185                 .append("\"")
186                 .append(":")
187                 .append(indentChar)
188                 .append("\"")
189                 .append(value)
190                 .append("\"")
191                 .append(System.lineSeparator());
192     }
193 
194     
195 
196 
197 
198 
199 
200     private String indent(int indent) {
201         if (indent < 1) {
202             return "";
203         }
204 
205         StringBuilder sb = new StringBuilder();
206         for (int i = 0; i < indent; i++) {
207             sb.append(indentChar);
208         }
209 
210         return sb.toString();
211     }
212 }