Skip to content

Commit d3052d3

Browse files
committed
Base implementation
1 parent b2778cd commit d3052d3

File tree

5 files changed

+250
-0
lines changed

5 files changed

+250
-0
lines changed
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
/*
2+
* Copyright 2021 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.yaml;
17+
18+
import java.io.IOException;
19+
import java.io.Serializable;
20+
import java.lang.reflect.InvocationTargetException;
21+
import java.lang.reflect.Method;
22+
import java.util.Arrays;
23+
import java.util.List;
24+
import java.util.Objects;
25+
26+
import com.diffplug.spotless.FormatterFunc;
27+
import com.diffplug.spotless.FormatterStep;
28+
import com.diffplug.spotless.JarState;
29+
import com.diffplug.spotless.Provisioner;
30+
31+
/**
32+
* Simple YAML formatter which reformats the file according to Jackson YAMLFactory.
33+
*/
34+
public final class YamlJacksonStep {
35+
private static final String MAVEN_COORDINATE = "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:";
36+
private static final String DEFAULT_VERSION = "2.13.4";
37+
38+
public static String defaultVersion() {
39+
return DEFAULT_VERSION;
40+
}
41+
42+
public static FormatterStep create(List<String> enabledFeatures,
43+
List<String> disabledFeatures,
44+
String jacksonVersion,
45+
Provisioner provisioner) {
46+
Objects.requireNonNull(provisioner, "provisioner cannot be null");
47+
return FormatterStep.createLazy("yaml",
48+
() -> new State(enabledFeatures, disabledFeatures, jacksonVersion, provisioner),
49+
State::toFormatter);
50+
}
51+
52+
public static FormatterStep create(Provisioner provisioner) {
53+
return create(Arrays.asList("INDENT_OUTPUT"), Arrays.asList(), defaultVersion(), provisioner);
54+
}
55+
56+
private static final class State implements Serializable {
57+
private static final long serialVersionUID = 1L;
58+
59+
private final List<String> enabledFeatures;
60+
private final List<String> disabledFeatures;
61+
62+
private final JarState jarState;
63+
64+
private State(List<String> enabledFeatures,
65+
List<String> disabledFeatures,
66+
String jacksonVersion,
67+
Provisioner provisioner) throws IOException {
68+
this.enabledFeatures = enabledFeatures;
69+
this.disabledFeatures = disabledFeatures;
70+
71+
this.jarState = JarState.from(MAVEN_COORDINATE + jacksonVersion, provisioner);
72+
}
73+
74+
FormatterFunc toFormatter() {
75+
Class<?> jsonFactoryClass;
76+
Class<?> yamlFactoryClass;
77+
Class<?> objectMapperClass;
78+
79+
Class<?> serializationFeatureClass;
80+
Method enableFeature;
81+
Method disableFeature;
82+
83+
Method stringToObject;
84+
Method objectToString;
85+
try {
86+
ClassLoader classLoader = jarState.getClassLoader();
87+
jsonFactoryClass = classLoader.loadClass("com.fasterxml.jackson.core.JsonFactory");
88+
yamlFactoryClass = classLoader.loadClass("com.fasterxml.jackson.dataformat.yaml.YAMLFactory");
89+
90+
objectMapperClass = classLoader.loadClass("com.fasterxml.jackson.databind.ObjectMapper");
91+
92+
// Configure the ObjectMapper
93+
// https://github.com/FasterXML/jackson-databind#commonly-used-features
94+
{
95+
serializationFeatureClass =
96+
classLoader.loadClass("com.fasterxml.jackson.databind.SerializationFeature");
97+
enableFeature = objectMapperClass.getMethod("enable", serializationFeatureClass);
98+
disableFeature = objectMapperClass.getMethod("disable", serializationFeatureClass);
99+
}
100+
101+
stringToObject = objectMapperClass.getMethod("readValue", String.class, Class.class);
102+
objectToString = objectMapperClass.getMethod("writeValueAsString", Object.class);
103+
} catch (ClassNotFoundException | NoSuchMethodException e) {
104+
throw new IllegalStateException("There was a problem preparing org.json dependencies", e);
105+
}
106+
107+
return s -> {
108+
if (s.isEmpty()) {
109+
return s;
110+
}
111+
112+
Object yamlFactory = yamlFactoryClass.getConstructor().newInstance();
113+
Object objectMapper = objectMapperClass.getConstructor(jsonFactoryClass).newInstance(yamlFactory);
114+
115+
for (String feature : enabledFeatures) {
116+
// https://stackoverflow.com/questions/3735927/java-instantiating-an-enum-using-reflection
117+
Object indentOutput = Enum.valueOf(serializationFeatureClass.asSubclass(Enum.class), feature);
118+
119+
enableFeature.invoke(objectMapper, indentOutput);
120+
}
121+
122+
for (String feature : disabledFeatures) {
123+
// https://stackoverflow.com/questions/3735927/java-instantiating-an-enum-using-reflection
124+
Object indentOutput = Enum.valueOf(serializationFeatureClass.asSubclass(Enum.class), feature);
125+
126+
disableFeature.invoke(objectMapper, indentOutput);
127+
}
128+
129+
return format(objectMapper, stringToObject, objectToString, s);
130+
};
131+
}
132+
133+
private String format(Object objectMapper, Method stringToObject, Method objectToString, String s)
134+
throws IllegalAccessException, IllegalArgumentException {
135+
try {
136+
Object parsed = stringToObject.invoke(s, Object.class);
137+
return (String) objectToString.invoke(objectMapper, parsed);
138+
} catch (InvocationTargetException ex) {
139+
throw new AssertionError("Unable to format YAML", ex.getCause());
140+
}
141+
}
142+
}
143+
144+
private YamlJacksonStep() {
145+
// cannot be directly instantiated
146+
}
147+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* Copyright 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.maven.yaml;
17+
18+
import java.util.Arrays;
19+
import java.util.List;
20+
21+
import org.apache.maven.plugins.annotations.Parameter;
22+
23+
import com.diffplug.spotless.FormatterStep;
24+
import com.diffplug.spotless.maven.FormatterStepConfig;
25+
import com.diffplug.spotless.maven.FormatterStepFactory;
26+
import com.diffplug.spotless.yaml.YamlJacksonStep;
27+
28+
public class JacksonYaml implements FormatterStepFactory {
29+
30+
@Parameter
31+
private String version = YamlJacksonStep.defaultVersion();
32+
33+
@Parameter
34+
private String[] enabledFeatures = new String[] { "INDENT_OUTPUT" };
35+
36+
@Parameter
37+
private String[] disabledFeatures = new String[0];
38+
39+
@Override
40+
public FormatterStep newFormatterStep(FormatterStepConfig stepConfig) {
41+
List<String> enabledFeaturesAsList = Arrays.asList(enabledFeatures);
42+
List<String> disabledFeaturesAsList = Arrays.asList(disabledFeatures);
43+
return YamlJacksonStep
44+
.create(enabledFeaturesAsList, disabledFeaturesAsList, version, stepConfig.getProvisioner());
45+
}
46+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
* Copyright 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.maven.yaml;
17+
18+
import java.util.Collections;
19+
import java.util.Set;
20+
21+
import com.diffplug.spotless.maven.FormatterFactory;
22+
23+
/**
24+
* A {@link FormatterFactory} implementation that corresponds to {@code <yaml>...</yaml>} configuration element.
25+
*/
26+
public class Yaml extends FormatterFactory {
27+
@Override
28+
public Set<String> defaultIncludes() {
29+
return Collections.emptySet();
30+
}
31+
32+
@Override
33+
public String licenseHeaderDelimiter() {
34+
return null;
35+
}
36+
37+
public void addJackson(JacksonYaml jackson) {
38+
addStepFactory(jackson);
39+
}
40+
41+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
hr:
3+
- Mark McGwire
4+
# Following node labeled SS
5+
- &SS Sammy Sosa
6+
rbi:
7+
- *SS # Subsequent occurrence
8+
- Ken Griffey
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
hr:
3+
- Mark McGwire
4+
# Following node labeled SS
5+
- &SS Sammy Sosa
6+
rbi:
7+
- *SS # Subsequent occurrence
8+
- Ken Griffey

0 commit comments

Comments
 (0)