Skip to content

Commit a9f5aac

Browse files
authored
Add jasckon for both json and yaml, gradle & maven (#1508)
Progress with jackson yaml and json
2 parents a21049a + 63dd687 commit a9f5aac

37 files changed

+1108
-191
lines changed

CHANGES.md

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (
1616
### Fixed
1717
* The default list of type annotations used by `formatAnnotations` has had 8 more annotations from the Checker Framework added [#1494](https://github.com/diffplug/spotless/pull/1494)
1818
### Changes
19+
* Rename `YamlJacksonStep` into `JacksonYamlStep` while normalizing Jackson usage ([#1492](https://github.com/diffplug/spotless/pull/1492))
1920

2021
## [2.32.0] - 2023-01-13
2122
### Added

README.md

+4-2
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ lib('java.RemoveUnusedImportsStep') +'{{yes}} | {{yes}}
6363
extra('java.EclipseJdtFormatterStep') +'{{yes}} | {{yes}} | {{yes}} | {{no}} |',
6464
lib('java.FormatAnnotationsStep') +'{{yes}} | {{yes}} | {{no}} | {{no}} |',
6565
lib('json.gson.GsonStep') +'{{yes}} | {{yes}} | {{no}} | {{no}} |',
66+
lib('json.JacksonJsonStep') +'{{yes}} | {{yes}} | {{no}} | {{no}} |',
6667
lib('json.JsonSimpleStep') +'{{yes}} | {{yes}} | {{no}} | {{no}} |',
6768
lib('kotlin.KtLintStep') +'{{yes}} | {{yes}} | {{yes}} | {{no}} |',
6869
lib('kotlin.KtfmtStep') +'{{yes}} | {{yes}} | {{no}} | {{no}} |',
@@ -77,7 +78,7 @@ lib('python.BlackStep') +'{{yes}} | {{no}}
7778
lib('scala.ScalaFmtStep') +'{{yes}} | {{yes}} | {{yes}} | {{no}} |',
7879
lib('sql.DBeaverSQLFormatterStep') +'{{yes}} | {{yes}} | {{yes}} | {{no}} |',
7980
extra('wtp.EclipseWtpFormatterStep') +'{{yes}} | {{yes}} | {{no}} | {{no}} |',
80-
lib('yaml.YamlJacksonStep') +'{{no}} | {{yes}} | {{no}} | {{no}} |',
81+
lib('yaml.JacksonYamlStep') +'{{yes}} | {{yes}} | {{no}} | {{no}} |',
8182
'| [(Your FormatterStep here)](CONTRIBUTING.md#how-to-add-a-new-formatterstep) | {{no}} | {{no}} | {{no}} | {{no}} |',
8283
].join('\n');
8384
-->
@@ -109,6 +110,7 @@ lib('yaml.YamlJacksonStep') +'{{no}} | {{yes}}
109110
| [`java.EclipseJdtFormatterStep`](lib-extra/src/main/java/com/diffplug/spotless/extra/java/EclipseJdtFormatterStep.java) | :+1: | :+1: | :+1: | :white_large_square: |
110111
| [`java.FormatAnnotationsStep`](lib/src/main/java/com/diffplug/spotless/java/FormatAnnotationsStep.java) | :+1: | :+1: | :white_large_square: | :white_large_square: |
111112
| [`json.gson.GsonStep`](lib/src/main/java/com/diffplug/spotless/json/gson/GsonStep.java) | :+1: | :+1: | :white_large_square: | :white_large_square: |
113+
| [`json.JacksonJsonStep`](lib/src/main/java/com/diffplug/spotless/json/JacksonJsonStep.java) | :+1: | :+1: | :white_large_square: | :white_large_square: |
112114
| [`json.JsonSimpleStep`](lib/src/main/java/com/diffplug/spotless/json/JsonSimpleStep.java) | :+1: | :+1: | :white_large_square: | :white_large_square: |
113115
| [`kotlin.KtLintStep`](lib/src/main/java/com/diffplug/spotless/kotlin/KtLintStep.java) | :+1: | :+1: | :+1: | :white_large_square: |
114116
| [`kotlin.KtfmtStep`](lib/src/main/java/com/diffplug/spotless/kotlin/KtfmtStep.java) | :+1: | :+1: | :white_large_square: | :white_large_square: |
@@ -123,7 +125,7 @@ lib('yaml.YamlJacksonStep') +'{{no}} | {{yes}}
123125
| [`scala.ScalaFmtStep`](lib/src/main/java/com/diffplug/spotless/scala/ScalaFmtStep.java) | :+1: | :+1: | :+1: | :white_large_square: |
124126
| [`sql.DBeaverSQLFormatterStep`](lib/src/main/java/com/diffplug/spotless/sql/DBeaverSQLFormatterStep.java) | :+1: | :+1: | :+1: | :white_large_square: |
125127
| [`wtp.EclipseWtpFormatterStep`](lib-extra/src/main/java/com/diffplug/spotless/extra/wtp/EclipseWtpFormatterStep.java) | :+1: | :+1: | :white_large_square: | :white_large_square: |
126-
| [`yaml.YamlJacksonStep`](lib/src/main/java/com/diffplug/spotless/yaml/YamlJacksonStep.java) | :white_large_square: | :+1: | :white_large_square: | :white_large_square: |
128+
| [`yaml.JacksonYamlStep`](lib/src/main/java/com/diffplug/spotless/yaml/JacksonYamlStep.java) | :+1: | :+1: | :white_large_square: | :white_large_square: |
127129
| [(Your FormatterStep here)](CONTRIBUTING.md#how-to-add-a-new-formatterstep) | :white_large_square: | :white_large_square: | :white_large_square: | :white_large_square: |
128130
<!---freshmark /matrix -->
129131

lib/build.gradle

+1
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ dependencies {
5757
palantirJavaFormatCompileOnly 'com.palantir.javaformat:palantir-java-format:1.1.0' // this version needs to stay compilable against Java 8 for CI Job testNpm
5858

5959
// used jackson-based formatters
60+
jacksonCompileOnly 'com.fasterxml.jackson.core:jackson-databind:2.14.1'
6061
jacksonCompileOnly 'com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.14.1'
6162

6263
String VER_KTFMT = '0.42'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
/*
2+
* Copyright 2021-2023 DiffPlug
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.diffplug.spotless.glue.json;
17+
18+
import java.io.IOException;
19+
import java.util.Map;
20+
21+
import com.fasterxml.jackson.core.JsonFactory;
22+
import com.fasterxml.jackson.core.JsonProcessingException;
23+
import com.fasterxml.jackson.core.PrettyPrinter;
24+
import com.fasterxml.jackson.core.util.DefaultPrettyPrinter;
25+
import com.fasterxml.jackson.databind.ObjectMapper;
26+
import com.fasterxml.jackson.databind.SerializationFeature;
27+
28+
import com.diffplug.spotless.FormatterFunc;
29+
import com.diffplug.spotless.json.JacksonConfig;
30+
31+
/**
32+
* A {@link FormatterFunc} based on Jackson library
33+
*/
34+
// https://github.com/FasterXML/jackson-dataformats-text/issues/372
35+
public abstract class AJacksonFormatterFunc implements FormatterFunc {
36+
private JacksonConfig jacksonConfig;
37+
38+
public AJacksonFormatterFunc(JacksonConfig jacksonConfig) {
39+
this.jacksonConfig = jacksonConfig;
40+
}
41+
42+
@Override
43+
public String apply(String input) throws Exception {
44+
ObjectMapper objectMapper = makeObjectMapper();
45+
46+
return format(objectMapper, input);
47+
}
48+
49+
protected String format(ObjectMapper objectMapper, String input) throws IllegalArgumentException, IOException {
50+
try {
51+
// ObjectNode is not compatible with SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS
52+
Map objectNode = objectMapper.readValue(input, Map.class);
53+
String output = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(objectNode);
54+
55+
return output;
56+
} catch (JsonProcessingException e) {
57+
throw new IllegalArgumentException("Unable to format. input='" + input + "'", e);
58+
}
59+
}
60+
61+
/**
62+
* @return a {@link JsonFactory}. May be overridden to handle alternative formats.
63+
* @see <a href="https://github.com/FasterXML/jackson-dataformats-text">jackson-dataformats-text</a>
64+
*/
65+
protected abstract JsonFactory makeJsonFactory();
66+
67+
protected ObjectMapper makeObjectMapper() {
68+
JsonFactory jsonFactory = makeJsonFactory();
69+
ObjectMapper objectMapper = new ObjectMapper(jsonFactory);
70+
71+
objectMapper.setDefaultPrettyPrinter(makePrettyPrinter());
72+
73+
// Configure the ObjectMapper
74+
// https://github.com/FasterXML/jackson-databind#commonly-used-features
75+
jacksonConfig.getFeatureToToggle().forEach((rawFeature, toggle) -> {
76+
// https://stackoverflow.com/questions/3735927/java-instantiating-an-enum-using-reflection
77+
SerializationFeature feature = SerializationFeature.valueOf(rawFeature);
78+
79+
objectMapper.configure(feature, toggle);
80+
});
81+
82+
return objectMapper;
83+
}
84+
85+
protected PrettyPrinter makePrettyPrinter() {
86+
return new DefaultPrettyPrinter();
87+
}
88+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
/*
2+
* Copyright 2021-2023 DiffPlug
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.diffplug.spotless.glue.json;
17+
18+
import com.fasterxml.jackson.core.JsonFactory;
19+
import com.fasterxml.jackson.core.JsonFactoryBuilder;
20+
import com.fasterxml.jackson.core.JsonGenerator;
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+
25+
import com.diffplug.spotless.FormatterFunc;
26+
import com.diffplug.spotless.json.JacksonJsonConfig;
27+
28+
/**
29+
* A {@link FormatterFunc} based on Jackson library
30+
*/
31+
// https://github.com/FasterXML/jackson-dataformats-text/issues/372
32+
public class JacksonJsonFormatterFunc extends AJacksonFormatterFunc {
33+
private JacksonJsonConfig jacksonConfig;
34+
35+
public JacksonJsonFormatterFunc(JacksonJsonConfig jacksonConfig) {
36+
super(jacksonConfig);
37+
this.jacksonConfig = jacksonConfig;
38+
}
39+
40+
/**
41+
* @return a {@link JsonFactory}. May be overridden to handle alternative formats.
42+
* @see <a href="https://github.com/FasterXML/jackson-dataformats-text">jackson-dataformats-text</a>
43+
*/
44+
protected JsonFactory makeJsonFactory() {
45+
JsonFactory jsonFactory = new JsonFactoryBuilder().build();
46+
47+
// Configure the ObjectMapper
48+
// https://github.com/FasterXML/jackson-databind#commonly-used-features
49+
jacksonConfig.getJsonFeatureToToggle().forEach((rawFeature, toggle) -> {
50+
// https://stackoverflow.com/questions/3735927/java-instantiating-an-enum-using-reflection
51+
JsonGenerator.Feature feature = JsonGenerator.Feature.valueOf(rawFeature);
52+
53+
jsonFactory.configure(feature, toggle);
54+
});
55+
56+
return jsonFactory;
57+
}
58+
59+
@Override
60+
protected DefaultPrettyPrinter makePrettyPrinter() {
61+
boolean spaceBeforeSeparator = jacksonConfig.isSpaceBeforeSeparator();
62+
63+
// DefaultIndenter default constructor relies on 2 whitespaces as default tabulation
64+
// By we want to force '\n' as eol given Spotless provides LF-input (whatever the actual File content/current OS)
65+
DefaultPrettyPrinter.Indenter indenter = new DefaultIndenter(" ", "\n");
66+
DefaultPrettyPrinter printer = new SpotlessJsonPrettyPrinter(spaceBeforeSeparator);
67+
68+
printer.indentObjectsWith(indenter);
69+
printer.indentArraysWith(indenter);
70+
return printer;
71+
}
72+
73+
protected static class SpotlessJsonPrettyPrinter extends DefaultPrettyPrinter {
74+
private static final long serialVersionUID = 1L;
75+
private final boolean spaceBeforeSeparator;
76+
77+
public SpotlessJsonPrettyPrinter(boolean spaceBeforeSeparator) {
78+
this.spaceBeforeSeparator = spaceBeforeSeparator;
79+
}
80+
81+
@Override
82+
public DefaultPrettyPrinter createInstance() {
83+
return new SpotlessJsonPrettyPrinter(spaceBeforeSeparator);
84+
}
85+
86+
@Override
87+
public DefaultPrettyPrinter withSeparators(Separators separators) {
88+
this._separators = separators;
89+
if (spaceBeforeSeparator) {
90+
// This is Jackson default behavior
91+
this._objectFieldValueSeparatorWithSpaces = " " + separators.getObjectFieldValueSeparator() + " ";
92+
} else {
93+
this._objectFieldValueSeparatorWithSpaces = separators.getObjectFieldValueSeparator() + " ";
94+
}
95+
return this;
96+
}
97+
}
98+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/*
2+
* Copyright 2021-2023 DiffPlug
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.diffplug.spotless.glue.yaml;
17+
18+
import java.io.IOException;
19+
import java.io.StringWriter;
20+
import java.util.List;
21+
22+
import com.fasterxml.jackson.core.JsonFactory;
23+
import com.fasterxml.jackson.core.JsonParser;
24+
import com.fasterxml.jackson.core.JsonProcessingException;
25+
import com.fasterxml.jackson.databind.JsonNode;
26+
import com.fasterxml.jackson.databind.ObjectMapper;
27+
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
28+
import com.fasterxml.jackson.dataformat.yaml.YAMLFactoryBuilder;
29+
import com.fasterxml.jackson.dataformat.yaml.YAMLGenerator;
30+
31+
import com.diffplug.spotless.glue.json.AJacksonFormatterFunc;
32+
import com.diffplug.spotless.yaml.JacksonYamlConfig;
33+
34+
public class JacksonYamlFormatterFunc extends AJacksonFormatterFunc {
35+
final JacksonYamlConfig yamlConfig;
36+
37+
public JacksonYamlFormatterFunc(JacksonYamlConfig jacksonConfig) {
38+
super(jacksonConfig);
39+
this.yamlConfig = jacksonConfig;
40+
41+
if (jacksonConfig == null) {
42+
throw new IllegalArgumentException("ARG");
43+
}
44+
}
45+
46+
protected JsonFactory makeJsonFactory() {
47+
YAMLFactoryBuilder yamlFactoryBuilder = new YAMLFactoryBuilder(new YAMLFactory());
48+
49+
// Configure the ObjectMapper
50+
// https://github.com/FasterXML/jackson-databind#commonly-used-features
51+
yamlConfig.getYamlFeatureToToggle().forEach((rawFeature, toggle) -> {
52+
// https://stackoverflow.com/questions/3735927/java-instantiating-an-enum-using-reflection
53+
YAMLGenerator.Feature feature = YAMLGenerator.Feature.valueOf(rawFeature);
54+
55+
yamlFactoryBuilder.configure(feature, toggle);
56+
});
57+
58+
return yamlFactoryBuilder.build();
59+
}
60+
61+
@Override
62+
protected String format(ObjectMapper objectMapper, String input) throws IllegalArgumentException, IOException {
63+
try {
64+
// https://stackoverflow.com/questions/25222327/deserialize-pojos-from-multiple-yaml-documents-in-a-single-file-in-jackson
65+
// https://github.com/FasterXML/jackson-dataformats-text/issues/66#issuecomment-375328648
66+
JsonParser yamlParser = objectMapper.getFactory().createParser(input);
67+
List<JsonNode> documents = objectMapper.readValues(yamlParser, JsonNode.class).readAll();
68+
69+
// https://github.com/FasterXML/jackson-dataformats-text/issues/66#issuecomment-554265055
70+
// https://github.com/FasterXML/jackson-dataformats-text/issues/66#issuecomment-554265055
71+
StringWriter stringWriter = new StringWriter();
72+
objectMapper.writer().writeValues(stringWriter).writeAll(documents).close();
73+
return stringWriter.toString();
74+
} catch (JsonProcessingException e) {
75+
throw new IllegalArgumentException("Unable to format. input='" + input + "'", e);
76+
}
77+
}
78+
}

0 commit comments

Comments
 (0)