Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add JSON jackson step, Refactor with Yaml, enable endWithEol, feature… #1492

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ We adhere to the [keepachangelog](https://keepachangelog.com/en/1.0.0/) format (
### Fixed
* 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)
### Changes
* Rename `YamlJacksonStep` into `JacksonYamlStep` while normalizing Jackson usage ([#1492](https://github.com/diffplug/spotless/pull/1492))

## [2.32.0] - 2023-01-13
### Added
Expand Down
1 change: 1 addition & 0 deletions lib/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ dependencies {
palantirJavaFormatCompileOnly 'com.palantir.javaformat:palantir-java-format:1.1.0' // this version needs to stay compilable against Java 8 for CI Job testNpm

// used jackson-based formatters
jacksonCompileOnly 'com.fasterxml.jackson.core:jackson-databind:2.14.1'
jacksonCompileOnly 'com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.14.1'

String VER_KTFMT = '0.42'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/*
* Copyright 2021-2023 DiffPlug
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.diffplug.spotless.glue.json;

import java.io.IOException;
import java.util.Map;

import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.PrettyPrinter;
import com.fasterxml.jackson.core.util.DefaultPrettyPrinter;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;

import com.diffplug.spotless.FormatterFunc;
import com.diffplug.spotless.json.JacksonConfig;

/**
* A {@link FormatterFunc} based on Jackson library
*/
// https://github.com/FasterXML/jackson-dataformats-text/issues/372
public abstract class AJacksonFormatterFunc implements FormatterFunc {
private JacksonConfig jacksonConfig;

public AJacksonFormatterFunc(JacksonConfig jacksonConfig) {
this.jacksonConfig = jacksonConfig;
}

@Override
public String apply(String input) throws Exception {
ObjectMapper objectMapper = makeObjectMapper();

return format(objectMapper, input);
}

protected String format(ObjectMapper objectMapper, String input) throws IllegalArgumentException, IOException {
try {
// ObjectNode is not compatible with SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS
Map objectNode = objectMapper.readValue(input, Map.class);
String output = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(objectNode);

return output;
} catch (JsonProcessingException e) {
throw new IllegalArgumentException("Unable to format. input='" + input + "'", e);
}
}

/**
* @return a {@link JsonFactory}. May be overridden to handle alternative formats.
* @see <a href="https://github.com/FasterXML/jackson-dataformats-text">jackson-dataformats-text</a>
*/
protected abstract JsonFactory makeJsonFactory();

protected ObjectMapper makeObjectMapper() {
JsonFactory jsonFactory = makeJsonFactory();
ObjectMapper objectMapper = new ObjectMapper(jsonFactory);

objectMapper.setDefaultPrettyPrinter(makePrettyPrinter());

// Configure the ObjectMapper
// https://github.com/FasterXML/jackson-databind#commonly-used-features
jacksonConfig.getFeatureToToggle().forEach((rawFeature, toggle) -> {
// https://stackoverflow.com/questions/3735927/java-instantiating-an-enum-using-reflection
SerializationFeature feature = SerializationFeature.valueOf(rawFeature);

objectMapper.configure(feature, toggle);
});

return objectMapper;
}

protected PrettyPrinter makePrettyPrinter() {
return new DefaultPrettyPrinter();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
/*
* Copyright 2021-2023 DiffPlug
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.diffplug.spotless.glue.json;

import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonFactoryBuilder;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.util.DefaultIndenter;
import com.fasterxml.jackson.core.util.DefaultPrettyPrinter;
import com.fasterxml.jackson.core.util.Separators;

import com.diffplug.spotless.FormatterFunc;
import com.diffplug.spotless.json.JacksonJsonConfig;

/**
* A {@link FormatterFunc} based on Jackson library
*/
// https://github.com/FasterXML/jackson-dataformats-text/issues/372
public class JacksonJsonFormatterFunc extends AJacksonFormatterFunc {
private JacksonJsonConfig jacksonConfig;

public JacksonJsonFormatterFunc(JacksonJsonConfig jacksonConfig) {
super(jacksonConfig);
this.jacksonConfig = jacksonConfig;
}

/**
* @return a {@link JsonFactory}. May be overridden to handle alternative formats.
* @see <a href="https://github.com/FasterXML/jackson-dataformats-text">jackson-dataformats-text</a>
*/
protected JsonFactory makeJsonFactory() {
JsonFactory jsonFactory = new JsonFactoryBuilder().build();

// Configure the ObjectMapper
// https://github.com/FasterXML/jackson-databind#commonly-used-features
jacksonConfig.getJsonFeatureToToggle().forEach((rawFeature, toggle) -> {
// https://stackoverflow.com/questions/3735927/java-instantiating-an-enum-using-reflection
JsonGenerator.Feature feature = JsonGenerator.Feature.valueOf(rawFeature);

jsonFactory.configure(feature, toggle);
});

return jsonFactory;
}

@Override
protected DefaultPrettyPrinter makePrettyPrinter() {
boolean spaceBeforeSeparator = jacksonConfig.isSpaceBeforeSeparator();

// DefaultIndenter default constructor relies on 2 whitespaces as default tabulation
// By we want to force '\n' as eol given Spotless provides LF-input (whatever the actual File content/current OS)
DefaultPrettyPrinter.Indenter indenter = new DefaultIndenter(" ", "\n");
DefaultPrettyPrinter printer = new SpotlessJsonPrettyPrinter(spaceBeforeSeparator);

printer.indentObjectsWith(indenter);
printer.indentArraysWith(indenter);
return printer;
}

protected static class SpotlessJsonPrettyPrinter extends DefaultPrettyPrinter {
private static final long serialVersionUID = 1L;
private final boolean spaceBeforeSeparator;

public SpotlessJsonPrettyPrinter(boolean spaceBeforeSeparator) {
this.spaceBeforeSeparator = spaceBeforeSeparator;
}

@Override
public DefaultPrettyPrinter createInstance() {
return new SpotlessJsonPrettyPrinter(spaceBeforeSeparator);
}

@Override
public DefaultPrettyPrinter withSeparators(Separators separators) {
this._separators = separators;
if (spaceBeforeSeparator) {
// This is Jackson default behavior
this._objectFieldValueSeparatorWithSpaces = " " + separators.getObjectFieldValueSeparator() + " ";
} else {
this._objectFieldValueSeparatorWithSpaces = separators.getObjectFieldValueSeparator() + " ";
}
return this;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/*
* Copyright 2021-2023 DiffPlug
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.diffplug.spotless.glue.yaml;

import java.io.IOException;
import java.io.StringWriter;
import java.util.List;

import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactoryBuilder;
import com.fasterxml.jackson.dataformat.yaml.YAMLGenerator;

import com.diffplug.spotless.glue.json.AJacksonFormatterFunc;
import com.diffplug.spotless.yaml.JacksonYamlConfig;

public class JacksonYamlFormatterFunc extends AJacksonFormatterFunc {
final JacksonYamlConfig yamlConfig;

public JacksonYamlFormatterFunc(JacksonYamlConfig jacksonConfig) {
super(jacksonConfig);
this.yamlConfig = jacksonConfig;

if (jacksonConfig == null) {
throw new IllegalArgumentException("ARG");
}
}

protected JsonFactory makeJsonFactory() {
YAMLFactoryBuilder yamlFactoryBuilder = new YAMLFactoryBuilder(new YAMLFactory());

// Configure the ObjectMapper
// https://github.com/FasterXML/jackson-databind#commonly-used-features
yamlConfig.getYamlFeatureToToggle().forEach((rawFeature, toggle) -> {
// https://stackoverflow.com/questions/3735927/java-instantiating-an-enum-using-reflection
YAMLGenerator.Feature feature = YAMLGenerator.Feature.valueOf(rawFeature);

yamlFactoryBuilder.configure(feature, toggle);
});

return yamlFactoryBuilder.build();
}

@Override
protected String format(ObjectMapper objectMapper, String input) throws IllegalArgumentException, IOException {
try {
// https://stackoverflow.com/questions/25222327/deserialize-pojos-from-multiple-yaml-documents-in-a-single-file-in-jackson
// https://github.com/FasterXML/jackson-dataformats-text/issues/66#issuecomment-375328648
JsonParser yamlParser = objectMapper.getFactory().createParser(input);
List<JsonNode> documents = objectMapper.readValues(yamlParser, JsonNode.class).readAll();

// https://github.com/FasterXML/jackson-dataformats-text/issues/66#issuecomment-554265055
// https://github.com/FasterXML/jackson-dataformats-text/issues/66#issuecomment-554265055
StringWriter stringWriter = new StringWriter();
objectMapper.writer().writeValues(stringWriter).writeAll(documents).close();
return stringWriter.toString();
} catch (JsonProcessingException e) {
throw new IllegalArgumentException("Unable to format. input='" + input + "'", e);
}
}
}

This file was deleted.

Loading