1
2
3
4
5
6
7
8
9
10 package de.funfried.netbeans.plugins.external.formatter.json.jackson;
11
12 import java.util.Objects;
13
14 import org.apache.commons.lang3.StringUtils;
15 import org.netbeans.api.annotations.common.CheckForNull;
16 import org.netbeans.api.annotations.common.NonNull;
17
18 import com.fasterxml.jackson.core.JsonFactory;
19 import com.fasterxml.jackson.core.JsonParser;
20 import com.fasterxml.jackson.core.JsonProcessingException;
21 import com.fasterxml.jackson.core.util.DefaultIndenter;
22 import com.fasterxml.jackson.core.util.DefaultPrettyPrinter;
23 import com.fasterxml.jackson.core.util.Separators;
24 import com.fasterxml.jackson.databind.ObjectMapper;
25 import com.fasterxml.jackson.databind.SerializationFeature;
26
27 import de.funfried.netbeans.plugins.external.formatter.exceptions.FormattingFailedException;
28
29
30
31
32
33
34 public final class JacksonJsonFormatterWrapper {
35
36
37
38 JacksonJsonFormatterWrapper() {
39 }
40
41
42
43
44
45
46
47
48
49
50
51 @CheckForNull
52 public String format(String code, String lineFeed, Options options) throws FormattingFailedException {
53 if (code == null) {
54 return null;
55 }
56
57 if (lineFeed == null) {
58 lineFeed = System.getProperty("line.separator");
59 }
60
61 if (options == null) {
62 options = new Options();
63 }
64
65 int indentSize = options.getIndentSize();
66 int spacesPerTab = options.getSpacesPerTab();
67 boolean spaceBeforeSeparator = options.isSpaceBeforeSeparator();
68 boolean expandTabsToSpaces = options.isExpandTabsToSpaces();
69
70 String indentString;
71 if (expandTabsToSpaces) {
72 indentString = StringUtils.repeat(" ", indentSize);
73 } else {
74 indentString = StringUtils.repeat("\t", indentSize / spacesPerTab) + StringUtils.repeat(" ", indentSize % spacesPerTab);
75 }
76
77 DefaultPrettyPrinter.Indenter indenter = new DefaultIndenter(indentString, lineFeed);
78
79 DefaultPrettyPrinter printer = new JacksonPrettyPrinter(spaceBeforeSeparator);
80 printer.withSeparators(DefaultPrettyPrinter.DEFAULT_SEPARATORS);
81 printer.indentObjectsWith(indenter);
82 printer.indentArraysWith(indenter);
83
84 ObjectMapper objectMapper = new ObjectMapper();
85 objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
86 objectMapper.setDefaultPrettyPrinter(printer);
87
88 JsonFactory factory = objectMapper.getFactory();
89 factory.enable(JsonParser.Feature.ALLOW_COMMENTS);
90 factory.enable(JsonParser.Feature.ALLOW_SINGLE_QUOTES);
91 factory.enable(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES);
92 factory.enable(JsonParser.Feature.ALLOW_YAML_COMMENTS);
93
94 return format(objectMapper, code);
95 }
96
97
98
99
100
101
102
103
104
105
106
107
108
109 @CheckForNull
110 private String format(ObjectMapper objectMapper, @NonNull String code) throws FormattingFailedException {
111 String formattedCode;
112 try {
113 Object json = objectMapper.readValue(code, Object.class);
114 formattedCode = objectMapper.writer().writeValueAsString(json);
115 if (Objects.equals(code, formattedCode)) {
116 return null;
117 }
118 } catch (JsonProcessingException ex) {
119 throw new FormattingFailedException(ex);
120 }
121
122 return formattedCode;
123 }
124
125
126
127
128 private static class JacksonPrettyPrinter extends DefaultPrettyPrinter {
129 private static final long serialVersionUID = 1L;
130
131 private final boolean spaceBeforeSeparator;
132
133
134
135
136
137
138
139 public JacksonPrettyPrinter(boolean spaceBeforeSeparator) {
140 super();
141 this.spaceBeforeSeparator = spaceBeforeSeparator;
142 }
143
144
145
146
147 @Override
148 public DefaultPrettyPrinter createInstance() {
149 return new DefaultPrettyPrinter(this);
150 }
151
152
153
154
155 @Override
156 public DefaultPrettyPrinter withSeparators(Separators separators) {
157 this._separators = separators;
158 this._objectFieldValueSeparatorWithSpaces = (this.spaceBeforeSeparator ? " " : "") + separators.getObjectFieldValueSeparator() + " ";
159
160 return this;
161 }
162 }
163
164 public static class Options {
165 private int indentSize = 2;
166
167 private int spacesPerTab = 2;
168
169 private boolean spaceBeforeSeparator = false;
170
171 private boolean expandTabsToSpaces = true;
172
173 public int getIndentSize() {
174 return indentSize;
175 }
176
177 public void setIndentSize(int indentSize) {
178 this.indentSize = indentSize;
179 }
180
181 public int getSpacesPerTab() {
182 return spacesPerTab;
183 }
184
185 public void setSpacesPerTab(int spacesPerTab) {
186 this.spacesPerTab = spacesPerTab;
187 }
188
189 public boolean isSpaceBeforeSeparator() {
190 return spaceBeforeSeparator;
191 }
192
193 public void setSpaceBeforeSeparator(boolean spaceBeforeSeparator) {
194 this.spaceBeforeSeparator = spaceBeforeSeparator;
195 }
196
197 public boolean isExpandTabsToSpaces() {
198 return expandTabsToSpaces;
199 }
200
201 public void setExpandTabsToSpaces(boolean expandTabsToSpaces) {
202 this.expandTabsToSpaces = expandTabsToSpaces;
203 }
204 }
205 }