Update Jackson support to require Jackson 3
Closes gh-45535
This commit is contained in:
parent
8bfb170ebc
commit
d353038c58
|
@ -59,8 +59,6 @@ dependencies {
|
|||
|
||||
testImplementation(project(":test-support:spring-boot-gradle-test-support"))
|
||||
testImplementation(project(":test-support:spring-boot-test-support"))
|
||||
testImplementation("com.fasterxml.jackson.core:jackson-databind")
|
||||
testImplementation("com.fasterxml.jackson.module:jackson-module-parameter-names")
|
||||
testImplementation("com.tngtech.archunit:archunit-junit5:1.4.0")
|
||||
testImplementation("net.java.dev.jna:jna-platform")
|
||||
testImplementation("org.apache.commons:commons-compress")
|
||||
|
@ -70,6 +68,7 @@ dependencies {
|
|||
testImplementation("org.jetbrains.kotlin:kotlin-compiler-runner:$kotlinVersion")
|
||||
testImplementation("org.jetbrains.kotlin:kotlin-daemon-client:$kotlinVersion")
|
||||
testImplementation("org.tomlj:tomlj:1.0.0")
|
||||
testImplementation("tools.jackson.core:jackson-databind")
|
||||
}
|
||||
|
||||
repositories {
|
||||
|
|
|
@ -22,9 +22,6 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonView;
|
||||
import com.fasterxml.jackson.core.Versioned;
|
||||
import com.fasterxml.jackson.databind.Module;
|
||||
import com.fasterxml.jackson.module.paramnames.ParameterNamesModule;
|
||||
import com.sun.jna.Platform;
|
||||
import io.spring.gradle.dependencymanagement.DependencyManagementPlugin;
|
||||
import org.antlr.v4.runtime.Lexer;
|
||||
|
@ -39,6 +36,8 @@ import org.jetbrains.kotlin.gradle.plugin.KotlinCompilerPluginSupportPlugin;
|
|||
import org.jetbrains.kotlin.project.model.LanguageSettings;
|
||||
import org.jetbrains.kotlin.tooling.core.KotlinToolingVersion;
|
||||
import org.tomlj.Toml;
|
||||
import tools.jackson.core.JsonParser;
|
||||
import tools.jackson.databind.JacksonModule;
|
||||
|
||||
import org.springframework.asm.ClassVisitor;
|
||||
import org.springframework.boot.buildpack.platform.build.BuildRequest;
|
||||
|
@ -103,9 +102,8 @@ public class PluginClasspathGradleBuild extends GradleBuild {
|
|||
classpath.add(new File(pathOfJarContaining(HttpClientConnectionManager.class)));
|
||||
classpath.add(new File(pathOfJarContaining(HttpRequest.class)));
|
||||
classpath.add(new File(pathOfJarContaining(HttpVersionPolicy.class)));
|
||||
classpath.add(new File(pathOfJarContaining(Module.class)));
|
||||
classpath.add(new File(pathOfJarContaining(Versioned.class)));
|
||||
classpath.add(new File(pathOfJarContaining(ParameterNamesModule.class)));
|
||||
classpath.add(new File(pathOfJarContaining(JacksonModule.class)));
|
||||
classpath.add(new File(pathOfJarContaining(JsonParser.class)));
|
||||
classpath.add(new File(pathOfJarContaining("com.github.openjson.JSONObject")));
|
||||
classpath.add(new File(pathOfJarContaining(JsonView.class)));
|
||||
classpath.add(new File(pathOfJarContaining(Platform.class)));
|
||||
|
|
|
@ -43,9 +43,9 @@ dependencies {
|
|||
checkstyle("com.puppycrawl.tools:checkstyle:${checkstyle.toolVersion}")
|
||||
checkstyle("io.spring.javaformat:spring-javaformat-checkstyle:${javaFormatVersion}")
|
||||
|
||||
implementation(platform("com.fasterxml.jackson:jackson-bom:${jacksonVersion}"))
|
||||
implementation(platform("com.fasterxml.jackson:jackson-bom:${jackson2Version}"))
|
||||
implementation(platform("tools.jackson:jackson-bom:${jacksonVersion}"))
|
||||
implementation(platform("org.springframework:spring-framework-bom:${springFrameworkVersion}"))
|
||||
implementation("com.fasterxml.jackson.core:jackson-databind")
|
||||
implementation("com.github.node-gradle:gradle-node-plugin:3.5.1")
|
||||
implementation("com.gradle:develocity-gradle-plugin:3.17.2")
|
||||
implementation("com.tngtech.archunit:archunit:1.4.1")
|
||||
|
@ -65,6 +65,7 @@ dependencies {
|
|||
implementation("org.springframework:spring-web")
|
||||
implementation("org.yaml:snakeyaml:${snakeYamlVersion}")
|
||||
implementation("io.spring.gradle.nullability:nullability-plugin:${nullabilityPluginVersion}")
|
||||
implementation("tools.jackson.core:jackson-databind")
|
||||
|
||||
testImplementation(platform("org.junit:junit-bom:${junitJupiterVersion}"))
|
||||
testImplementation("org.assertj:assertj-core:${assertjVersion}")
|
||||
|
|
|
@ -6,4 +6,11 @@
|
|||
<module name="io.spring.javaformat.checkstyle.SpringChecks">
|
||||
<property name="excludes" value="com.puppycrawl.tools.checkstyle.checks.javadoc.JavadocPackageCheck" />
|
||||
</module>
|
||||
</module>
|
||||
<module name="com.puppycrawl.tools.checkstyle.TreeWalker">
|
||||
<module name="com.puppycrawl.tools.checkstyle.checks.imports.IllegalImportCheck">
|
||||
<property name="regexp" value="true" />
|
||||
<property name="illegalPkgs"
|
||||
value="^com\.fasterxml\.jackson(?!\.annotation).*" />
|
||||
</module>
|
||||
</module>
|
||||
</module>
|
||||
|
|
|
@ -17,8 +17,6 @@
|
|||
package org.springframework.boot.build;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
|
@ -26,7 +24,6 @@ import java.util.LinkedHashMap;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.github.gradle.node.NodeExtension;
|
||||
import com.github.gradle.node.npm.task.NpmInstallTask;
|
||||
import io.spring.gradle.antora.GenerateAntoraYmlPlugin;
|
||||
|
@ -44,6 +41,7 @@ import org.gradle.api.provider.Provider;
|
|||
import org.gradle.api.tasks.Copy;
|
||||
import org.gradle.api.tasks.TaskContainer;
|
||||
import org.gradle.api.tasks.TaskProvider;
|
||||
import tools.jackson.databind.ObjectMapper;
|
||||
|
||||
import org.springframework.boot.build.antora.AntoraAsciidocAttributes;
|
||||
import org.springframework.boot.build.antora.GenerateAntoraPlaybook;
|
||||
|
@ -198,18 +196,13 @@ public class AntoraConventions {
|
|||
}
|
||||
|
||||
private String getUiBundleUrl(Project project) {
|
||||
try {
|
||||
File packageJson = project.getRootProject().file("antora/package.json");
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
Map<?, ?> json = objectMapper.readerFor(Map.class).readValue(packageJson);
|
||||
Map<?, ?> config = (json != null) ? (Map<?, ?>) json.get("config") : null;
|
||||
String url = (config != null) ? (String) config.get("ui-bundle-url") : null;
|
||||
Assert.state(StringUtils.hasText(url.toString()), "package.json has not ui-bundle-url config");
|
||||
return url;
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new UncheckedIOException(ex);
|
||||
}
|
||||
File packageJson = project.getRootProject().file("antora/package.json");
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
Map<?, ?> json = objectMapper.readerFor(Map.class).readValue(packageJson);
|
||||
Map<?, ?> config = (json != null) ? (Map<?, ?>) json.get("config") : null;
|
||||
String url = (config != null) ? (String) config.get("ui-bundle-url") : null;
|
||||
Assert.state(StringUtils.hasText(url.toString()), "package.json has not ui-bundle-url config");
|
||||
return url;
|
||||
}
|
||||
|
||||
private void configureNodeExtension(Project project, NodeExtension nodeExtension) {
|
||||
|
|
|
@ -162,10 +162,9 @@ public class AntoraAsciidocAttributes {
|
|||
attributes.put("version-native-build-tools", (String) this.projectProperties.get("nativeBuildToolsVersion"));
|
||||
attributes.put("version-graal", (String) this.projectProperties.get("graalVersion"));
|
||||
addDependencyVersion(attributes, "jackson-annotations", "com.fasterxml.jackson.core:jackson-annotations");
|
||||
addDependencyVersion(attributes, "jackson-core", "com.fasterxml.jackson.core:jackson-core");
|
||||
addDependencyVersion(attributes, "jackson-databind", "com.fasterxml.jackson.core:jackson-databind");
|
||||
addDependencyVersion(attributes, "jackson-dataformat-xml",
|
||||
"com.fasterxml.jackson.dataformat:jackson-dataformat-xml");
|
||||
addDependencyVersion(attributes, "jackson-core", "tools.jackson.core:jackson-core");
|
||||
addDependencyVersion(attributes, "jackson-databind", "tools.jackson.core:jackson-databind");
|
||||
addDependencyVersion(attributes, "jackson-dataformat-xml", "tools.jackson.dataformat:jackson-dataformat-xml");
|
||||
addSpringDataDependencyVersion(attributes, internal, "spring-data-commons");
|
||||
addSpringDataDependencyVersion(attributes, internal, "spring-data-couchbase");
|
||||
addSpringDataDependencyVersion(attributes, internal, "spring-data-cassandra");
|
||||
|
|
|
@ -25,10 +25,8 @@ import java.net.URI;
|
|||
import java.util.List;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude.Include;
|
||||
import com.fasterxml.jackson.annotation.JsonSetter;
|
||||
import com.fasterxml.jackson.annotation.Nulls;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
import tools.jackson.databind.ObjectMapper;
|
||||
import tools.jackson.databind.json.JsonMapper;
|
||||
|
||||
/**
|
||||
* A resolved bom.
|
||||
|
@ -42,10 +40,9 @@ public record ResolvedBom(Id id, List<ResolvedLibrary> libraries) {
|
|||
private static final ObjectMapper objectMapper;
|
||||
|
||||
static {
|
||||
ObjectMapper mapper = new ObjectMapper().enable(SerializationFeature.INDENT_OUTPUT)
|
||||
.setDefaultPropertyInclusion(Include.NON_EMPTY);
|
||||
mapper.configOverride(List.class).setSetterInfo(JsonSetter.Value.forValueNulls(Nulls.AS_EMPTY));
|
||||
objectMapper = mapper;
|
||||
objectMapper = JsonMapper.builder()
|
||||
.changeDefaultPropertyInclusion((value) -> value.withContentInclusion(Include.NON_EMPTY))
|
||||
.build();
|
||||
}
|
||||
|
||||
public static ResolvedBom readFrom(File file) {
|
||||
|
@ -58,12 +55,7 @@ public record ResolvedBom(Id id, List<ResolvedLibrary> libraries) {
|
|||
}
|
||||
|
||||
public void writeTo(Writer writer) {
|
||||
try {
|
||||
objectMapper.writeValue(writer, this);
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new UncheckedIOException(ex);
|
||||
}
|
||||
objectMapper.writeValue(writer, this);
|
||||
}
|
||||
|
||||
public record ResolvedLibrary(String name, String version, String versionProperty, List<Id> managedDependencies,
|
||||
|
|
|
@ -19,9 +19,8 @@ package org.springframework.boot.build.bom.bomr.github;
|
|||
import java.util.Base64;
|
||||
import java.util.Collections;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.converter.json.JacksonJsonHttpMessageConverter;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import org.springframework.web.util.DefaultUriBuilderFactory;
|
||||
import org.springframework.web.util.UriTemplateHandler;
|
||||
|
@ -61,8 +60,7 @@ final class StandardGitHub implements GitHub {
|
|||
|
||||
@SuppressWarnings({ "deprecation", "removal" })
|
||||
private RestTemplate createRestTemplate() {
|
||||
return new RestTemplate(Collections.singletonList(
|
||||
new org.springframework.http.converter.json.MappingJackson2HttpMessageConverter(new ObjectMapper())));
|
||||
return new RestTemplate(Collections.singletonList(new JacksonJsonHttpMessageConverter()));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -28,9 +28,6 @@ import java.util.Iterator;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonParseException;
|
||||
import com.fasterxml.jackson.databind.JsonMappingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.gradle.api.file.FileTree;
|
||||
import org.gradle.api.file.RegularFileProperty;
|
||||
import org.gradle.api.tasks.InputFiles;
|
||||
|
@ -40,6 +37,7 @@ import org.gradle.api.tasks.PathSensitivity;
|
|||
import org.gradle.api.tasks.SourceTask;
|
||||
import org.gradle.api.tasks.TaskAction;
|
||||
import org.gradle.api.tasks.VerificationException;
|
||||
import tools.jackson.databind.ObjectMapper;
|
||||
|
||||
/**
|
||||
* {@link SourceTask} that checks additional Spring configuration metadata files.
|
||||
|
@ -65,7 +63,7 @@ public abstract class CheckAdditionalSpringConfigurationMetadata extends SourceT
|
|||
}
|
||||
|
||||
@TaskAction
|
||||
void check() throws JsonParseException, IOException {
|
||||
void check() throws IOException {
|
||||
Report report = createReport();
|
||||
File reportFile = getReportLocation().get().getAsFile();
|
||||
Files.write(reportFile.toPath(), report, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
|
||||
|
@ -76,7 +74,7 @@ public abstract class CheckAdditionalSpringConfigurationMetadata extends SourceT
|
|||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Report createReport() throws IOException, JsonParseException, JsonMappingException {
|
||||
private Report createReport() {
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
Report report = new Report();
|
||||
for (File file : getSource().getFiles()) {
|
||||
|
|
|
@ -26,9 +26,6 @@ import java.util.Iterator;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonParseException;
|
||||
import com.fasterxml.jackson.databind.JsonMappingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.gradle.api.DefaultTask;
|
||||
import org.gradle.api.file.RegularFileProperty;
|
||||
import org.gradle.api.provider.ListProperty;
|
||||
|
@ -40,6 +37,7 @@ import org.gradle.api.tasks.PathSensitivity;
|
|||
import org.gradle.api.tasks.SourceTask;
|
||||
import org.gradle.api.tasks.TaskAction;
|
||||
import org.gradle.api.tasks.VerificationException;
|
||||
import tools.jackson.databind.ObjectMapper;
|
||||
|
||||
/**
|
||||
* {@link SourceTask} that checks {@code spring-configuration-metadata.json} files.
|
||||
|
@ -65,7 +63,7 @@ public abstract class CheckSpringConfigurationMetadata extends DefaultTask {
|
|||
public abstract ListProperty<String> getExclusions();
|
||||
|
||||
@TaskAction
|
||||
void check() throws JsonParseException, IOException {
|
||||
void check() throws IOException {
|
||||
Report report = createReport();
|
||||
File reportFile = getReportLocation().get().getAsFile();
|
||||
Files.write(reportFile.toPath(), report, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
|
||||
|
@ -76,7 +74,7 @@ public abstract class CheckSpringConfigurationMetadata extends DefaultTask {
|
|||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Report createReport() throws IOException, JsonParseException, JsonMappingException {
|
||||
private Report createReport() {
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
File file = getMetadataLocation().get().getAsFile();
|
||||
Report report = new Report(this.projectRoot.relativize(file.toPath()));
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
package org.springframework.boot.build.context.properties;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
|
@ -25,7 +24,7 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import tools.jackson.databind.ObjectMapper;
|
||||
|
||||
/**
|
||||
* Configuration properties read from one or more
|
||||
|
@ -56,20 +55,15 @@ final class ConfigurationProperties {
|
|||
|
||||
@SuppressWarnings("unchecked")
|
||||
static ConfigurationProperties fromFiles(Iterable<File> files) {
|
||||
try {
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
List<ConfigurationProperty> properties = new ArrayList<>();
|
||||
for (File file : files) {
|
||||
Map<String, Object> json = objectMapper.readValue(file, Map.class);
|
||||
for (Map<String, Object> property : (List<Map<String, Object>>) json.get("properties")) {
|
||||
properties.add(ConfigurationProperty.fromJsonProperties(property));
|
||||
}
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
List<ConfigurationProperty> properties = new ArrayList<>();
|
||||
for (File file : files) {
|
||||
Map<String, Object> json = objectMapper.readValue(file, Map.class);
|
||||
for (Map<String, Object> property : (List<Map<String, Object>>) json.get("properties")) {
|
||||
properties.add(ConfigurationProperty.fromJsonProperties(property));
|
||||
}
|
||||
return new ConfigurationProperties(properties);
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new RuntimeException("Failed to load configuration metadata", ex);
|
||||
}
|
||||
return new ConfigurationProperties(properties);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -77,12 +77,13 @@ url-spring-data-rest-site=https://spring.io/projects/spring-data-rest
|
|||
url-spring-data-rest-javadoc=https://docs.spring.io/spring-data/rest/docs/{dotxversion-spring-data-rest}/api
|
||||
url-spring-data-site=https://spring.io/projects/spring-data
|
||||
url-jackson-annotations-javadoc=https://javadoc.io/doc/com.fasterxml.jackson.core/jackson-annotations/{version-jackson-annotations}
|
||||
url-jackson-core-javadoc=https://javadoc.io/doc/com.fasterxml.jackson.core/jackson-core/{version-jackson-core}
|
||||
url-jackson-databind-javadoc=https://javadoc.io/doc/com.fasterxml.jackson.core/jackson-databind/{version-jackson-databind}
|
||||
url-jackson-dataformat-xml-javadoc=https://javadoc.io/doc/com.fasterxml.jackson.dataformat/jackson-dataformat-xml/{version-jackson-dataformat-xml}
|
||||
url-jackson-core-javadoc=https://javadoc.io/doc/tools.jackson.core/jackson-core/{version-jackson-core}
|
||||
url-jackson-databind-javadoc=https://javadoc.io/doc/tools.jackson.core/jackson-databind/{version-jackson-databind}
|
||||
url-jackson-dataformat-xml-javadoc=https://javadoc.io/doc/tools.jackson.dataformat/jackson-dataformat-xml/{version-jackson-dataformat-xml}
|
||||
|
||||
# === Javadoc Locations ===
|
||||
|
||||
javadoc-location-com-fasterxml-jackson-annotation={url-jackson-annotations-javadoc}
|
||||
javadoc-location-org-apache-pulsar-client-api={url-pulsar-client-api-javadoc}
|
||||
javadoc-location-org-apache-pulsar-reactive-client-api={url-pulsar-client-reactive-api-javadoc}
|
||||
javadoc-location-org-springframework-data-cassandra={url-spring-data-cassandra-javadoc}
|
||||
|
@ -99,10 +100,9 @@ javadoc-location-org-springframework-data-neo4j={url-spring-data-neo4j-javadoc}
|
|||
javadoc-location-org-springframework-data-r2dbc={url-spring-data-r2dbc-javadoc}
|
||||
javadoc-location-org-springframework-data-redis={url-spring-data-redis-javadoc}
|
||||
javadoc-location-org-springframework-data-rest={url-spring-data-rest-javadoc}
|
||||
javadoc-location-com-fasterxml-jackson-annotation={url-jackson-annotations-javadoc}
|
||||
javadoc-location-com-fasterxml-jackson-core={url-jackson-core-javadoc}
|
||||
javadoc-location-com-fasterxml-jackson-databind={url-jackson-databind-javadoc}
|
||||
javadoc-location-com-fasterxml-jackson-dataformat-xml={url-jackson-dataformat-xml-javadoc}
|
||||
javadoc-location-tools-jackson-core={url-jackson-core-javadoc}
|
||||
javadoc-location-tools-jackson-databind={url-jackson-databind-javadoc}
|
||||
javadoc-location-tools-jackson-dataformat-xml={url-jackson-dataformat-xml-javadoc}
|
||||
|
||||
# === API References ===
|
||||
|
||||
|
|
|
@ -280,12 +280,12 @@ class AntoraAsciidocAttributesTests {
|
|||
addMockTestcontainersVersion(versions, "rabbitmq", version);
|
||||
addMockTestcontainersVersion(versions, "redpanda", version);
|
||||
addMockTestcontainersVersion(versions, "r2dbc", version);
|
||||
addMockJacksonCoreVersion(versions, "jackson-annotations", version);
|
||||
addMockJackson2CoreVersion(versions, "jackson-annotations", version);
|
||||
addMockJacksonCoreVersion(versions, "jackson-core", version);
|
||||
addMockJacksonCoreVersion(versions, "jackson-databind", version);
|
||||
versions.put("org.apache.pulsar:pulsar-client-api", version);
|
||||
versions.put("org.apache.pulsar:pulsar-client-reactive-api", version);
|
||||
versions.put("com.fasterxml.jackson.dataformat:jackson-dataformat-xml", version);
|
||||
versions.put("tools.jackson.dataformat:jackson-dataformat-xml", version);
|
||||
return versions;
|
||||
}
|
||||
|
||||
|
@ -297,8 +297,12 @@ class AntoraAsciidocAttributesTests {
|
|||
versions.put("org.testcontainers:" + artifactId, version);
|
||||
}
|
||||
|
||||
private void addMockJacksonCoreVersion(Map<String, String> versions, String artifactId, String version) {
|
||||
private void addMockJackson2CoreVersion(Map<String, String> versions, String artifactId, String version) {
|
||||
versions.put("com.fasterxml.jackson.core:" + artifactId, version);
|
||||
}
|
||||
|
||||
private void addMockJacksonCoreVersion(Map<String, String> versions, String artifactId, String version) {
|
||||
versions.put("tools.jackson.core:" + artifactId, version);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -28,13 +28,12 @@ dependencies {
|
|||
|
||||
dockerTestRuntimeOnly("org.testcontainers:testcontainers")
|
||||
|
||||
implementation("com.fasterxml.jackson.core:jackson-databind")
|
||||
implementation("com.fasterxml.jackson.module:jackson-module-parameter-names")
|
||||
implementation("net.java.dev.jna:jna-platform")
|
||||
implementation("org.apache.commons:commons-compress")
|
||||
implementation("org.apache.httpcomponents.client5:httpclient5")
|
||||
implementation("org.springframework:spring-core")
|
||||
implementation("org.tomlj:tomlj:1.0.0")
|
||||
implementation("tools.jackson.core:jackson-databind")
|
||||
|
||||
testImplementation(project(":test-support:spring-boot-test-support"))
|
||||
}
|
||||
|
|
|
@ -23,10 +23,10 @@ import java.util.Collections;
|
|||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import tools.jackson.core.JacksonException;
|
||||
import tools.jackson.databind.JsonNode;
|
||||
import tools.jackson.databind.node.ObjectNode;
|
||||
|
||||
import org.springframework.boot.buildpack.platform.docker.type.Image;
|
||||
import org.springframework.boot.buildpack.platform.docker.type.ImageConfig;
|
||||
|
@ -152,7 +152,7 @@ class BuilderMetadata extends MappedObject {
|
|||
String json = SharedObjectMapper.get().writeValueAsString(getNode());
|
||||
update.withLabel(LABEL_NAME, json);
|
||||
}
|
||||
catch (JsonProcessingException ex) {
|
||||
catch (JacksonException ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
}
|
||||
|
@ -239,7 +239,7 @@ class BuilderMetadata extends MappedObject {
|
|||
RunImage(JsonNode node) {
|
||||
super(node, MethodHandles.lookup());
|
||||
this.image = extractImage();
|
||||
this.mirrors = childrenAt("/mirrors", JsonNode::asText);
|
||||
this.mirrors = childrenAt("/mirrors", JsonNode::asString);
|
||||
}
|
||||
|
||||
private String extractImage() {
|
||||
|
@ -352,7 +352,7 @@ class BuilderMetadata extends MappedObject {
|
|||
private final ObjectNode copy;
|
||||
|
||||
private Update(BuilderMetadata source) {
|
||||
this.copy = source.getNode().deepCopy();
|
||||
this.copy = (ObjectNode) source.getNode().deepCopy();
|
||||
}
|
||||
|
||||
private BuilderMetadata run(Consumer<Update> update) {
|
||||
|
|
|
@ -21,8 +21,8 @@ import java.lang.invoke.MethodHandles;
|
|||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import tools.jackson.databind.JsonNode;
|
||||
|
||||
import org.springframework.boot.buildpack.platform.docker.type.Image;
|
||||
import org.springframework.boot.buildpack.platform.docker.type.ImageConfig;
|
||||
|
|
|
@ -19,8 +19,8 @@ package org.springframework.boot.buildpack.platform.build;
|
|||
import java.io.IOException;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import tools.jackson.databind.JsonNode;
|
||||
|
||||
import org.springframework.boot.buildpack.platform.docker.type.Image;
|
||||
import org.springframework.boot.buildpack.platform.docker.type.ImageConfig;
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
package org.springframework.boot.buildpack.platform.docker;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.Arrays;
|
||||
|
@ -286,10 +287,13 @@ public class DockerApi {
|
|||
listener.onStart();
|
||||
try {
|
||||
try (Response response = http().post(loadUri, "application/x-tar", archive::writeTo)) {
|
||||
jsonStream().get(response.getContent(), LoadImageUpdateEvent.class, (event) -> {
|
||||
streamListener.onUpdate(event);
|
||||
listener.onUpdate(event);
|
||||
});
|
||||
InputStream content = response.getContent();
|
||||
if (content != null) {
|
||||
jsonStream().get(content, LoadImageUpdateEvent.class, (event) -> {
|
||||
streamListener.onUpdate(event);
|
||||
listener.onUpdate(event);
|
||||
});
|
||||
}
|
||||
}
|
||||
streamListener.assertValidResponseReceived();
|
||||
}
|
||||
|
@ -395,7 +399,7 @@ public class DockerApi {
|
|||
: buildUrl("/containers/create");
|
||||
try (Response response = http().post(createUri, "application/json", config::writeTo)) {
|
||||
return ContainerReference
|
||||
.of(SharedObjectMapper.get().readTree(response.getContent()).at("/Id").asText());
|
||||
.of(SharedObjectMapper.get().readTree(response.getContent()).at("/Id").asString());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -18,8 +18,8 @@ package org.springframework.boot.buildpack.platform.docker.configuration;
|
|||
|
||||
import java.lang.invoke.MethodHandles;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import tools.jackson.databind.JsonNode;
|
||||
|
||||
import org.springframework.boot.buildpack.platform.json.MappedObject;
|
||||
import org.springframework.util.Assert;
|
||||
|
|
|
@ -28,10 +28,10 @@ import java.util.HexFormat;
|
|||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.node.NullNode;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import tools.jackson.core.JacksonException;
|
||||
import tools.jackson.databind.JsonNode;
|
||||
import tools.jackson.databind.node.NullNode;
|
||||
|
||||
import org.springframework.boot.buildpack.platform.json.MappedObject;
|
||||
import org.springframework.boot.buildpack.platform.json.SharedObjectMapper;
|
||||
|
@ -120,7 +120,7 @@ final class DockerConfigurationMetadata {
|
|||
try {
|
||||
return DockerConfig.fromJson(readPathContent(path));
|
||||
}
|
||||
catch (JsonProcessingException ex) {
|
||||
catch (JacksonException ex) {
|
||||
throw new IllegalStateException("Error parsing Docker configuration file '" + path + "'", ex);
|
||||
}
|
||||
}
|
||||
|
@ -142,7 +142,7 @@ final class DockerConfigurationMetadata {
|
|||
}
|
||||
return context;
|
||||
}
|
||||
catch (JsonProcessingException ex) {
|
||||
catch (JacksonException ex) {
|
||||
throw new IllegalStateException("Error parsing Docker context metadata file '" + metaPath + "'", ex);
|
||||
}
|
||||
}
|
||||
|
@ -181,7 +181,7 @@ final class DockerConfigurationMetadata {
|
|||
super(node, MethodHandles.lookup());
|
||||
this.currentContext = valueAt("/currentContext", String.class);
|
||||
this.credsStore = valueAt("/credsStore", String.class);
|
||||
this.credHelpers = mapAt("/credHelpers", JsonNode::textValue);
|
||||
this.credHelpers = mapAt("/credHelpers", JsonNode::stringValue);
|
||||
this.auths = mapAt("/auths", Auth::new);
|
||||
}
|
||||
|
||||
|
@ -201,7 +201,7 @@ final class DockerConfigurationMetadata {
|
|||
return this.auths;
|
||||
}
|
||||
|
||||
static DockerConfig fromJson(String json) throws JsonProcessingException {
|
||||
static DockerConfig fromJson(String json) {
|
||||
return new DockerConfig(SharedObjectMapper.get().readTree(json));
|
||||
}
|
||||
|
||||
|
@ -285,7 +285,7 @@ final class DockerConfigurationMetadata {
|
|||
return new DockerContext(this.getNode(), tlsPath);
|
||||
}
|
||||
|
||||
static DockerContext fromJson(String json) throws JsonProcessingException {
|
||||
static DockerContext fromJson(String json) {
|
||||
return new DockerContext(SharedObjectMapper.get().readTree(json), null);
|
||||
}
|
||||
|
||||
|
|
|
@ -19,8 +19,8 @@ package org.springframework.boot.buildpack.platform.docker.configuration;
|
|||
import java.util.Base64;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import tools.jackson.core.JacksonException;
|
||||
|
||||
import org.springframework.boot.buildpack.platform.json.SharedObjectMapper;
|
||||
|
||||
|
@ -44,7 +44,7 @@ class JsonEncodedDockerRegistryAuthentication implements DockerRegistryAuthentic
|
|||
try {
|
||||
this.authHeader = Base64.getUrlEncoder().encodeToString(SharedObjectMapper.get().writeValueAsBytes(this));
|
||||
}
|
||||
catch (JsonProcessingException ex) {
|
||||
catch (JacksonException ex) {
|
||||
throw new IllegalStateException("Error creating Docker registry authentication header", ex);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,6 +38,7 @@ import org.apache.hc.core5.http.HttpHost;
|
|||
import org.apache.hc.core5.http.HttpRequest;
|
||||
import org.apache.hc.core5.http.io.entity.AbstractHttpEntity;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import tools.jackson.core.JacksonException;
|
||||
|
||||
import org.springframework.boot.buildpack.platform.io.Content;
|
||||
import org.springframework.boot.buildpack.platform.io.IOConsumer;
|
||||
|
@ -196,7 +197,7 @@ abstract class HttpClientTransport implements HttpTransport {
|
|||
try {
|
||||
return SharedObjectMapper.get().readValue(content, Errors.class);
|
||||
}
|
||||
catch (IOException ex) {
|
||||
catch (JacksonException ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -209,7 +210,7 @@ abstract class HttpClientTransport implements HttpTransport {
|
|||
Message message = SharedObjectMapper.get().readValue(content, Message.class);
|
||||
return (message.getMessage() != null) ? message : null;
|
||||
}
|
||||
catch (IOException ex) {
|
||||
catch (JacksonException ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ package org.springframework.boot.buildpack.platform.docker.type;
|
|||
|
||||
import java.lang.invoke.MethodHandles;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import tools.jackson.databind.JsonNode;
|
||||
|
||||
import org.springframework.boot.buildpack.platform.json.MappedObject;
|
||||
import org.springframework.util.Assert;
|
||||
|
|
|
@ -26,10 +26,10 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.node.ArrayNode;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import tools.jackson.databind.ObjectMapper;
|
||||
import tools.jackson.databind.node.ArrayNode;
|
||||
import tools.jackson.databind.node.ObjectNode;
|
||||
|
||||
import org.springframework.boot.buildpack.platform.json.SharedObjectMapper;
|
||||
import org.springframework.util.Assert;
|
||||
|
@ -51,7 +51,7 @@ public class ContainerConfig {
|
|||
|
||||
ContainerConfig(@Nullable String user, ImageReference image, String command, List<String> args,
|
||||
Map<String, String> labels, List<Binding> bindings, Map<String, String> env, @Nullable String networkMode,
|
||||
List<String> securityOptions) throws IOException {
|
||||
List<String> securityOptions) {
|
||||
Assert.notNull(image, "'image' must not be null");
|
||||
Assert.hasText(command, "'command' must not be empty");
|
||||
ObjectMapper objectMapper = SharedObjectMapper.get();
|
||||
|
@ -135,14 +135,9 @@ public class ContainerConfig {
|
|||
|
||||
private ContainerConfig run(Consumer<Update> update) {
|
||||
update.accept(this);
|
||||
try {
|
||||
Assert.state(this.command != null, "'command' must not be null");
|
||||
return new ContainerConfig(this.user, this.image, this.command, this.args, this.labels, this.bindings,
|
||||
this.env, this.networkMode, this.securityOptions);
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
Assert.state(this.command != null, "'command' must not be null");
|
||||
return new ContainerConfig(this.user, this.image, this.command, this.args, this.labels, this.bindings,
|
||||
this.env, this.networkMode, this.securityOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -20,9 +20,9 @@ import java.io.IOException;
|
|||
import java.io.InputStream;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.node.NullNode;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import tools.jackson.databind.JsonNode;
|
||||
import tools.jackson.databind.node.NullNode;
|
||||
|
||||
import org.springframework.boot.buildpack.platform.json.MappedObject;
|
||||
import org.springframework.util.Assert;
|
||||
|
|
|
@ -23,8 +23,8 @@ import java.util.Arrays;
|
|||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import tools.jackson.databind.JsonNode;
|
||||
|
||||
import org.springframework.boot.buildpack.platform.json.MappedObject;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
@ -54,7 +54,7 @@ public class Image extends MappedObject {
|
|||
|
||||
Image(JsonNode node) {
|
||||
super(node, MethodHandles.lookup());
|
||||
this.digests = childrenAt("/RepoDigests", JsonNode::asText);
|
||||
this.digests = childrenAt("/RepoDigests", JsonNode::asString);
|
||||
this.config = new ImageConfig(getNode().at("/Config"));
|
||||
this.layers = extractLayers(valueAt("/RootFS/Layers", String[].class));
|
||||
this.os = valueAt("/Os", String.class);
|
||||
|
|
|
@ -29,11 +29,11 @@ import java.util.Collections;
|
|||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.node.ArrayNode;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import tools.jackson.databind.JsonNode;
|
||||
import tools.jackson.databind.ObjectMapper;
|
||||
import tools.jackson.databind.node.ArrayNode;
|
||||
import tools.jackson.databind.node.ObjectNode;
|
||||
|
||||
import org.springframework.boot.buildpack.platform.io.Content;
|
||||
import org.springframework.boot.buildpack.platform.io.IOConsumer;
|
||||
|
@ -173,11 +173,11 @@ public class ImageArchive implements TarArchive {
|
|||
private ObjectNode createConfig(List<LayerId> writtenLayers) {
|
||||
ObjectNode config = this.objectMapper.createObjectNode();
|
||||
config.set("Config", this.imageConfig.getNodeCopy());
|
||||
config.set("Created", config.textNode(getCreatedDate()));
|
||||
config.set("Created", config.stringNode(getCreatedDate()));
|
||||
config.set("History", createHistory(writtenLayers));
|
||||
config.set("Os", config.textNode(this.os));
|
||||
config.set("Architecture", config.textNode(this.architecture));
|
||||
config.set("Variant", config.textNode(this.variant));
|
||||
config.set("Os", config.stringNode(this.os));
|
||||
config.set("Architecture", config.stringNode(this.architecture));
|
||||
config.set("Variant", config.stringNode(this.variant));
|
||||
config.set("RootFS", createRootFs(writtenLayers));
|
||||
return config;
|
||||
}
|
||||
|
@ -212,7 +212,7 @@ public class ImageArchive implements TarArchive {
|
|||
private ArrayNode createManifest(String config, List<LayerId> writtenLayers) {
|
||||
ArrayNode manifest = this.objectMapper.createArrayNode();
|
||||
ObjectNode entry = manifest.addObject();
|
||||
entry.set("Config", entry.textNode(config));
|
||||
entry.set("Config", entry.stringNode(config));
|
||||
entry.set("Layers", getManifestLayers(writtenLayers));
|
||||
if (this.tag != null) {
|
||||
entry.set("RepoTags", entry.arrayNode().add(this.tag.toString()));
|
||||
|
|
|
@ -21,7 +21,7 @@ import java.io.InputStream;
|
|||
import java.lang.invoke.MethodHandles;
|
||||
import java.util.List;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import tools.jackson.databind.JsonNode;
|
||||
|
||||
import org.springframework.boot.buildpack.platform.json.MappedObject;
|
||||
import org.springframework.util.Assert;
|
||||
|
|
|
@ -22,7 +22,7 @@ import java.lang.invoke.MethodHandles;
|
|||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import tools.jackson.databind.JsonNode;
|
||||
|
||||
import org.springframework.boot.buildpack.platform.json.MappedObject;
|
||||
|
||||
|
|
|
@ -22,9 +22,9 @@ import java.util.LinkedHashMap;
|
|||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import tools.jackson.databind.JsonNode;
|
||||
import tools.jackson.databind.node.ObjectNode;
|
||||
|
||||
import org.springframework.boot.buildpack.platform.json.MappedObject;
|
||||
|
||||
|
@ -111,7 +111,7 @@ public class ImageConfig extends MappedObject {
|
|||
private final ObjectNode copy;
|
||||
|
||||
private Update(ImageConfig source) {
|
||||
this.copy = source.getNode().deepCopy();
|
||||
this.copy = (ObjectNode) source.getNode().deepCopy();
|
||||
}
|
||||
|
||||
private ImageConfig run(Consumer<Update> update) {
|
||||
|
|
|
@ -21,8 +21,8 @@ import java.io.InputStream;
|
|||
import java.lang.invoke.MethodHandles;
|
||||
import java.util.List;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import tools.jackson.databind.JsonNode;
|
||||
|
||||
import org.springframework.boot.buildpack.platform.json.MappedObject;
|
||||
import org.springframework.util.Assert;
|
||||
|
|
|
@ -22,8 +22,8 @@ import java.lang.invoke.MethodHandles;
|
|||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import tools.jackson.databind.JsonNode;
|
||||
|
||||
import org.springframework.boot.buildpack.platform.json.MappedObject;
|
||||
import org.springframework.util.Assert;
|
||||
|
|
|
@ -20,12 +20,11 @@ import java.io.IOException;
|
|||
import java.io.InputStream;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonFactory;
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import com.fasterxml.jackson.core.JsonToken;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import tools.jackson.core.JsonParser;
|
||||
import tools.jackson.core.JsonToken;
|
||||
import tools.jackson.databind.ObjectMapper;
|
||||
import tools.jackson.databind.node.ObjectNode;
|
||||
|
||||
/**
|
||||
* Utility class that allows JSON to be parsed and processed as it's received.
|
||||
|
@ -64,8 +63,7 @@ public class JsonStream {
|
|||
* @throws IOException on IO error
|
||||
*/
|
||||
public <T> void get(InputStream content, Class<T> type, Consumer<T> consumer) throws IOException {
|
||||
JsonFactory jsonFactory = this.objectMapper.getFactory();
|
||||
try (JsonParser parser = jsonFactory.createParser(content)) {
|
||||
try (JsonParser parser = this.objectMapper.createParser(content)) {
|
||||
while (!parser.isClosed()) {
|
||||
JsonToken token = parser.nextToken();
|
||||
if (token != null && token != JsonToken.END_OBJECT) {
|
||||
|
@ -79,9 +77,9 @@ public class JsonStream {
|
|||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> @Nullable T read(JsonParser parser, Class<T> type) throws IOException {
|
||||
private <T> @Nullable T read(JsonParser parser, Class<T> type) {
|
||||
if (ObjectNode.class.isAssignableFrom(type)) {
|
||||
ObjectNode node = this.objectMapper.readTree(parser);
|
||||
ObjectNode node = (ObjectNode) this.objectMapper.readTree(parser);
|
||||
if (node == null || node.isMissingNode() || node.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -30,9 +30,10 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import tools.jackson.core.JacksonException;
|
||||
import tools.jackson.databind.JsonNode;
|
||||
import tools.jackson.databind.ObjectMapper;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StreamUtils;
|
||||
|
@ -111,7 +112,7 @@ public class MappedObject {
|
|||
return Collections.emptyList();
|
||||
}
|
||||
List<T> children = new ArrayList<>();
|
||||
node.elements().forEachRemaining((childNode) -> children.add(factory.apply(childNode)));
|
||||
node.values().forEach((childNode) -> children.add(factory.apply(childNode)));
|
||||
return Collections.unmodifiableList(children);
|
||||
}
|
||||
|
||||
|
@ -146,7 +147,7 @@ public class MappedObject {
|
|||
try {
|
||||
return SharedObjectMapper.get().treeToValue(result, type);
|
||||
}
|
||||
catch (IOException ex) {
|
||||
catch (JacksonException ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,11 +16,12 @@
|
|||
|
||||
package org.springframework.boot.buildpack.platform.json;
|
||||
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
import com.fasterxml.jackson.module.paramnames.ParameterNamesModule;
|
||||
import tools.jackson.core.json.JsonWriteFeature;
|
||||
import tools.jackson.databind.DeserializationFeature;
|
||||
import tools.jackson.databind.ObjectMapper;
|
||||
import tools.jackson.databind.PropertyNamingStrategies;
|
||||
import tools.jackson.databind.SerializationFeature;
|
||||
import tools.jackson.databind.json.JsonMapper;
|
||||
|
||||
/**
|
||||
* Provides access to a shared pre-configured {@link ObjectMapper}.
|
||||
|
@ -33,12 +34,12 @@ public final class SharedObjectMapper {
|
|||
private static final ObjectMapper INSTANCE;
|
||||
|
||||
static {
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
objectMapper.registerModule(new ParameterNamesModule());
|
||||
objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
|
||||
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||
objectMapper.setPropertyNamingStrategy(PropertyNamingStrategies.LOWER_CAMEL_CASE);
|
||||
INSTANCE = objectMapper;
|
||||
INSTANCE = JsonMapper.builder()
|
||||
.enable(SerializationFeature.INDENT_OUTPUT)
|
||||
.disable(DeserializationFeature.FAIL_ON_TRAILING_TOKENS)
|
||||
.disable(JsonWriteFeature.ESCAPE_FORWARD_SLASHES)
|
||||
.propertyNamingStrategy(PropertyNamingStrategies.LOWER_CAMEL_CASE)
|
||||
.build();
|
||||
}
|
||||
|
||||
private SharedObjectMapper() {
|
||||
|
|
|
@ -26,9 +26,6 @@ import java.util.LinkedHashMap;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.node.ArrayNode;
|
||||
import com.sun.jna.Platform;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
@ -37,6 +34,8 @@ import org.junit.jupiter.api.Test;
|
|||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.mockito.stubbing.Answer;
|
||||
import org.skyscreamer.jsonassert.JSONAssert;
|
||||
import tools.jackson.databind.JsonNode;
|
||||
import tools.jackson.databind.node.ArrayNode;
|
||||
|
||||
import org.springframework.boot.buildpack.platform.docker.DockerApi;
|
||||
import org.springframework.boot.buildpack.platform.docker.DockerApi.ContainerApi;
|
||||
|
@ -482,7 +481,7 @@ class LifecycleTests {
|
|||
return (invocation) -> {
|
||||
ContainerConfig config = invocation.getArgument(0, ContainerConfig.class);
|
||||
ArrayNode command = getCommand(config);
|
||||
String name = command.get(0).asText().substring(1).replaceAll("/", "-");
|
||||
String name = command.get(0).asString().substring(1).replaceAll("/", "-");
|
||||
this.configs.put(name, config);
|
||||
if (invocation.getArguments().length > 2) {
|
||||
this.content.put(name, invocation.getArgument(2, ContainerContent.class));
|
||||
|
@ -491,7 +490,7 @@ class LifecycleTests {
|
|||
};
|
||||
}
|
||||
|
||||
private ArrayNode getCommand(ContainerConfig config) throws JsonProcessingException {
|
||||
private ArrayNode getCommand(ContainerConfig config) {
|
||||
JsonNode node = SharedObjectMapper.get().readTree(config.toString());
|
||||
return (ArrayNode) node.at("/Cmd");
|
||||
}
|
||||
|
|
|
@ -24,10 +24,10 @@ import java.util.HashMap;
|
|||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import tools.jackson.core.type.TypeReference;
|
||||
|
||||
import org.springframework.boot.buildpack.platform.docker.type.ImageReference;
|
||||
import org.springframework.boot.buildpack.platform.json.SharedObjectMapper;
|
||||
|
|
|
@ -16,8 +16,6 @@
|
|||
|
||||
package org.springframework.boot.buildpack.platform.docker.type;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.buildpack.platform.json.AbstractJsonTests;
|
||||
|
@ -32,7 +30,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
|||
class ImageArchiveIndexTests extends AbstractJsonTests {
|
||||
|
||||
@Test
|
||||
void loadJson() throws IOException {
|
||||
void loadJson() {
|
||||
String content = getContentAsString("image-archive-index.json");
|
||||
ImageArchiveIndex index = getIndex(content);
|
||||
assertThat(index.getSchemaVersion()).isEqualTo(2);
|
||||
|
@ -43,7 +41,7 @@ class ImageArchiveIndexTests extends AbstractJsonTests {
|
|||
.isEqualTo("sha256:3bbe02431d8e5124ffe816ec27bf6508b50edd1d10218be1a03e799a186b9004");
|
||||
}
|
||||
|
||||
private ImageArchiveIndex getIndex(String content) throws IOException {
|
||||
private ImageArchiveIndex getIndex(String content) {
|
||||
return new ImageArchiveIndex(getObjectMapper().readTree(content));
|
||||
}
|
||||
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
|
||||
package org.springframework.boot.buildpack.platform.docker.type;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
@ -35,7 +34,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
|||
class ImageArchiveManifestTests extends AbstractJsonTests {
|
||||
|
||||
@Test
|
||||
void getLayersReturnsLayers() throws Exception {
|
||||
void getLayersReturnsLayers() {
|
||||
String content = getContentAsString("image-archive-manifest.json");
|
||||
ImageArchiveManifest manifest = getManifest(content);
|
||||
List<String> expectedLayers = new ArrayList<>();
|
||||
|
@ -49,7 +48,7 @@ class ImageArchiveManifestTests extends AbstractJsonTests {
|
|||
}
|
||||
|
||||
@Test
|
||||
void getLayersWithNoLayersReturnsEmptyList() throws Exception {
|
||||
void getLayersWithNoLayersReturnsEmptyList() {
|
||||
String content = "[{\"Layers\": []}]";
|
||||
ImageArchiveManifest manifest = getManifest(content);
|
||||
assertThat(manifest.getEntries()).hasSize(1);
|
||||
|
@ -57,13 +56,13 @@ class ImageArchiveManifestTests extends AbstractJsonTests {
|
|||
}
|
||||
|
||||
@Test
|
||||
void getLayersWithEmptyManifestReturnsEmptyList() throws Exception {
|
||||
void getLayersWithEmptyManifestReturnsEmptyList() {
|
||||
String content = "[]";
|
||||
ImageArchiveManifest manifest = getManifest(content);
|
||||
assertThat(manifest.getEntries()).isEmpty();
|
||||
}
|
||||
|
||||
private ImageArchiveManifest getManifest(String content) throws IOException {
|
||||
private ImageArchiveManifest getManifest(String content) {
|
||||
return new ImageArchiveManifest(getObjectMapper().readTree(content));
|
||||
}
|
||||
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
|
||||
package org.springframework.boot.buildpack.platform.docker.type;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
@ -35,7 +34,7 @@ import static org.assertj.core.api.Assertions.entry;
|
|||
class ImageConfigTests extends AbstractJsonTests {
|
||||
|
||||
@Test
|
||||
void getEnvContainsParsedValues() throws Exception {
|
||||
void getEnvContainsParsedValues() {
|
||||
ImageConfig imageConfig = getImageConfig();
|
||||
Map<String, String> env = imageConfig.getEnv();
|
||||
assertThat(env).contains(entry("PATH", "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"),
|
||||
|
@ -44,28 +43,28 @@ class ImageConfigTests extends AbstractJsonTests {
|
|||
}
|
||||
|
||||
@Test
|
||||
void whenConfigHasNoEnvThenImageConfigEnvIsEmpty() throws Exception {
|
||||
void whenConfigHasNoEnvThenImageConfigEnvIsEmpty() {
|
||||
ImageConfig imageConfig = getMinimalImageConfig();
|
||||
Map<String, String> env = imageConfig.getEnv();
|
||||
assertThat(env).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenConfigHasNoLabelsThenImageConfigLabelsIsEmpty() throws Exception {
|
||||
void whenConfigHasNoLabelsThenImageConfigLabelsIsEmpty() {
|
||||
ImageConfig imageConfig = getMinimalImageConfig();
|
||||
Map<String, String> env = imageConfig.getLabels();
|
||||
assertThat(env).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void getLabelsReturnsLabels() throws Exception {
|
||||
void getLabelsReturnsLabels() {
|
||||
ImageConfig imageConfig = getImageConfig();
|
||||
Map<String, String> labels = imageConfig.getLabels();
|
||||
assertThat(labels).hasSize(4).contains(entry("io.buildpacks.stack.id", "org.cloudfoundry.stacks.cflinuxfs3"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void updateWithLabelUpdatesLabels() throws Exception {
|
||||
void updateWithLabelUpdatesLabels() {
|
||||
ImageConfig imageConfig = getImageConfig();
|
||||
ImageConfig updatedImageConfig = imageConfig
|
||||
.copy((update) -> update.withLabel("io.buildpacks.stack.id", "test"));
|
||||
|
@ -74,11 +73,11 @@ class ImageConfigTests extends AbstractJsonTests {
|
|||
assertThat(updatedImageConfig.getLabels()).hasSize(4).contains(entry("io.buildpacks.stack.id", "test"));
|
||||
}
|
||||
|
||||
private ImageConfig getImageConfig() throws IOException {
|
||||
private ImageConfig getImageConfig() {
|
||||
return new ImageConfig(getObjectMapper().readTree(getContent("image-config.json")));
|
||||
}
|
||||
|
||||
private ImageConfig getMinimalImageConfig() throws IOException {
|
||||
private ImageConfig getMinimalImageConfig() {
|
||||
return new ImageConfig(getObjectMapper().readTree(getContent("minimal-image-config.json")));
|
||||
}
|
||||
|
||||
|
|
|
@ -16,8 +16,6 @@
|
|||
|
||||
package org.springframework.boot.buildpack.platform.docker.type;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.buildpack.platform.json.AbstractJsonTests;
|
||||
|
@ -32,7 +30,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
|||
class ManifestListTests extends AbstractJsonTests {
|
||||
|
||||
@Test
|
||||
void loadJsonFromDistributionManifestList() throws IOException {
|
||||
void loadJsonFromDistributionManifestList() {
|
||||
String content = getContentAsString("distribution-manifest-list.json");
|
||||
ManifestList manifestList = getManifestList(content);
|
||||
assertThat(manifestList.getSchemaVersion()).isEqualTo(2);
|
||||
|
@ -40,7 +38,7 @@ class ManifestListTests extends AbstractJsonTests {
|
|||
assertThat(manifestList.getManifests()).hasSize(2);
|
||||
}
|
||||
|
||||
private ManifestList getManifestList(String content) throws IOException {
|
||||
private ManifestList getManifestList(String content) {
|
||||
return new ManifestList(getObjectMapper().readTree(content));
|
||||
}
|
||||
|
||||
|
|
|
@ -16,8 +16,6 @@
|
|||
|
||||
package org.springframework.boot.buildpack.platform.docker.type;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.buildpack.platform.json.AbstractJsonTests;
|
||||
|
@ -32,7 +30,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
|||
class ManifestTests extends AbstractJsonTests {
|
||||
|
||||
@Test
|
||||
void loadJsonFromDistributionManifest() throws IOException {
|
||||
void loadJsonFromDistributionManifest() {
|
||||
String content = getContentAsString("distribution-manifest.json");
|
||||
Manifest manifestList = getManifest(content);
|
||||
assertThat(manifestList.getSchemaVersion()).isEqualTo(2);
|
||||
|
@ -41,7 +39,7 @@ class ManifestTests extends AbstractJsonTests {
|
|||
}
|
||||
|
||||
@Test
|
||||
void loadJsonFromImageManifest() throws IOException {
|
||||
void loadJsonFromImageManifest() {
|
||||
String content = getContentAsString("image-manifest.json");
|
||||
Manifest manifestList = getManifest(content);
|
||||
assertThat(manifestList.getSchemaVersion()).isEqualTo(2);
|
||||
|
@ -49,7 +47,7 @@ class ManifestTests extends AbstractJsonTests {
|
|||
assertThat(manifestList.getLayers()).hasSize(1);
|
||||
}
|
||||
|
||||
private Manifest getManifest(String content) throws IOException {
|
||||
private Manifest getManifest(String content) {
|
||||
return new Manifest(getObjectMapper().readTree(content));
|
||||
}
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ import java.io.UncheckedIOException;
|
|||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import tools.jackson.databind.ObjectMapper;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
|
|
|
@ -20,8 +20,8 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import tools.jackson.databind.node.ObjectNode;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
|
@ -44,7 +44,7 @@ class JsonStreamTests extends AbstractJsonTests {
|
|||
List<ObjectNode> result = new ArrayList<>();
|
||||
this.jsonStream.get(getContent("stream.json"), result::add);
|
||||
assertThat(result).hasSize(595);
|
||||
assertThat(result.get(594).toString())
|
||||
assertThat(result.get(594).get("status").asString())
|
||||
.contains("Status: Downloaded newer image for paketo-buildpacks/cnb:base");
|
||||
}
|
||||
|
||||
|
|
|
@ -20,8 +20,8 @@ import java.io.IOException;
|
|||
import java.io.InputStream;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import tools.jackson.databind.JsonNode;
|
||||
|
||||
import org.springframework.boot.buildpack.platform.json.MappedObjectTests.TestMappedObject.Person;
|
||||
|
||||
|
|
|
@ -16,12 +16,11 @@
|
|||
|
||||
package org.springframework.boot.buildpack.platform.json;
|
||||
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
import com.fasterxml.jackson.module.paramnames.ParameterNamesModule;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import tools.jackson.databind.DeserializationFeature;
|
||||
import tools.jackson.databind.ObjectMapper;
|
||||
import tools.jackson.databind.PropertyNamingStrategies;
|
||||
import tools.jackson.databind.SerializationFeature;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
|
@ -36,14 +35,14 @@ class SharedObjectMapperTests {
|
|||
void getReturnsConfiguredObjectMapper() {
|
||||
ObjectMapper mapper = SharedObjectMapper.get();
|
||||
assertThat(mapper).isNotNull();
|
||||
assertThat(mapper.getRegisteredModuleIds()).contains(new ParameterNamesModule().getTypeId());
|
||||
assertThat(SerializationFeature.INDENT_OUTPUT
|
||||
.enabledIn(mapper.getSerializationConfig().getSerializationFeatures())).isTrue();
|
||||
assertThat(
|
||||
SerializationFeature.INDENT_OUTPUT.enabledIn(mapper.serializationConfig().getSerializationFeatures()))
|
||||
.isTrue();
|
||||
assertThat(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES
|
||||
.enabledIn(mapper.getDeserializationConfig().getDeserializationFeatures())).isFalse();
|
||||
assertThat(mapper.getSerializationConfig().getPropertyNamingStrategy())
|
||||
.enabledIn(mapper.deserializationConfig().getDeserializationFeatures())).isFalse();
|
||||
assertThat(mapper.serializationConfig().getPropertyNamingStrategy())
|
||||
.isEqualTo(PropertyNamingStrategies.LOWER_CAMEL_CASE);
|
||||
assertThat(mapper.getDeserializationConfig().getPropertyNamingStrategy())
|
||||
assertThat(mapper.deserializationConfig().getPropertyNamingStrategy())
|
||||
.isEqualTo(PropertyNamingStrategies.LOWER_CAMEL_CASE);
|
||||
}
|
||||
|
||||
|
|
|
@ -45,10 +45,10 @@ dependencies {
|
|||
testImplementation(project(":test-support:spring-boot-test-support"))
|
||||
testImplementation(testFixtures(project(":core:spring-boot")))
|
||||
testImplementation("ch.qos.logback:logback-classic")
|
||||
testImplementation("com.fasterxml.jackson.core:jackson-databind")
|
||||
testImplementation("io.projectreactor:reactor-core")
|
||||
testImplementation("org.springframework:spring-context-support")
|
||||
testImplementation("org.springframework.security:spring-security-config")
|
||||
testImplementation("tools.jackson.core:jackson-databind")
|
||||
|
||||
testRuntimeOnly("com.github.ben-manes.caffeine:caffeine")
|
||||
testRuntimeOnly("org.springframework:spring-webflux")
|
||||
|
|
|
@ -22,6 +22,8 @@ import org.springframework.aop.config.AopConfigUtils;
|
|||
import org.springframework.aop.framework.autoproxy.AutoProxyUtils;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener;
|
||||
import org.springframework.boot.logging.LogLevel;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.boot.testsupport.classpath.ClassPathExclusions;
|
||||
|
||||
|
@ -40,16 +42,18 @@ class NonAspectJAopAutoConfigurationTests {
|
|||
|
||||
@Test
|
||||
void whenAspectJIsAbsentAndProxyTargetClassIsEnabledProxyCreatorBeanIsDefined() {
|
||||
this.contextRunner.run((context) -> {
|
||||
BeanDefinition defaultProxyConfig = context.getBeanFactory()
|
||||
.getBeanDefinition(AutoProxyUtils.DEFAULT_PROXY_CONFIG_BEAN_NAME);
|
||||
assertThat(defaultProxyConfig.getPropertyValues().get("proxyTargetClass")).isEqualTo(Boolean.TRUE);
|
||||
});
|
||||
this.contextRunner.withInitializer(ConditionEvaluationReportLoggingListener.forLogLevel(LogLevel.INFO))
|
||||
.run((context) -> {
|
||||
BeanDefinition defaultProxyConfig = context.getBeanFactory()
|
||||
.getBeanDefinition(AutoProxyUtils.DEFAULT_PROXY_CONFIG_BEAN_NAME);
|
||||
assertThat(defaultProxyConfig.getPropertyValues().get("proxyTargetClass")).isEqualTo(Boolean.TRUE);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenAspectJIsAbsentAndProxyTargetClassIsDisabledNoProxyCreatorBeanIsDefined() {
|
||||
this.contextRunner.withPropertyValues("spring.aop.proxy-target-class:false")
|
||||
this.contextRunner.withInitializer(ConditionEvaluationReportLoggingListener.forLogLevel(LogLevel.INFO))
|
||||
.withPropertyValues("spring.aop.proxy-target-class:false")
|
||||
.run((context) -> assertThat(context).doesNotHaveBean(AutoProxyUtils.DEFAULT_PROXY_CONFIG_BEAN_NAME)
|
||||
.doesNotHaveBean(AopConfigUtils.AUTO_PROXY_CREATOR_BEAN_NAME));
|
||||
}
|
||||
|
|
|
@ -16,8 +16,8 @@
|
|||
|
||||
package org.springframework.boot.autoconfigure.condition;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import tools.jackson.databind.ObjectMapper;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.OnBeanCondition.BeanTypeDeductionException;
|
||||
import org.springframework.boot.testsupport.classpath.ClassPathExclusions;
|
||||
|
|
|
@ -28,8 +28,7 @@ description = "Spring Boot Docker Compose"
|
|||
dependencies {
|
||||
api(project(":core:spring-boot-autoconfigure"))
|
||||
|
||||
implementation("com.fasterxml.jackson.core:jackson-databind")
|
||||
implementation("com.fasterxml.jackson.module:jackson-module-parameter-names")
|
||||
implementation("tools.jackson.core:jackson-databind")
|
||||
|
||||
dockerTestImplementation(project(":test-support:spring-boot-docker-test-support"))
|
||||
|
||||
|
|
|
@ -16,16 +16,14 @@
|
|||
|
||||
package org.springframework.boot.docker.compose.core;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.JavaType;
|
||||
import com.fasterxml.jackson.databind.MapperFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.json.JsonMapper;
|
||||
import com.fasterxml.jackson.module.paramnames.ParameterNamesModule;
|
||||
import tools.jackson.databind.DeserializationFeature;
|
||||
import tools.jackson.databind.JavaType;
|
||||
import tools.jackson.databind.MapperFeature;
|
||||
import tools.jackson.databind.ObjectMapper;
|
||||
import tools.jackson.databind.json.JsonMapper;
|
||||
|
||||
/**
|
||||
* Support class used to handle JSON returned from the {@link DockerCli}.
|
||||
|
@ -40,7 +38,6 @@ final class DockerJson {
|
|||
.defaultLocale(Locale.ENGLISH)
|
||||
.enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES)
|
||||
.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
|
||||
.addModule(new ParameterNamesModule())
|
||||
.build();
|
||||
|
||||
private DockerJson() {
|
||||
|
@ -74,12 +71,7 @@ final class DockerJson {
|
|||
}
|
||||
|
||||
private static <T> T deserialize(String json, JavaType type) {
|
||||
try {
|
||||
return objectMapper.readValue(json.trim(), type);
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new DockerOutputParseException(json, ex);
|
||||
}
|
||||
return objectMapper.readValue(json.trim(), type);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -64,6 +64,7 @@ class ConnectionNamePredicateTests {
|
|||
assertThat(predicateOf("redis")).accepts(sourceOf("myhost.com/library/redis"));
|
||||
assertThat(predicateOf("redis")).accepts(sourceOf("myhost.com:8080/library/redis"));
|
||||
assertThat(predicateOf("redis")).rejects(sourceOf("internalhost:8080/redis"));
|
||||
assertThat(predicateOf("redis")).accepts(sourceOf("docker.my-company.com/library/redis:latest"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -27,7 +27,6 @@ dependencies {
|
|||
api(project(":core:spring-boot"))
|
||||
api("org.springframework:spring-test")
|
||||
|
||||
optional("com.fasterxml.jackson.core:jackson-databind")
|
||||
optional("com.google.code.gson:gson")
|
||||
optional("com.jayway.jsonpath:json-path")
|
||||
optional("io.projectreactor.netty:reactor-netty-http")
|
||||
|
@ -44,6 +43,7 @@ dependencies {
|
|||
optional("org.springframework:spring-web")
|
||||
optional("org.springframework:spring-webflux")
|
||||
optional("org.springframework.graphql:spring-graphql-test")
|
||||
optional("tools.jackson.core:jackson-databind")
|
||||
|
||||
testImplementation(project(":test-support:spring-boot-test-support"))
|
||||
testImplementation("ch.qos.logback:logback-classic")
|
||||
|
|
|
@ -18,16 +18,29 @@ package org.springframework.boot.test.json;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
import java.io.StringWriter;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import com.fasterxml.jackson.databind.JavaType;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.ObjectReader;
|
||||
import com.fasterxml.jackson.databind.ObjectWriter;
|
||||
import com.jayway.jsonpath.Configuration;
|
||||
import com.jayway.jsonpath.spi.json.JacksonJsonProvider;
|
||||
import com.jayway.jsonpath.spi.mapper.JacksonMappingProvider;
|
||||
import com.jayway.jsonpath.InvalidJsonException;
|
||||
import com.jayway.jsonpath.TypeRef;
|
||||
import com.jayway.jsonpath.spi.json.AbstractJsonProvider;
|
||||
import com.jayway.jsonpath.spi.mapper.MappingException;
|
||||
import com.jayway.jsonpath.spi.mapper.MappingProvider;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import tools.jackson.core.JacksonException;
|
||||
import tools.jackson.core.JsonGenerator;
|
||||
import tools.jackson.databind.JavaType;
|
||||
import tools.jackson.databind.ObjectMapper;
|
||||
import tools.jackson.databind.ObjectReader;
|
||||
import tools.jackson.databind.ObjectWriter;
|
||||
import tools.jackson.databind.json.JsonMapper;
|
||||
|
||||
import org.springframework.beans.factory.ObjectFactory;
|
||||
import org.springframework.core.ResolvableType;
|
||||
|
@ -35,14 +48,14 @@ import org.springframework.util.Assert;
|
|||
|
||||
/**
|
||||
* AssertJ based JSON tester backed by Jackson. Usually instantiated via
|
||||
* {@link #initFields(Object, ObjectMapper)}, for example: <pre class="code">
|
||||
* {@link #initFields(Object, JsonMapper)}, for example: <pre class="code">
|
||||
* public class ExampleObjectJsonTests {
|
||||
*
|
||||
* private JacksonTester<ExampleObject> json;
|
||||
*
|
||||
* @Before
|
||||
* public void setup() {
|
||||
* ObjectMapper objectMapper = new ObjectMapper();
|
||||
* JsonMapper jsonMapper = new JsonMapper();
|
||||
* JacksonTester.initFields(this, objectMapper);
|
||||
* }
|
||||
*
|
||||
|
@ -65,42 +78,44 @@ import org.springframework.util.Assert;
|
|||
*/
|
||||
public class JacksonTester<T> extends AbstractJsonMarshalTester<T> {
|
||||
|
||||
private final ObjectMapper objectMapper;
|
||||
private final JsonMapper jsonMapper;
|
||||
|
||||
private @Nullable Class<?> view;
|
||||
|
||||
/**
|
||||
* Create a new {@link JacksonTester} instance.
|
||||
* @param objectMapper the Jackson object mapper
|
||||
* @param jsonMapper the Jackson JSON mapper
|
||||
* @since 4.0.0
|
||||
*/
|
||||
protected JacksonTester(ObjectMapper objectMapper) {
|
||||
Assert.notNull(objectMapper, "'objectMapper' must not be null");
|
||||
this.objectMapper = objectMapper;
|
||||
protected JacksonTester(JsonMapper jsonMapper) {
|
||||
Assert.notNull(jsonMapper, "'objectMapper' must not be null");
|
||||
this.jsonMapper = jsonMapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link JacksonTester} instance.
|
||||
* @param resourceLoadClass the source class used to load resources
|
||||
* @param type the type under test
|
||||
* @param objectMapper the Jackson object mapper
|
||||
* @param jsonMapper the Jackson JSON mapper
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public JacksonTester(Class<?> resourceLoadClass, ResolvableType type, ObjectMapper objectMapper) {
|
||||
this(resourceLoadClass, type, objectMapper, null);
|
||||
public JacksonTester(Class<?> resourceLoadClass, ResolvableType type, JsonMapper jsonMapper) {
|
||||
this(resourceLoadClass, type, jsonMapper, null);
|
||||
}
|
||||
|
||||
public JacksonTester(Class<?> resourceLoadClass, ResolvableType type, ObjectMapper objectMapper,
|
||||
public JacksonTester(Class<?> resourceLoadClass, ResolvableType type, JsonMapper jsonMapper,
|
||||
@Nullable Class<?> view) {
|
||||
super(resourceLoadClass, type);
|
||||
Assert.notNull(objectMapper, "'objectMapper' must not be null");
|
||||
this.objectMapper = objectMapper;
|
||||
Assert.notNull(jsonMapper, "'jsonMapper' must not be null");
|
||||
this.jsonMapper = jsonMapper;
|
||||
this.view = view;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JsonContent<T> getJsonContent(String json) {
|
||||
Configuration configuration = Configuration.builder()
|
||||
.jsonProvider(new JacksonJsonProvider(this.objectMapper))
|
||||
.mappingProvider(new JacksonMappingProvider(this.objectMapper))
|
||||
.jsonProvider(new JacksonJsonProvider(this.jsonMapper))
|
||||
.mappingProvider(new JacksonMappingProvider(this.jsonMapper))
|
||||
.build();
|
||||
Class<?> resourceLoadClass = getResourceLoadClass();
|
||||
Assert.state(resourceLoadClass != null, "'resourceLoadClass' must not be null");
|
||||
|
@ -118,7 +133,7 @@ public class JacksonTester<T> extends AbstractJsonMarshalTester<T> {
|
|||
}
|
||||
|
||||
private ObjectReader getObjectReader(ResolvableType type) {
|
||||
ObjectReader objectReader = this.objectMapper.readerFor(getType(type));
|
||||
ObjectReader objectReader = this.jsonMapper.readerFor(getType(type));
|
||||
if (this.view != null) {
|
||||
return objectReader.withView(this.view);
|
||||
}
|
||||
|
@ -131,7 +146,7 @@ public class JacksonTester<T> extends AbstractJsonMarshalTester<T> {
|
|||
}
|
||||
|
||||
private ObjectWriter getObjectWriter(ResolvableType type) {
|
||||
ObjectWriter objectWriter = this.objectMapper.writerFor(getType(type));
|
||||
ObjectWriter objectWriter = this.jsonMapper.writerFor(getType(type));
|
||||
if (this.view != null) {
|
||||
return objectWriter.withView(this.view);
|
||||
}
|
||||
|
@ -139,29 +154,31 @@ public class JacksonTester<T> extends AbstractJsonMarshalTester<T> {
|
|||
}
|
||||
|
||||
private JavaType getType(ResolvableType type) {
|
||||
return this.objectMapper.constructType(type.getType());
|
||||
return this.jsonMapper.constructType(type.getType());
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method to initialize {@link JacksonTester} fields. See {@link JacksonTester
|
||||
* class-level documentation} for example usage.
|
||||
* @param testInstance the test instance
|
||||
* @param objectMapper the object mapper
|
||||
* @see #initFields(Object, ObjectMapper)
|
||||
* @param jsonMapper the JSON mapper
|
||||
* @since 4.0.0
|
||||
* @see #initFields(Object, JsonMapper)
|
||||
*/
|
||||
public static void initFields(Object testInstance, ObjectMapper objectMapper) {
|
||||
new JacksonFieldInitializer().initFields(testInstance, objectMapper);
|
||||
public static void initFields(Object testInstance, JsonMapper jsonMapper) {
|
||||
new JacksonFieldInitializer().initFields(testInstance, jsonMapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method to initialize {@link JacksonTester} fields. See {@link JacksonTester
|
||||
* class-level documentation} for example usage.
|
||||
* @param testInstance the test instance
|
||||
* @param objectMapperFactory a factory to create the object mapper
|
||||
* @see #initFields(Object, ObjectMapper)
|
||||
* @param jsonMapperFactory a factory to create the JSON mapper
|
||||
* @since 4.0.0
|
||||
* @see #initFields(Object, JsonMapper)
|
||||
*/
|
||||
public static void initFields(Object testInstance, ObjectFactory<ObjectMapper> objectMapperFactory) {
|
||||
new JacksonFieldInitializer().initFields(testInstance, objectMapperFactory);
|
||||
public static void initFields(Object testInstance, ObjectFactory<JsonMapper> jsonMapperFactory) {
|
||||
new JacksonFieldInitializer().initFields(testInstance, jsonMapperFactory);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -175,13 +192,13 @@ public class JacksonTester<T> extends AbstractJsonMarshalTester<T> {
|
|||
ResolvableType type = getType();
|
||||
Assert.state(resourceLoadClass != null, "'resourceLoadClass' must not be null");
|
||||
Assert.state(type != null, "'type' must not be null");
|
||||
return new JacksonTester<>(resourceLoadClass, type, this.objectMapper, view);
|
||||
return new JacksonTester<>(resourceLoadClass, type, this.jsonMapper, view);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link FieldInitializer} for Jackson.
|
||||
*/
|
||||
private static class JacksonFieldInitializer extends FieldInitializer<ObjectMapper> {
|
||||
private static class JacksonFieldInitializer extends FieldInitializer<JsonMapper> {
|
||||
|
||||
protected JacksonFieldInitializer() {
|
||||
super(JacksonTester.class);
|
||||
|
@ -189,10 +206,115 @@ public class JacksonTester<T> extends AbstractJsonMarshalTester<T> {
|
|||
|
||||
@Override
|
||||
protected AbstractJsonMarshalTester<Object> createTester(Class<?> resourceLoadClass, ResolvableType type,
|
||||
ObjectMapper marshaller) {
|
||||
JsonMapper marshaller) {
|
||||
return new JacksonTester<>(resourceLoadClass, type, marshaller);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static final class JacksonJsonProvider extends AbstractJsonProvider {
|
||||
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
private final ObjectReader objectReader;
|
||||
|
||||
private JacksonJsonProvider(ObjectMapper objectMapper) {
|
||||
this.objectMapper = objectMapper;
|
||||
this.objectReader = objectMapper.reader().forType(Object.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object parse(String json) throws InvalidJsonException {
|
||||
try {
|
||||
return this.objectReader.readValue(json);
|
||||
}
|
||||
catch (JacksonException ex) {
|
||||
throw new InvalidJsonException(ex, json);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object parse(byte[] json) throws InvalidJsonException {
|
||||
try {
|
||||
return this.objectReader.readValue(json);
|
||||
}
|
||||
catch (JacksonException ex) {
|
||||
throw new InvalidJsonException(ex, new String(json, StandardCharsets.UTF_8));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object parse(InputStream jsonStream, String charset) throws InvalidJsonException {
|
||||
try {
|
||||
return this.objectReader.readValue(new InputStreamReader(jsonStream, charset));
|
||||
}
|
||||
catch (UnsupportedEncodingException | JacksonException ex) {
|
||||
throw new InvalidJsonException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toJson(Object obj) {
|
||||
StringWriter writer = new StringWriter();
|
||||
try (JsonGenerator generator = this.objectMapper.createGenerator(writer)) {
|
||||
this.objectMapper.writeValue(generator, obj);
|
||||
}
|
||||
catch (JacksonException ex) {
|
||||
throw new InvalidJsonException(ex);
|
||||
}
|
||||
return writer.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Object> createArray() {
|
||||
return new LinkedList<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object createMap() {
|
||||
return new LinkedHashMap<String, Object>();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static final class JacksonMappingProvider implements MappingProvider {
|
||||
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
private JacksonMappingProvider(ObjectMapper objectMapper) {
|
||||
this.objectMapper = objectMapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> @Nullable T map(Object source, Class<T> targetType, Configuration configuration) {
|
||||
if (source == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return this.objectMapper.convertValue(source, targetType);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new MappingException(ex);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> @Nullable T map(Object source, final TypeRef<T> targetType, Configuration configuration) {
|
||||
if (source == null) {
|
||||
return null;
|
||||
}
|
||||
JavaType type = this.objectMapper.getTypeFactory().constructType(targetType.getType());
|
||||
try {
|
||||
return (T) this.objectMapper.convertValue(source, type);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new MappingException(ex);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -22,11 +22,10 @@ import java.util.LinkedHashMap;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.fasterxml.jackson.databind.MapperFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.json.JsonMapper;
|
||||
import org.assertj.core.api.InstanceOfAssertFactories;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import tools.jackson.databind.MapperFeature;
|
||||
import tools.jackson.databind.json.JsonMapper;
|
||||
|
||||
import org.springframework.core.io.ByteArrayResource;
|
||||
|
||||
|
@ -55,14 +54,14 @@ class JacksonTesterIntegrationTests {
|
|||
|
||||
@Test
|
||||
void typicalTest() throws Exception {
|
||||
JacksonTester.initFields(this, new ObjectMapper());
|
||||
JacksonTester.initFields(this, new JsonMapper());
|
||||
String example = JSON;
|
||||
assertThat(this.simpleJson.parse(example).getObject().getName()).isEqualTo("Spring");
|
||||
}
|
||||
|
||||
@Test
|
||||
void typicalListTest() throws Exception {
|
||||
JacksonTester.initFields(this, new ObjectMapper());
|
||||
JacksonTester.initFields(this, new JsonMapper());
|
||||
String example = "[" + JSON + "]";
|
||||
assertThat(this.listJson.parse(example)).asInstanceOf(InstanceOfAssertFactories.LIST).hasSize(1);
|
||||
assertThat(this.listJson.parse(example).getObject().get(0).getName()).isEqualTo("Spring");
|
||||
|
@ -70,7 +69,7 @@ class JacksonTesterIntegrationTests {
|
|||
|
||||
@Test
|
||||
void typicalMapTest() throws Exception {
|
||||
JacksonTester.initFields(this, new ObjectMapper());
|
||||
JacksonTester.initFields(this, new JsonMapper());
|
||||
Map<String, Integer> map = new LinkedHashMap<>();
|
||||
map.put("a", 1);
|
||||
map.put("b", 2);
|
||||
|
@ -79,7 +78,7 @@ class JacksonTesterIntegrationTests {
|
|||
|
||||
@Test
|
||||
void stringLiteral() throws Exception {
|
||||
JacksonTester.initFields(this, new ObjectMapper());
|
||||
JacksonTester.initFields(this, new JsonMapper());
|
||||
String stringWithSpecialCharacters = "myString";
|
||||
assertThat(this.stringJson.write(stringWithSpecialCharacters)).extractingJsonPathStringValue("@")
|
||||
.isEqualTo(stringWithSpecialCharacters);
|
||||
|
@ -87,7 +86,7 @@ class JacksonTesterIntegrationTests {
|
|||
|
||||
@Test
|
||||
void parseSpecialCharactersTest() throws Exception {
|
||||
JacksonTester.initFields(this, new ObjectMapper());
|
||||
JacksonTester.initFields(this, new JsonMapper());
|
||||
// Confirms that the handling of special characters is symmetrical between
|
||||
// the serialization (through the JacksonTester) and the parsing (through
|
||||
// json-path). By default json-path uses SimpleJson as its parser, which has a
|
||||
|
|
|
@ -18,8 +18,8 @@ package org.springframework.boot.test.json;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import tools.jackson.databind.json.JsonMapper;
|
||||
|
||||
import org.springframework.core.ResolvableType;
|
||||
|
||||
|
@ -35,14 +35,14 @@ class JacksonTesterTests extends AbstractJsonMarshalTesterTests {
|
|||
|
||||
@Test
|
||||
void initFieldsWhenTestIsNullShouldThrowException() {
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> JacksonTester.initFields(null, new ObjectMapper()))
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> JacksonTester.initFields(null, new JsonMapper()))
|
||||
.withMessageContaining("'testInstance' must not be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
void initFieldsWhenMarshallerIsNullShouldThrowException() {
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> JacksonTester.initFields(new InitFieldsTestClass(), (ObjectMapper) null))
|
||||
.isThrownBy(() -> JacksonTester.initFields(new InitFieldsTestClass(), (JsonMapper) null))
|
||||
.withMessageContaining("'marshaller' must not be null");
|
||||
}
|
||||
|
||||
|
@ -51,7 +51,7 @@ class JacksonTesterTests extends AbstractJsonMarshalTesterTests {
|
|||
InitFieldsTestClass test = new InitFieldsTestClass();
|
||||
assertThat(test.test).isNull();
|
||||
assertThat(test.base).isNull();
|
||||
JacksonTester.initFields(test, new ObjectMapper());
|
||||
JacksonTester.initFields(test, new JsonMapper());
|
||||
assertThat(test.test).isNotNull();
|
||||
assertThat(test.base).isNotNull();
|
||||
assertThat(test.test.getType().resolve()).isEqualTo(List.class);
|
||||
|
@ -60,7 +60,7 @@ class JacksonTesterTests extends AbstractJsonMarshalTesterTests {
|
|||
|
||||
@Override
|
||||
protected AbstractJsonMarshalTester<Object> createTester(Class<?> resourceLoadClass, ResolvableType type) {
|
||||
return new JacksonTester<>(resourceLoadClass, type, new ObjectMapper());
|
||||
return new JacksonTester<>(resourceLoadClass, type, new JsonMapper());
|
||||
}
|
||||
|
||||
abstract static class InitFieldsBaseClass {
|
||||
|
@ -68,7 +68,7 @@ class JacksonTesterTests extends AbstractJsonMarshalTesterTests {
|
|||
public JacksonTester<ExampleObject> base;
|
||||
|
||||
public JacksonTester<ExampleObject> baseSet = new JacksonTester<>(InitFieldsBaseClass.class,
|
||||
ResolvableType.forClass(ExampleObject.class), new ObjectMapper());
|
||||
ResolvableType.forClass(ExampleObject.class), new JsonMapper());
|
||||
|
||||
}
|
||||
|
||||
|
@ -77,7 +77,7 @@ class JacksonTesterTests extends AbstractJsonMarshalTesterTests {
|
|||
public JacksonTester<List<ExampleObject>> test;
|
||||
|
||||
public JacksonTester<ExampleObject> testSet = new JacksonTester<>(InitFieldsBaseClass.class,
|
||||
ResolvableType.forClass(ExampleObject.class), new ObjectMapper());
|
||||
ResolvableType.forClass(ExampleObject.class), new JsonMapper());
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -33,7 +33,6 @@ dependencies {
|
|||
api("org.springframework:spring-context")
|
||||
|
||||
optional("ch.qos.logback:logback-classic")
|
||||
optional("com.fasterxml.jackson.core:jackson-databind")
|
||||
optional("com.google.code.gson:gson")
|
||||
optional("io.projectreactor:reactor-core")
|
||||
optional("jakarta.servlet:jakarta.servlet-api")
|
||||
|
@ -49,6 +48,7 @@ dependencies {
|
|||
optional("org.springframework:spring-test")
|
||||
optional("org.springframework:spring-web")
|
||||
optional("org.yaml:snakeyaml")
|
||||
optional("tools.jackson.core:jackson-databind")
|
||||
|
||||
testFixturesCompileOnly(project(":test-support:spring-boot-test-support"))
|
||||
|
||||
|
|
|
@ -19,9 +19,9 @@ package org.springframework.boot.json;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import tools.jackson.core.type.TypeReference;
|
||||
import tools.jackson.databind.ObjectMapper;
|
||||
|
||||
/**
|
||||
* Thin wrapper to adapt Jackson 2 {@link ObjectMapper} to {@link JsonParser}.
|
||||
|
|
|
@ -1,56 +0,0 @@
|
|||
/*
|
||||
* Copyright 2012-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.boot.json;
|
||||
|
||||
import com.fasterxml.jackson.databind.ser.std.ClassSerializer;
|
||||
import com.fasterxml.jackson.databind.ser.std.FileSerializer;
|
||||
import com.fasterxml.jackson.databind.ser.std.StdJdkSerializers.AtomicBooleanSerializer;
|
||||
import com.fasterxml.jackson.databind.ser.std.StdJdkSerializers.AtomicIntegerSerializer;
|
||||
import com.fasterxml.jackson.databind.ser.std.StdJdkSerializers.AtomicLongSerializer;
|
||||
import com.fasterxml.jackson.databind.ser.std.TokenBufferSerializer;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.aot.hint.MemberCategory;
|
||||
import org.springframework.aot.hint.ReflectionHints;
|
||||
import org.springframework.aot.hint.RuntimeHints;
|
||||
import org.springframework.aot.hint.RuntimeHintsRegistrar;
|
||||
import org.springframework.aot.hint.TypeHint;
|
||||
import org.springframework.aot.hint.TypeReference;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* {@link RuntimeHintsRegistrar} implementation for Jackson.
|
||||
*
|
||||
* @author Moritz Halbritter
|
||||
*/
|
||||
class JacksonRuntimeHints implements RuntimeHintsRegistrar {
|
||||
|
||||
@Override
|
||||
public void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {
|
||||
if (!ClassUtils.isPresent("com.fasterxml.jackson.databind.ser.BasicSerializerFactory", classLoader)) {
|
||||
return;
|
||||
}
|
||||
registerSerializers(hints.reflection());
|
||||
}
|
||||
|
||||
private void registerSerializers(ReflectionHints hints) {
|
||||
hints.registerTypes(TypeReference.listOf(AtomicBooleanSerializer.class, AtomicIntegerSerializer.class,
|
||||
AtomicLongSerializer.class, FileSerializer.class, ClassSerializer.class, TokenBufferSerializer.class),
|
||||
TypeHint.builtWith(MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS));
|
||||
}
|
||||
|
||||
}
|
|
@ -35,7 +35,7 @@ public abstract class JsonParserFactory {
|
|||
* @return a {@link JsonParser}
|
||||
*/
|
||||
public static JsonParser getJsonParser() {
|
||||
if (ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper", null)) {
|
||||
if (ClassUtils.isPresent("tools.jackson.databind.ObjectMapper", null)) {
|
||||
return new JacksonJsonParser();
|
||||
}
|
||||
if (ClassUtils.isPresent("com.google.gson.Gson", null)) {
|
||||
|
|
|
@ -5,7 +5,6 @@ org.springframework.boot.WebApplicationType$WebApplicationTypeRuntimeHints,\
|
|||
org.springframework.boot.context.config.ConfigDataLocationRuntimeHints,\
|
||||
org.springframework.boot.context.config.ConfigDataPropertiesRuntimeHints,\
|
||||
org.springframework.boot.env.PropertySourceRuntimeHints,\
|
||||
org.springframework.boot.json.JacksonRuntimeHints,\
|
||||
org.springframework.boot.logging.java.JavaLoggingSystemRuntimeHints,\
|
||||
org.springframework.boot.logging.logback.LogbackRuntimeHints,\
|
||||
org.springframework.boot.logging.structured.ElasticCommonSchemaProperties$ElasticCommonSchemaPropertiesRuntimeHints,\
|
||||
|
|
|
@ -16,12 +16,10 @@
|
|||
|
||||
package org.springframework.boot.json;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import tools.jackson.core.type.TypeReference;
|
||||
import tools.jackson.databind.ObjectMapper;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
|
@ -43,7 +41,7 @@ class JacksonJsonParserTests extends AbstractJsonParserTests {
|
|||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
void instanceWithSpecificObjectMapper() throws IOException {
|
||||
void instanceWithSpecificObjectMapper() {
|
||||
ObjectMapper objectMapper = spy(new ObjectMapper());
|
||||
new JacksonJsonParser(objectMapper).parseMap("{}");
|
||||
then(objectMapper).should().readValue(eq("{}"), any(TypeReference.class));
|
||||
|
|
|
@ -1,64 +0,0 @@
|
|||
/*
|
||||
* Copyright 2012-present the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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 org.springframework.boot.json;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import com.fasterxml.jackson.databind.ser.std.ClassSerializer;
|
||||
import com.fasterxml.jackson.databind.ser.std.FileSerializer;
|
||||
import com.fasterxml.jackson.databind.ser.std.StdJdkSerializers.AtomicBooleanSerializer;
|
||||
import com.fasterxml.jackson.databind.ser.std.StdJdkSerializers.AtomicIntegerSerializer;
|
||||
import com.fasterxml.jackson.databind.ser.std.StdJdkSerializers.AtomicLongSerializer;
|
||||
import com.fasterxml.jackson.databind.ser.std.TokenBufferSerializer;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.aot.hint.MemberCategory;
|
||||
import org.springframework.aot.hint.ReflectionHints;
|
||||
import org.springframework.aot.hint.RuntimeHints;
|
||||
import org.springframework.aot.hint.TypeHint;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link JacksonRuntimeHints}.
|
||||
*
|
||||
* @author Moritz Halbritter
|
||||
*/
|
||||
class JacksonRuntimeHintsTests {
|
||||
|
||||
@Test
|
||||
void shouldRegisterSerializerConstructors() {
|
||||
ReflectionHints hints = registerHints();
|
||||
Stream
|
||||
.of(AtomicBooleanSerializer.class, AtomicIntegerSerializer.class, AtomicLongSerializer.class,
|
||||
FileSerializer.class, ClassSerializer.class, TokenBufferSerializer.class)
|
||||
.forEach((serializer) -> {
|
||||
TypeHint typeHint = hints.getTypeHint(serializer);
|
||||
assertThat(typeHint).withFailMessage(() -> "No hints found for serializer " + serializer).isNotNull();
|
||||
Set<MemberCategory> memberCategories = typeHint.getMemberCategories();
|
||||
assertThat(memberCategories).containsExactly(MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS);
|
||||
});
|
||||
}
|
||||
|
||||
private ReflectionHints registerHints() {
|
||||
RuntimeHints hints = new RuntimeHints();
|
||||
new JacksonRuntimeHints().registerHints(hints, getClass().getClassLoader());
|
||||
return hints.reflection();
|
||||
}
|
||||
|
||||
}
|
|
@ -20,16 +20,14 @@ import java.time.Instant;
|
|||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.apache.logging.log4j.Level;
|
||||
import org.apache.logging.log4j.core.impl.MutableLogEvent;
|
||||
import org.apache.logging.log4j.message.SimpleMessage;
|
||||
import org.assertj.core.api.Assertions;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import tools.jackson.core.type.TypeReference;
|
||||
import tools.jackson.databind.ObjectMapper;
|
||||
|
||||
import org.springframework.boot.logging.structured.MockStructuredLoggingJsonMembersCustomizerBuilder;
|
||||
import org.springframework.boot.logging.structured.StructuredLoggingJsonMembersCustomizer;
|
||||
|
@ -79,14 +77,8 @@ abstract class AbstractStructuredLoggingTests {
|
|||
}
|
||||
|
||||
protected Map<String, Object> deserialize(String json) {
|
||||
try {
|
||||
return OBJECT_MAPPER.readValue(json, new TypeReference<>() {
|
||||
});
|
||||
}
|
||||
catch (JsonProcessingException ex) {
|
||||
Assertions.fail("Failed to deserialize JSON: " + json, ex);
|
||||
return null;
|
||||
}
|
||||
return OBJECT_MAPPER.readValue(json, new TypeReference<>() {
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -34,7 +34,6 @@ import java.util.logging.Handler;
|
|||
import java.util.logging.Level;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
|
@ -333,15 +332,16 @@ class Log4J2LoggingSystemTests extends AbstractLoggingSystemTests {
|
|||
// No classes, only XML
|
||||
Arguments.of(Collections.emptyList(), List.of(".xml")),
|
||||
// Log4j Core 2
|
||||
Arguments.of(List.of(JsonConfigurationFactory.class.getName(), ObjectMapper.class.getName()),
|
||||
List.of(".json", ".jsn", ".xml")),
|
||||
Arguments.of(List.of(JsonConfigurationFactory.class.getName(),
|
||||
"com.fasterxml.jackson.databind.ObjectMapper"), List.of(".json", ".jsn", ".xml")),
|
||||
Arguments.of(List.of(PropertiesConfigurationFactory.class.getName(),
|
||||
PropertiesConfigurationBuilder.class.getName()), List.of(".properties", ".xml")),
|
||||
Arguments.of(List.of(YamlConfigurationFactory.class.getName(),
|
||||
"com.fasterxml.jackson.dataformat.yaml.YAMLMapper"), List.of(".yaml", ".yml", ".xml")),
|
||||
Arguments.of(List.of(JsonConfigurationFactory.class.getName(), ObjectMapper.class.getName(),
|
||||
PropertiesConfigurationFactory.class.getName(), PropertiesConfigurationBuilder.class.getName(),
|
||||
YamlConfigurationFactory.class.getName(), "com.fasterxml.jackson.dataformat.yaml.YAMLMapper"),
|
||||
Arguments.of(List.of(JsonConfigurationFactory.class.getName(),
|
||||
"com.fasterxml.jackson.databind.ObjectMapper", PropertiesConfigurationFactory.class.getName(),
|
||||
PropertiesConfigurationBuilder.class.getName(), YamlConfigurationFactory.class.getName(),
|
||||
"com.fasterxml.jackson.dataformat.yaml.YAMLMapper"),
|
||||
List.of(".properties", ".yaml", ".yml", ".json", ".jsn", ".xml")),
|
||||
// Log4j Core 3
|
||||
Arguments.of(List.of(JsonConfigurationFactory.class.getName(),
|
||||
|
|
|
@ -26,10 +26,6 @@ import ch.qos.logback.classic.Level;
|
|||
import ch.qos.logback.classic.pattern.ThrowableProxyConverter;
|
||||
import ch.qos.logback.classic.spi.LoggingEvent;
|
||||
import ch.qos.logback.classic.spi.ThrowableProxy;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.assertj.core.api.Assertions;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
|
@ -38,6 +34,8 @@ import org.mockito.junit.jupiter.MockitoExtension;
|
|||
import org.slf4j.Marker;
|
||||
import org.slf4j.event.KeyValuePair;
|
||||
import org.slf4j.helpers.BasicMarkerFactory;
|
||||
import tools.jackson.core.type.TypeReference;
|
||||
import tools.jackson.databind.ObjectMapper;
|
||||
|
||||
import org.springframework.boot.logging.structured.MockStructuredLoggingJsonMembersCustomizerBuilder;
|
||||
import org.springframework.boot.logging.structured.StructuredLoggingJsonMembersCustomizer;
|
||||
|
@ -122,14 +120,8 @@ abstract class AbstractStructuredLoggingTests {
|
|||
}
|
||||
|
||||
protected Map<String, Object> deserialize(String json) {
|
||||
try {
|
||||
return OBJECT_MAPPER.readValue(json, new TypeReference<>() {
|
||||
});
|
||||
}
|
||||
catch (JsonProcessingException ex) {
|
||||
Assertions.fail("Failed to deserialize JSON: " + json, ex);
|
||||
return null;
|
||||
}
|
||||
return OBJECT_MAPPER.readValue(json, new TypeReference<>() {
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -18,9 +18,8 @@ package org.springframework.boot.web.error;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import tools.jackson.databind.ObjectMapper;
|
||||
|
||||
import org.springframework.context.MessageSourceResolvable;
|
||||
import org.springframework.context.support.DefaultMessageSourceResolvable;
|
||||
|
@ -46,7 +45,7 @@ class ErrorTests {
|
|||
}
|
||||
|
||||
@Test
|
||||
void errorCauseDoesNotAppearInJson() throws JsonProcessingException {
|
||||
void errorCauseDoesNotAppearInJson() {
|
||||
String json = new ObjectMapper()
|
||||
.writeValueAsString(Error.wrapIfNecessary(List.of(new CustomMessageSourceResolvable("code"))));
|
||||
assertThat(json).doesNotContain("some detail");
|
||||
|
|
|
@ -16,15 +16,14 @@
|
|||
|
||||
package org.springframework.boot.actuate.docs;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
import tools.jackson.databind.SerializationFeature;
|
||||
import tools.jackson.databind.json.JsonMapper;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
|
@ -32,7 +31,7 @@ import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfi
|
|||
import org.springframework.boot.actuate.autoconfigure.endpoint.jackson.JacksonEndpointAutoConfiguration;
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;
|
||||
import org.springframework.boot.actuate.docs.AbstractEndpointDocumentationTests.BaseDocumentationConfiguration;
|
||||
import org.springframework.boot.actuate.endpoint.jackson.EndpointObjectMapper;
|
||||
import org.springframework.boot.actuate.endpoint.jackson.EndpointJsonMapper;
|
||||
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
|
||||
import org.springframework.boot.http.converter.autoconfigure.HttpMessageConvertersAutoConfiguration;
|
||||
|
@ -77,29 +76,24 @@ public abstract class AbstractEndpointDocumentationTests {
|
|||
@SuppressWarnings("unchecked")
|
||||
protected <T> OperationPreprocessor limit(Predicate<T> filter, String... keys) {
|
||||
return new ContentModifyingOperationPreprocessor((content, mediaType) -> {
|
||||
ObjectMapper objectMapper = new ObjectMapper().enable(SerializationFeature.INDENT_OUTPUT);
|
||||
try {
|
||||
Map<String, Object> payload = objectMapper.readValue(content, Map.class);
|
||||
Object target = payload;
|
||||
Map<Object, Object> parent = null;
|
||||
for (String key : keys) {
|
||||
if (!(target instanceof Map)) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
parent = (Map<Object, Object>) target;
|
||||
target = parent.get(key);
|
||||
JsonMapper objectMapper = JsonMapper.builder().enable(SerializationFeature.INDENT_OUTPUT).build();
|
||||
Map<String, Object> payload = objectMapper.readValue(content, Map.class);
|
||||
Object target = payload;
|
||||
Map<Object, Object> parent = null;
|
||||
for (String key : keys) {
|
||||
if (!(target instanceof Map)) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
if (target instanceof Map) {
|
||||
parent.put(keys[keys.length - 1], select((Map<String, Object>) target, filter));
|
||||
}
|
||||
else {
|
||||
parent.put(keys[keys.length - 1], select((List<Object>) target, filter));
|
||||
}
|
||||
return objectMapper.writeValueAsBytes(payload);
|
||||
parent = (Map<Object, Object>) target;
|
||||
target = parent.get(key);
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
if (target instanceof Map) {
|
||||
parent.put(keys[keys.length - 1], select((Map<String, Object>) target, filter));
|
||||
}
|
||||
else {
|
||||
parent.put(keys[keys.length - 1], select((List<Object>) target, filter));
|
||||
}
|
||||
return objectMapper.writeValueAsBytes(payload);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -135,14 +129,16 @@ public abstract class AbstractEndpointDocumentationTests {
|
|||
static class BaseDocumentationConfiguration {
|
||||
|
||||
@Bean
|
||||
static BeanPostProcessor endpointObjectMapperBeanPostProcessor() {
|
||||
static BeanPostProcessor endpointJsonMapperBeanPostProcessor() {
|
||||
return new BeanPostProcessor() {
|
||||
|
||||
@Override
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
|
||||
if (bean instanceof EndpointObjectMapper) {
|
||||
return (EndpointObjectMapper) () -> ((EndpointObjectMapper) bean).get()
|
||||
.enable(SerializationFeature.INDENT_OUTPUT);
|
||||
if (bean instanceof EndpointJsonMapper) {
|
||||
return (EndpointJsonMapper) () -> ((EndpointJsonMapper) bean).get()
|
||||
.rebuild()
|
||||
.enable(SerializationFeature.INDENT_OUTPUT)
|
||||
.build();
|
||||
}
|
||||
return bean;
|
||||
}
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
|
||||
package org.springframework.boot.actuate.docs.env;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
@ -24,9 +23,10 @@ import java.util.Set;
|
|||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import tools.jackson.databind.ObjectMapper;
|
||||
import tools.jackson.databind.SerializationFeature;
|
||||
import tools.jackson.databind.json.JsonMapper;
|
||||
|
||||
import org.springframework.boot.actuate.docs.MockMvcEndpointDocumentationTests;
|
||||
import org.springframework.boot.actuate.endpoint.Show;
|
||||
|
@ -116,24 +116,19 @@ class EnvironmentEndpointDocumentationTests extends MockMvcEndpointDocumentation
|
|||
|
||||
@SuppressWarnings("unchecked")
|
||||
private byte[] filterProperties(byte[] content, MediaType mediaType) {
|
||||
ObjectMapper objectMapper = new ObjectMapper().enable(SerializationFeature.INDENT_OUTPUT);
|
||||
try {
|
||||
Map<String, Object> payload = objectMapper.readValue(content, Map.class);
|
||||
List<Map<String, Object>> propertySources = (List<Map<String, Object>>) payload.get("propertySources");
|
||||
for (Map<String, Object> propertySource : propertySources) {
|
||||
Map<String, String> properties = (Map<String, String>) propertySource.get("properties");
|
||||
Set<String> filteredKeys = properties.keySet()
|
||||
.stream()
|
||||
.filter(this::retainKey)
|
||||
.limit(3)
|
||||
.collect(Collectors.toSet());
|
||||
properties.keySet().retainAll(filteredKeys);
|
||||
}
|
||||
return objectMapper.writeValueAsBytes(payload);
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
ObjectMapper objectMapper = JsonMapper.builder().enable(SerializationFeature.INDENT_OUTPUT).build();
|
||||
Map<String, Object> payload = objectMapper.readValue(content, Map.class);
|
||||
List<Map<String, Object>> propertySources = (List<Map<String, Object>>) payload.get("propertySources");
|
||||
for (Map<String, Object> propertySource : propertySources) {
|
||||
Map<String, String> properties = (Map<String, String>) propertySource.get("properties");
|
||||
Set<String> filteredKeys = properties.keySet()
|
||||
.stream()
|
||||
.filter(this::retainKey)
|
||||
.limit(3)
|
||||
.collect(Collectors.toSet());
|
||||
properties.keySet().retainAll(filteredKeys);
|
||||
}
|
||||
return objectMapper.writeValueAsBytes(payload);
|
||||
}
|
||||
|
||||
private boolean retainKey(String key) {
|
||||
|
|
|
@ -34,7 +34,6 @@ import org.springframework.restdocs.payload.FieldDescriptor;
|
|||
import org.springframework.session.FindByIndexNameSessionRepository;
|
||||
import org.springframework.session.MapSession;
|
||||
import org.springframework.session.Session;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
import org.springframework.test.context.bean.override.mockito.MockitoBean;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
@ -51,7 +50,6 @@ import static org.springframework.restdocs.request.RequestDocumentation.queryPar
|
|||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
@TestPropertySource(properties = "spring.jackson.serialization.write-dates-as-timestamps=false")
|
||||
class SessionsEndpointDocumentationTests extends MockMvcEndpointDocumentationTests {
|
||||
|
||||
private static final Session sessionOne = createSession(Instant.now().minusSeconds(60 * 60 * 12),
|
||||
|
|
|
@ -634,8 +634,8 @@
|
|||
* xref:how-to:security.adoc#howto.security.switch-off-spring-boot-configuration[#howto.security.switch-off-spring-boot-configuration]
|
||||
* xref:how-to:security.adoc#howto.security[#howto-security]
|
||||
* xref:how-to:security.adoc#howto.security[#howto.security]
|
||||
* xref:how-to:spring-mvc.adoc#howto.spring-mvc.customize-jackson-objectmapper[#howto-customize-the-jackson-objectmapper]
|
||||
* xref:how-to:spring-mvc.adoc#howto.spring-mvc.customize-jackson-objectmapper[#howto.spring-mvc.customize-jackson-objectmapper]
|
||||
* xref:how-to:spring-mvc.adoc#howto.spring-mvc.customize-jackson-jsonmapper[#howto-customize-the-jackson-objectmapper]
|
||||
* xref:how-to:spring-mvc.adoc#howto.spring-mvc.customize-jackson-jsonmapper[#howto.spring-mvc.customize-jackson-objectmapper]
|
||||
* xref:how-to:spring-mvc.adoc#howto.spring-mvc.customize-responsebody-rendering[#howto-customize-the-responsebody-rendering]
|
||||
* xref:how-to:spring-mvc.adoc#howto.spring-mvc.customize-responsebody-rendering[#howto.spring-mvc.customize-responsebody-rendering]
|
||||
* xref:how-to:spring-mvc.adoc#howto.spring-mvc.customize-view-resolvers[#howto-customize-view-resolvers]
|
||||
|
|
|
@ -10,11 +10,11 @@ This section answers common questions about Spring MVC and Spring Boot.
|
|||
[[howto.spring-mvc.write-json-rest-service]]
|
||||
== Write a JSON REST Service
|
||||
|
||||
Any Spring javadoc:org.springframework.web.bind.annotation.RestController[format=annotation] in a Spring Boot application should render JSON response by default as long as Jackson2 is on the classpath, as shown in the following example:
|
||||
Any Spring javadoc:org.springframework.web.bind.annotation.RestController[format=annotation] in a Spring Boot application should render JSON response by default as long as Jackson 3 is on the classpath, as shown in the following example:
|
||||
|
||||
include-code::MyController[]
|
||||
|
||||
As long as `MyThing` can be serialized by Jackson2 (true for a normal POJO or Groovy object), then `http://localhost:8080/thing` serves a JSON representation of it by default.
|
||||
As long as `MyThing` can be serialized by Jackson 3 (true for a normal POJO or Groovy object), then `http://localhost:8080/thing` serves a JSON representation of it by default.
|
||||
Note that, in a browser, you might sometimes see XML responses, because browsers tend to send accept headers that prefer XML.
|
||||
|
||||
|
||||
|
@ -29,7 +29,7 @@ To use the Jackson XML renderer, add the following dependency to your project:
|
|||
[source,xml]
|
||||
----
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.dataformat</groupId>
|
||||
<groupId>tools.jackson.dataformat</groupId>
|
||||
<artifactId>jackson-dataformat-xml</artifactId>
|
||||
</dependency>
|
||||
----
|
||||
|
@ -52,53 +52,41 @@ NOTE: To get the server to render XML instead of JSON, you might have to send an
|
|||
|
||||
|
||||
|
||||
[[howto.spring-mvc.customize-jackson-objectmapper]]
|
||||
== Customize the Jackson ObjectMapper
|
||||
[[howto.spring-mvc.customize-jackson-jsonmapper]]
|
||||
== Customize the Jackson JsonMapper
|
||||
|
||||
Spring MVC (client and server side) uses javadoc:org.springframework.boot.http.converter.autoconfigure.HttpMessageConverters[] to negotiate content conversion in an HTTP exchange.
|
||||
If Jackson is on the classpath, you already get the default converter(s) provided by javadoc:org.springframework.http.converter.json.Jackson2ObjectMapperBuilder[], an instance of which is auto-configured for you.
|
||||
|
||||
The javadoc:com.fasterxml.jackson.databind.ObjectMapper[] (or javadoc:com.fasterxml.jackson.dataformat.xml.XmlMapper[] for Jackson XML converter) instance (created by default) has the following customized properties:
|
||||
|
||||
* `MapperFeature.DEFAULT_VIEW_INCLUSION` is disabled
|
||||
* `DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES` is disabled
|
||||
* `SerializationFeature.WRITE_DATES_AS_TIMESTAMPS` is disabled
|
||||
* `SerializationFeature.WRITE_DURATIONS_AS_TIMESTAMPS` is disabled
|
||||
|
||||
Spring Boot also has some features to make it easier to customize this behavior.
|
||||
|
||||
You can configure the javadoc:com.fasterxml.jackson.databind.ObjectMapper[] and javadoc:com.fasterxml.jackson.dataformat.xml.XmlMapper[] instances by using the environment.
|
||||
You can configure the javadoc:tools.jackson.databind.JsonMapper[] by using the environment.
|
||||
Jackson provides an extensive suite of on/off features that can be used to configure various aspects of its processing.
|
||||
These features are described in several enums (in Jackson) that map onto properties in the environment:
|
||||
|
||||
|===
|
||||
| Enum | Property | Values
|
||||
|
||||
| javadoc:com.fasterxml.jackson.databind.cfg.EnumFeature[]
|
||||
| javadoc:tools.jackson.databind.cfg.EnumFeature[]
|
||||
| `spring.jackson.datatype.enum.<feature_name>`
|
||||
| `true`, `false`
|
||||
|
||||
| javadoc:com.fasterxml.jackson.databind.cfg.JsonNodeFeature[]
|
||||
| javadoc:tools.jackson.databind.cfg.JsonNodeFeature[]
|
||||
| `spring.jackson.datatype.json-node.<feature_name>`
|
||||
| `true`, `false`
|
||||
|
||||
| javadoc:com.fasterxml.jackson.databind.DeserializationFeature[]
|
||||
| javadoc:tools.jackson.databind.DeserializationFeature[]
|
||||
| `spring.jackson.deserialization.<feature_name>`
|
||||
| `true`, `false`
|
||||
|
||||
| javadoc:com.fasterxml.jackson.core.JsonGenerator$Feature[]
|
||||
| `spring.jackson.generator.<feature_name>`
|
||||
| `true`, `false`
|
||||
|
||||
| javadoc:com.fasterxml.jackson.databind.MapperFeature[]
|
||||
| javadoc:tools.jackson.databind.MapperFeature[]
|
||||
| `spring.jackson.mapper.<feature_name>`
|
||||
| `true`, `false`
|
||||
|
||||
| javadoc:com.fasterxml.jackson.core.JsonParser$Feature[]
|
||||
| `spring.jackson.parser.<feature_name>`
|
||||
| javadoc:tools.jackson.core.JsonReadFeature[]
|
||||
| `spring.jackson.read.<feature_name>`
|
||||
| `true`, `false`
|
||||
|
||||
| javadoc:com.fasterxml.jackson.databind.SerializationFeature[]
|
||||
| javadoc:tools.jackson.core.JsonWriteFeature[]
|
||||
| `spring.jackson.write.<feature_name>`
|
||||
| `true`, `false`
|
||||
|
||||
| javadoc:tools.jackson.databind.SerializationFeature[]
|
||||
| `spring.jackson.serialization.<feature_name>`
|
||||
| `true`, `false`
|
||||
|
||||
|
@ -110,21 +98,19 @@ These features are described in several enums (in Jackson) that map onto propert
|
|||
For example, to enable pretty print, set `spring.jackson.serialization.indent_output=true`.
|
||||
Note that, thanks to the use of xref:reference:features/external-config.adoc#features.external-config.typesafe-configuration-properties.relaxed-binding[relaxed binding], the case of `indent_output` does not have to match the case of the corresponding enum constant, which is `INDENT_OUTPUT`.
|
||||
|
||||
This environment-based configuration is applied to the auto-configured javadoc:org.springframework.http.converter.json.Jackson2ObjectMapperBuilder[] bean and applies to any mappers created by using the builder, including the auto-configured javadoc:com.fasterxml.jackson.databind.ObjectMapper[] bean.
|
||||
This environment-based configuration is applied to the auto-configured javadoc:tools.jackson.databind.json.JsonMapper.Builder[] bean and applies to any mappers created by using the builder, including the auto-configured javadoc:tools.jackson.databind.json.JsonMapper[] bean.
|
||||
|
||||
The context's javadoc:org.springframework.http.converter.json.Jackson2ObjectMapperBuilder[] can be customized by one or more javadoc:org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer[] beans.
|
||||
The context's javadoc:tools.jackson.databind.json.JsonMapper.Builder[] can be customized by one or more javadoc:org.springframework.boot.autoconfigure.jackson.JsonMapperBuilderCustomizer[] beans.
|
||||
Such customizer beans can be ordered (Boot's own customizer has an order of 0), letting additional customization be applied both before and after Boot's customization.
|
||||
|
||||
Any beans of type javadoc:com.fasterxml.jackson.databind.Module[] are automatically registered with the auto-configured javadoc:org.springframework.http.converter.json.Jackson2ObjectMapperBuilder[] and are applied to any javadoc:com.fasterxml.jackson.databind.ObjectMapper[] instances that it creates.
|
||||
Any beans of type javadoc:tools.jackson.databind.JacksonModule[] are automatically registered with the auto-configured javadoc:tools.jackson.databind.json.JsonMapper.Builder[] and are applied to any javadoc:tools.jackson.databind.json.JsonMapper[] instances that it creates.
|
||||
This provides a global mechanism for contributing custom modules when you add new features to your application.
|
||||
|
||||
NOTE: If you wish to register additional modules programmatically using a javadoc:org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer[], make sure to use the `modulesToInstall` method that takes a consumer as the other variants are not additive.
|
||||
If you want to replace the default javadoc:tools.jackson.databind.json.JsonMapper[] completely, either define a javadoc:org.springframework.context.annotation.Bean[format=annotation] of that type or, if you prefer the builder-based approach, define a javadoc:tools.jackson.databind.json.JsonMapper.Builder[] javadoc:org.springframework.context.annotation.Bean[format=annotation].
|
||||
When defining an javadoc:tools.jackson.databind.json.JsonMapper[] bean, marking it as javadoc:org.springframework.context.annotation.Primary[format=annotation] is recommended as the auto-configuration's javadoc:tools.jackson.databind.json.JsonMapper[] that it will replace is javadoc:org.springframework.context.annotation.Primary[format=annotation].
|
||||
Note that, in either case, doing so disables all auto-configuration of the javadoc:tools.jackson.databind.json.JsonMapper[].
|
||||
|
||||
If you want to replace the default javadoc:com.fasterxml.jackson.databind.ObjectMapper[] completely, either define a javadoc:org.springframework.context.annotation.Bean[format=annotation] of that type or, if you prefer the builder-based approach, define a javadoc:org.springframework.http.converter.json.Jackson2ObjectMapperBuilder[] javadoc:org.springframework.context.annotation.Bean[format=annotation].
|
||||
When defining an javadoc:com.fasterxml.jackson.databind.ObjectMapper[] bean, marking it as javadoc:org.springframework.context.annotation.Primary[format=annotation] is recommended as the auto-configuration's javadoc:com.fasterxml.jackson.databind.ObjectMapper[] that it will replace is javadoc:org.springframework.context.annotation.Primary[format=annotation].
|
||||
Note that, in either case, doing so disables all auto-configuration of the javadoc:com.fasterxml.jackson.databind.ObjectMapper[].
|
||||
|
||||
If you provide any javadoc:java.beans.Beans[format=annotation] of type javadoc:org.springframework.http.converter.json.MappingJackson2HttpMessageConverter[], they replace the default value in the MVC configuration.
|
||||
If you provide any javadoc:java.beans.Beans[format=annotation] of type javadoc:org.springframework.http.converter.json.JacksonJsonHttpMessageConverter[], they replace the default value in the MVC configuration.
|
||||
Also, a convenience bean of type javadoc:org.springframework.boot.http.converter.autoconfigure.HttpMessageConverters[] is provided (and is always available if you use the default MVC configuration).
|
||||
It has some useful methods to access the default and user-enhanced message converters.
|
||||
|
||||
|
@ -137,7 +123,7 @@ See the xref:spring-mvc.adoc#howto.spring-mvc.customize-responsebody-rendering[]
|
|||
|
||||
Spring uses javadoc:org.springframework.boot.http.converter.autoconfigure.HttpMessageConverters[] to render javadoc:org.springframework.web.bind.annotation.ResponseBody[format=annotation] (or responses from javadoc:org.springframework.web.bind.annotation.RestController[format=annotation]).
|
||||
You can contribute additional converters by adding beans of the appropriate type in a Spring Boot context.
|
||||
If a bean you add is of a type that would have been included by default anyway (such as javadoc:org.springframework.http.converter.json.MappingJackson2HttpMessageConverter[] for JSON conversions), it replaces the default value.
|
||||
If a bean you add is of a type that would have been included by default anyway (such as javadoc:org.springframework.http.converter.json.JacksonJsonHttpMessageConverter[] for JSON conversions), it replaces the default value.
|
||||
A convenience bean of type javadoc:org.springframework.boot.http.converter.autoconfigure.HttpMessageConverters[] is provided and is always available if you use the default MVC configuration.
|
||||
It has some useful methods to access the default and user-enhanced message converters (For example, it can be useful if you want to manually inject them into a custom javadoc:org.springframework.web.client.RestTemplate[]).
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
Spring Boot provides integration with three JSON mapping libraries:
|
||||
|
||||
- Gson
|
||||
- Jackson
|
||||
- Jackson 3
|
||||
- JSON-B
|
||||
|
||||
Jackson is the preferred and default library.
|
||||
|
@ -15,18 +15,18 @@ Jackson is the preferred and default library.
|
|||
== Jackson
|
||||
|
||||
Auto-configuration for Jackson is provided and Jackson is part of `spring-boot-starter-json`.
|
||||
When Jackson is on the classpath an javadoc:com.fasterxml.jackson.databind.ObjectMapper[] bean is automatically configured.
|
||||
Several configuration properties are provided for xref:how-to:spring-mvc.adoc#howto.spring-mvc.customize-jackson-objectmapper[customizing the configuration of the javadoc:com.fasterxml.jackson.databind.ObjectMapper[]].
|
||||
When Jackson is on the classpath a javadoc:tools.jackson.databind.json.JsonMapper[] bean is automatically configured.
|
||||
Several configuration properties are provided for xref:how-to:spring-mvc.adoc#howto.spring-mvc.customize-jackson-jsonmapper[customizing the configuration of the javadoc:tools.jackson.databind.json.JsonMapper[]].
|
||||
|
||||
|
||||
|
||||
[[features.json.jackson.custom-serializers-and-deserializers]]
|
||||
=== Custom Serializers and Deserializers
|
||||
|
||||
If you use Jackson to serialize and deserialize JSON data, you might want to write your own javadoc:com.fasterxml.jackson.databind.JsonSerializer[] and javadoc:com.fasterxml.jackson.databind.JsonDeserializer[] classes.
|
||||
If you use Jackson to serialize and deserialize JSON data, you might want to write your own javadoc:tools.jackson.databind.ValueSerializer[] and javadoc:tools.jackson.databind.ValueDeserializer[] classes.
|
||||
Custom serializers are usually https://github.com/FasterXML/jackson-docs/wiki/JacksonHowToCustomSerializers[registered with Jackson through a module], but Spring Boot provides an alternative javadoc:org.springframework.boot.jackson.JsonComponent[format=annotation] annotation that makes it easier to directly register Spring Beans.
|
||||
|
||||
You can use the javadoc:org.springframework.boot.jackson.JsonComponent[format=annotation] annotation directly on javadoc:com.fasterxml.jackson.databind.JsonSerializer[], javadoc:com.fasterxml.jackson.databind.JsonDeserializer[] or javadoc:com.fasterxml.jackson.databind.KeyDeserializer[] implementations.
|
||||
You can use the javadoc:org.springframework.boot.jackson.JsonComponent[format=annotation] annotation directly on javadoc:tools.jackson.databind.ValueSerializer[], javadoc:tools.jackson.databind.ValueDeserializer[] or javadoc:tools.jackson.databind.KeyDeserializer[] implementations.
|
||||
You can also use it on classes that contain serializers/deserializers as inner classes, as shown in the following example:
|
||||
|
||||
include-code::MyJsonComponent[]
|
||||
|
@ -34,10 +34,10 @@ include-code::MyJsonComponent[]
|
|||
All javadoc:org.springframework.boot.jackson.JsonComponent[format=annotation] beans in the javadoc:org.springframework.context.ApplicationContext[] are automatically registered with Jackson.
|
||||
Because javadoc:org.springframework.boot.jackson.JsonComponent[format=annotation] is meta-annotated with javadoc:org.springframework.stereotype.Component[format=annotation], the usual component-scanning rules apply.
|
||||
|
||||
Spring Boot also provides javadoc:org.springframework.boot.jackson.JsonObjectSerializer[] and javadoc:org.springframework.boot.jackson.JsonObjectDeserializer[] base classes that provide useful alternatives to the standard Jackson versions when serializing objects.
|
||||
See javadoc:org.springframework.boot.jackson.JsonObjectSerializer[] and javadoc:org.springframework.boot.jackson.JsonObjectDeserializer[] in the API documentation for details.
|
||||
Spring Boot also provides javadoc:org.springframework.boot.jackson.ObjectValueSerializer[] and javadoc:org.springframework.boot.jackson.ObjectValueDeserializer[] base classes that provide useful alternatives to the standard Jackson versions when serializing objects.
|
||||
See javadoc:org.springframework.boot.jackson.ObjectValueSerializer[] and javadoc:org.springframework.boot.jackson.ObjectValueDeserializer[] in the API documentation for details.
|
||||
|
||||
The example above can be rewritten to use javadoc:org.springframework.boot.jackson.JsonObjectSerializer[] and javadoc:org.springframework.boot.jackson.JsonObjectDeserializer[] as follows:
|
||||
The example above can be rewritten to use javadoc:org.springframework.boot.jackson.ObjectValueSerializer[] and javadoc:org.springframework.boot.jackson.ObjectValueDeserializer[] as follows:
|
||||
|
||||
include-code::object/MyJsonComponent[]
|
||||
|
||||
|
@ -47,7 +47,7 @@ include-code::object/MyJsonComponent[]
|
|||
=== Mixins
|
||||
|
||||
Jackson has support for mixins that can be used to mix additional annotations into those already declared on a target class.
|
||||
Spring Boot's Jackson auto-configuration will scan your application's packages for classes annotated with javadoc:org.springframework.boot.jackson.JsonMixin[format=annotation] and register them with the auto-configured javadoc:com.fasterxml.jackson.databind.ObjectMapper[].
|
||||
Spring Boot's Jackson auto-configuration will scan your application's packages for classes annotated with javadoc:org.springframework.boot.jackson.JsonMixin[format=annotation] and register them with the auto-configured javadoc:tools.jackson.databind.json.JsonMapper[].
|
||||
The registration is performed by Spring Boot's javadoc:org.springframework.boot.jackson.JsonMixinModule[].
|
||||
|
||||
|
||||
|
|
|
@ -281,7 +281,7 @@ You can use this combination if you are not interested in "`slicing`" your appli
|
|||
To test that object JSON serialization and deserialization is working as expected, you can use the javadoc:org.springframework.boot.test.autoconfigure.json.JsonTest[format=annotation] annotation.
|
||||
javadoc:org.springframework.boot.test.autoconfigure.json.JsonTest[format=annotation] auto-configures the available supported JSON mapper, which can be one of the following libraries:
|
||||
|
||||
* Jackson javadoc:com.fasterxml.jackson.databind.ObjectMapper[], any javadoc:org.springframework.boot.jackson.JsonComponent[format=annotation] beans and any Jackson javadoc:com.fasterxml.jackson.databind.Module[]
|
||||
* Jackson javadoc:tools.jackson.databind.JsonMapper[], any javadoc:org.springframework.boot.jackson.JsonComponent[format=annotation] beans and any Jackson javadoc:tools.jackson.databind.JacksonModule[]
|
||||
* `Gson`
|
||||
* `Jsonb`
|
||||
|
||||
|
@ -317,7 +317,7 @@ javadoc:org.springframework.boot.context.properties.EnableConfigurationPropertie
|
|||
|
||||
TIP: A list of the auto-configuration settings that are enabled by javadoc:org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest[format=annotation] can be xref:appendix:test-auto-configuration/index.adoc[found in the appendix].
|
||||
|
||||
TIP: If you need to register extra components, such as the Jackson javadoc:com.fasterxml.jackson.databind.Module[], you can import additional configuration classes by using javadoc:org.springframework.context.annotation.Import[format=annotation] on your test.
|
||||
TIP: If you need to register extra components, such as a javadoc:tools.jackson.databind.JacksonModule[], you can import additional configuration classes by using javadoc:org.springframework.context.annotation.Import[format=annotation] on your test.
|
||||
|
||||
Often, javadoc:org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest[format=annotation] is limited to a single controller and is used in combination with javadoc:org.springframework.test.context.bean.override.mockito.MockitoBean[format=annotation] to provide mock implementations for required collaborators.
|
||||
|
||||
|
@ -361,7 +361,7 @@ javadoc:org.springframework.boot.context.properties.EnableConfigurationPropertie
|
|||
|
||||
TIP: A list of the auto-configurations that are enabled by javadoc:org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest[format=annotation] can be xref:appendix:test-auto-configuration/index.adoc[found in the appendix].
|
||||
|
||||
TIP: If you need to register extra components, such as Jackson javadoc:com.fasterxml.jackson.databind.Module[], you can import additional configuration classes using javadoc:org.springframework.context.annotation.Import[format=annotation] on your test.
|
||||
TIP: If you need to register extra components, such as a javadoc:tools.jackson.databind.JacksonModule[], you can import additional configuration classes using javadoc:org.springframework.context.annotation.Import[format=annotation] on your test.
|
||||
|
||||
Often, javadoc:org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest[format=annotation] is limited to a single controller and used in combination with the javadoc:org.springframework.test.context.bean.override.mockito.MockitoBean[format=annotation] annotation to provide mock implementations for required collaborators.
|
||||
|
||||
|
|
|
@ -2,11 +2,11 @@
|
|||
= Spring HATEOAS
|
||||
|
||||
If you develop a RESTful API that makes use of hypermedia, Spring Boot provides auto-configuration for Spring HATEOAS that works well with most applications.
|
||||
The auto-configuration replaces the need to use javadoc:org.springframework.hateoas.config.EnableHypermediaSupport[format=annotation] and registers a number of beans to ease building hypermedia-based applications, including a javadoc:org.springframework.hateoas.client.LinkDiscoverers[] (for client side support) and an javadoc:com.fasterxml.jackson.databind.ObjectMapper[] configured to correctly marshal responses into the desired representation.
|
||||
The javadoc:com.fasterxml.jackson.databind.ObjectMapper[] is customized by setting the various `spring.jackson.*` properties or, if one exists, by a javadoc:org.springframework.http.converter.json.Jackson2ObjectMapperBuilder[] bean.
|
||||
The auto-configuration replaces the need to use javadoc:org.springframework.hateoas.config.EnableHypermediaSupport[format=annotation] and registers a number of beans to ease building hypermedia-based applications, including a javadoc:org.springframework.hateoas.client.LinkDiscoverers[] (for client side support) and an javadoc:tools.jackson.databind.json.JsonMapper[] configured to correctly marshal responses into the desired representation.
|
||||
The javadoc:tools.jackson.databind.json.JsontMapper[] is customized by setting the various `spring.jackson.*` properties or, if any exist, the javadoc:org.springframework.boot.jackson.autoconfigure.JsonMapperBuilderCustomizer[] beans.
|
||||
|
||||
You can take control of Spring HATEOAS's configuration by using javadoc:org.springframework.hateoas.config.EnableHypermediaSupport[format=annotation].
|
||||
Note that doing so disables the javadoc:com.fasterxml.jackson.databind.ObjectMapper[] customization described earlier.
|
||||
Note that doing so disables the javadoc:tools.jackson.databind.json.JsonMapper[] customization described earlier.
|
||||
|
||||
WARNING: `spring-boot-starter-hateoas` is specific to Spring MVC and should not be combined with Spring WebFlux.
|
||||
In order to use Spring HATEOAS with Spring WebFlux, you can add a direct dependency on `org.springframework.hateoas:spring-hateoas` along with `spring-boot-starter-webflux`.
|
||||
|
|
|
@ -16,41 +16,37 @@
|
|||
|
||||
package org.springframework.boot.docs.features.json.jackson.customserializersanddeserializers;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import com.fasterxml.jackson.core.ObjectCodec;
|
||||
import com.fasterxml.jackson.databind.DeserializationContext;
|
||||
import com.fasterxml.jackson.databind.JsonDeserializer;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.JsonSerializer;
|
||||
import com.fasterxml.jackson.databind.SerializerProvider;
|
||||
import tools.jackson.core.JsonGenerator;
|
||||
import tools.jackson.core.JsonParser;
|
||||
import tools.jackson.databind.DeserializationContext;
|
||||
import tools.jackson.databind.JsonNode;
|
||||
import tools.jackson.databind.SerializationContext;
|
||||
import tools.jackson.databind.ValueDeserializer;
|
||||
import tools.jackson.databind.ValueSerializer;
|
||||
|
||||
import org.springframework.boot.jackson.JsonComponent;
|
||||
|
||||
@JsonComponent
|
||||
public class MyJsonComponent {
|
||||
|
||||
public static class Serializer extends JsonSerializer<MyObject> {
|
||||
public static class Serializer extends ValueSerializer<MyObject> {
|
||||
|
||||
@Override
|
||||
public void serialize(MyObject value, JsonGenerator jgen, SerializerProvider serializers) throws IOException {
|
||||
public void serialize(MyObject value, JsonGenerator jgen, SerializationContext context) {
|
||||
jgen.writeStartObject();
|
||||
jgen.writeStringField("name", value.getName());
|
||||
jgen.writeNumberField("age", value.getAge());
|
||||
jgen.writeStringProperty("name", value.getName());
|
||||
jgen.writeNumberProperty("age", value.getAge());
|
||||
jgen.writeEndObject();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class Deserializer extends JsonDeserializer<MyObject> {
|
||||
public static class Deserializer extends ValueDeserializer<MyObject> {
|
||||
|
||||
@Override
|
||||
public MyObject deserialize(JsonParser jsonParser, DeserializationContext ctxt) throws IOException {
|
||||
ObjectCodec codec = jsonParser.getCodec();
|
||||
JsonNode tree = codec.readTree(jsonParser);
|
||||
String name = tree.get("name").textValue();
|
||||
public MyObject deserialize(JsonParser jsonParser, DeserializationContext ctxt) {
|
||||
JsonNode tree = jsonParser.readValueAsTree();
|
||||
String name = tree.get("name").stringValue();
|
||||
int age = tree.get("age").intValue();
|
||||
return new MyObject(name, age);
|
||||
}
|
||||
|
|
|
@ -16,38 +16,33 @@
|
|||
|
||||
package org.springframework.boot.docs.features.json.jackson.customserializersanddeserializers.object;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import com.fasterxml.jackson.core.ObjectCodec;
|
||||
import com.fasterxml.jackson.databind.DeserializationContext;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.SerializerProvider;
|
||||
import tools.jackson.core.JsonGenerator;
|
||||
import tools.jackson.core.JsonParser;
|
||||
import tools.jackson.databind.DeserializationContext;
|
||||
import tools.jackson.databind.JsonNode;
|
||||
import tools.jackson.databind.SerializationContext;
|
||||
|
||||
import org.springframework.boot.jackson.JsonComponent;
|
||||
import org.springframework.boot.jackson.JsonObjectDeserializer;
|
||||
import org.springframework.boot.jackson.JsonObjectSerializer;
|
||||
import org.springframework.boot.jackson.ObjectValueDeserializer;
|
||||
import org.springframework.boot.jackson.ObjectValueSerializer;
|
||||
|
||||
@JsonComponent
|
||||
public class MyJsonComponent {
|
||||
|
||||
public static class Serializer extends JsonObjectSerializer<MyObject> {
|
||||
public static class Serializer extends ObjectValueSerializer<MyObject> {
|
||||
|
||||
@Override
|
||||
protected void serializeObject(MyObject value, JsonGenerator jgen, SerializerProvider provider)
|
||||
throws IOException {
|
||||
jgen.writeStringField("name", value.getName());
|
||||
jgen.writeNumberField("age", value.getAge());
|
||||
protected void serializeObject(MyObject value, JsonGenerator jgen, SerializationContext context) {
|
||||
jgen.writeStringProperty("name", value.getName());
|
||||
jgen.writeNumberProperty("age", value.getAge());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class Deserializer extends JsonObjectDeserializer<MyObject> {
|
||||
public static class Deserializer extends ObjectValueDeserializer<MyObject> {
|
||||
|
||||
@Override
|
||||
protected MyObject deserializeObject(JsonParser jsonParser, DeserializationContext context, ObjectCodec codec,
|
||||
JsonNode tree) throws IOException {
|
||||
protected MyObject deserializeObject(JsonParser jsonParser, DeserializationContext context, JsonNode tree) {
|
||||
String name = nullSafeValue(tree.get("name"), String.class);
|
||||
int age = nullSafeValue(tree.get("age"), Integer.class);
|
||||
return new MyObject(name, age);
|
||||
|
|
|
@ -16,36 +16,32 @@
|
|||
|
||||
package org.springframework.boot.docs.features.json.jackson.customserializersanddeserializers
|
||||
|
||||
import com.fasterxml.jackson.core.JsonGenerator
|
||||
import com.fasterxml.jackson.core.JsonParser
|
||||
import com.fasterxml.jackson.core.JsonProcessingException
|
||||
import com.fasterxml.jackson.databind.DeserializationContext
|
||||
import com.fasterxml.jackson.databind.JsonDeserializer
|
||||
import com.fasterxml.jackson.databind.JsonNode
|
||||
import com.fasterxml.jackson.databind.JsonSerializer
|
||||
import com.fasterxml.jackson.databind.SerializerProvider
|
||||
import tools.jackson.core.JsonGenerator
|
||||
import tools.jackson.core.JsonParser
|
||||
import tools.jackson.databind.DeserializationContext
|
||||
import tools.jackson.databind.JsonNode
|
||||
import tools.jackson.databind.SerializationContext
|
||||
import tools.jackson.databind.ValueDeserializer
|
||||
import tools.jackson.databind.ValueSerializer
|
||||
|
||||
import org.springframework.boot.jackson.JsonComponent
|
||||
import java.io.IOException
|
||||
|
||||
@JsonComponent
|
||||
class MyJsonComponent {
|
||||
|
||||
class Serializer : JsonSerializer<MyObject>() {
|
||||
@Throws(IOException::class)
|
||||
override fun serialize(value: MyObject, jgen: JsonGenerator, serializers: SerializerProvider) {
|
||||
class Serializer : ValueSerializer<MyObject>() {
|
||||
override fun serialize(value: MyObject, jgen: JsonGenerator, serializers: SerializationContext) {
|
||||
jgen.writeStartObject()
|
||||
jgen.writeStringField("name", value.name)
|
||||
jgen.writeNumberField("age", value.age)
|
||||
jgen.writeStringProperty("name", value.name)
|
||||
jgen.writeNumberProperty("age", value.age)
|
||||
jgen.writeEndObject()
|
||||
}
|
||||
}
|
||||
|
||||
class Deserializer : JsonDeserializer<MyObject>() {
|
||||
@Throws(IOException::class, JsonProcessingException::class)
|
||||
class Deserializer : ValueDeserializer<MyObject>() {
|
||||
override fun deserialize(jsonParser: JsonParser, ctxt: DeserializationContext): MyObject {
|
||||
val codec = jsonParser.codec
|
||||
val tree = codec.readTree<JsonNode>(jsonParser)
|
||||
val name = tree["name"].textValue()
|
||||
val tree = jsonParser.readValueAsTree<JsonNode>()
|
||||
val name = tree["name"].stringValue()
|
||||
val age = tree["age"].intValue()
|
||||
return MyObject(name, age)
|
||||
}
|
||||
|
|
|
@ -16,32 +16,29 @@
|
|||
|
||||
package org.springframework.boot.docs.features.json.jackson.customserializersanddeserializers.`object`
|
||||
|
||||
import com.fasterxml.jackson.core.JsonGenerator
|
||||
import com.fasterxml.jackson.core.JsonParser
|
||||
import com.fasterxml.jackson.core.ObjectCodec
|
||||
import com.fasterxml.jackson.databind.DeserializationContext
|
||||
import com.fasterxml.jackson.databind.JsonNode
|
||||
import com.fasterxml.jackson.databind.SerializerProvider
|
||||
import org.springframework.boot.jackson.JsonComponent
|
||||
import org.springframework.boot.jackson.JsonObjectDeserializer
|
||||
import org.springframework.boot.jackson.JsonObjectSerializer
|
||||
import java.io.IOException
|
||||
import tools.jackson.core.JsonGenerator
|
||||
import tools.jackson.core.JsonParser
|
||||
import tools.jackson.databind.DeserializationContext
|
||||
import tools.jackson.databind.JsonNode
|
||||
import tools.jackson.databind.SerializationContext
|
||||
|
||||
import org.springframework.boot.jackson.JsonComponent;
|
||||
import org.springframework.boot.jackson.ObjectValueDeserializer
|
||||
import org.springframework.boot.jackson.ObjectValueSerializer
|
||||
|
||||
@JsonComponent
|
||||
class MyJsonComponent {
|
||||
|
||||
class Serializer : JsonObjectSerializer<MyObject>() {
|
||||
@Throws(IOException::class)
|
||||
override fun serializeObject(value: MyObject, jgen: JsonGenerator, provider: SerializerProvider) {
|
||||
jgen.writeStringField("name", value.name)
|
||||
jgen.writeNumberField("age", value.age)
|
||||
class Serializer : ObjectValueSerializer<MyObject>() {
|
||||
override fun serializeObject(value: MyObject, jgen: JsonGenerator, context: SerializationContext) {
|
||||
jgen.writeStringProperty("name", value.name)
|
||||
jgen.writeNumberProperty("age", value.age)
|
||||
}
|
||||
}
|
||||
|
||||
class Deserializer : JsonObjectDeserializer<MyObject>() {
|
||||
@Throws(IOException::class)
|
||||
class Deserializer : ObjectValueDeserializer<MyObject>() {
|
||||
override fun deserializeObject(jsonParser: JsonParser, context: DeserializationContext,
|
||||
codec: ObjectCodec, tree: JsonNode): MyObject {
|
||||
tree: JsonNode): MyObject {
|
||||
val name = nullSafeValue(tree["name"], String::class.java) ?: throw IllegalStateException("name is null")
|
||||
val age = nullSafeValue(tree["age"], Int::class.java) ?: throw IllegalStateException("age is null")
|
||||
return MyObject(name, age)
|
||||
|
|
|
@ -11,7 +11,8 @@ checkstyleToolVersion=10.12.4
|
|||
commonsCodecVersion=1.19.0
|
||||
graalVersion=22.3
|
||||
hamcrestVersion=3.0
|
||||
jacksonVersion=2.20.0-rc1
|
||||
jackson2Version=2.20.0
|
||||
jacksonVersion=3.0.0-rc8
|
||||
javaFormatVersion=0.0.47
|
||||
junitJupiterVersion=5.13.4
|
||||
kotlinVersion=2.2.0
|
||||
|
|
|
@ -43,4 +43,5 @@ dependencies {
|
|||
testImplementation("net.minidev:json-smart")
|
||||
testImplementation("org.springframework.security:spring-security-web")
|
||||
testRuntimeOnly("ch.qos.logback:logback-classic")
|
||||
testRuntimeOnly("com.fasterxml.jackson.datatype:jackson-datatype-jsr310") // Required for Jersey
|
||||
}
|
||||
|
|
|
@ -16,16 +16,15 @@
|
|||
|
||||
package org.springframework.boot.actuate.metrics;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import io.micrometer.core.instrument.MeterRegistry;
|
||||
import io.micrometer.core.instrument.MockClock;
|
||||
import io.micrometer.core.instrument.binder.jvm.JvmMemoryMetrics;
|
||||
import io.micrometer.core.instrument.simple.SimpleConfig;
|
||||
import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
|
||||
import tools.jackson.databind.ObjectMapper;
|
||||
|
||||
import org.springframework.boot.actuate.endpoint.web.test.WebEndpointTest;
|
||||
import org.springframework.boot.micrometer.metrics.actuate.endpoint.MetricsEndpoint;
|
||||
|
@ -49,7 +48,7 @@ class MetricsEndpointWebIntegrationTests {
|
|||
|
||||
@WebEndpointTest
|
||||
@SuppressWarnings("unchecked")
|
||||
void listNames(WebTestClient client) throws IOException {
|
||||
void listNames(WebTestClient client) {
|
||||
String responseBody = client.get()
|
||||
.uri("/actuator/metrics")
|
||||
.exchange()
|
||||
|
|
|
@ -16,6 +16,12 @@
|
|||
|
||||
package org.springframework.boot.activemq.autoconfigure;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude.Include;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import jakarta.jms.ConnectionFactory;
|
||||
import org.apache.activemq.ActiveMQConnectionFactory;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
@ -47,6 +53,14 @@ class ActiveMQAutoConfigurationTests {
|
|||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(ActiveMQAutoConfiguration.class, JmsAutoConfiguration.class));
|
||||
|
||||
@Test
|
||||
void dunno() throws JsonProcessingException {
|
||||
Map<String, String> map = new HashMap<>();
|
||||
map.put("key", null);
|
||||
String string = new ObjectMapper().setDefaultPropertyInclusion(Include.NON_NULL).writeValueAsString(map);
|
||||
System.out.println(string);
|
||||
}
|
||||
|
||||
@Test
|
||||
void brokerIsEmbeddedByDefault() {
|
||||
this.contextRunner.withUserConfiguration(EmptyConfiguration.class).run((context) -> {
|
||||
|
|
|
@ -29,13 +29,11 @@ dependencies {
|
|||
api(project(":core:spring-boot-autoconfigure"))
|
||||
api(project(":module:spring-boot-actuator"))
|
||||
|
||||
implementation("com.fasterxml.jackson.core:jackson-databind")
|
||||
implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310")
|
||||
implementation("tools.jackson.core:jackson-databind")
|
||||
|
||||
optional(project(":module:spring-boot-health"))
|
||||
optional(project(":module:spring-boot-web-server"))
|
||||
|
||||
optional("com.fasterxml.jackson.core:jackson-databind")
|
||||
optional("io.micrometer:micrometer-core")
|
||||
optional("io.projectreactor:reactor-core")
|
||||
optional("jakarta.servlet:jakarta.servlet-api")
|
||||
|
|
|
@ -20,17 +20,15 @@ import java.util.HashSet;
|
|||
import java.util.Set;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude.Include;
|
||||
import com.fasterxml.jackson.databind.MapperFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
import tools.jackson.databind.ObjectMapper;
|
||||
import tools.jackson.databind.json.JsonMapper;
|
||||
|
||||
import org.springframework.boot.actuate.endpoint.jackson.EndpointObjectMapper;
|
||||
import org.springframework.boot.actuate.endpoint.jackson.EndpointJsonMapper;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
|
@ -40,30 +38,27 @@ import org.springframework.util.ClassUtils;
|
|||
* @since 3.0.0
|
||||
*/
|
||||
@AutoConfiguration
|
||||
@SuppressWarnings("removal")
|
||||
public final class JacksonEndpointAutoConfiguration {
|
||||
|
||||
private static final String CONTRIBUTED_HEALTH = "org.springframework.boot.health.contributor.ContributedHealth";
|
||||
|
||||
@Bean
|
||||
@ConditionalOnBooleanProperty(name = "management.endpoints.jackson.isolated-object-mapper", matchIfMissing = true)
|
||||
@ConditionalOnClass({ ObjectMapper.class, Jackson2ObjectMapperBuilder.class })
|
||||
EndpointObjectMapper endpointObjectMapper() {
|
||||
ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.json()
|
||||
.featuresToEnable(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY)
|
||||
.featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS,
|
||||
SerializationFeature.WRITE_DURATIONS_AS_TIMESTAMPS)
|
||||
.serializationInclusion(Include.NON_NULL)
|
||||
@ConditionalOnClass(ObjectMapper.class)
|
||||
EndpointJsonMapper endpointJsonMapper() {
|
||||
JsonMapper jsonMapper = JsonMapper.builder()
|
||||
.changeDefaultPropertyInclusion(
|
||||
(value) -> value.withValueInclusion(Include.NON_NULL).withContentInclusion(Include.NON_NULL))
|
||||
.build();
|
||||
Set<Class<?>> supportedTypes = new HashSet<>(EndpointObjectMapper.DEFAULT_SUPPORTED_TYPES);
|
||||
Set<Class<?>> supportedTypes = new HashSet<>(EndpointJsonMapper.DEFAULT_SUPPORTED_TYPES);
|
||||
if (ClassUtils.isPresent(CONTRIBUTED_HEALTH, null)) {
|
||||
supportedTypes.add(ClassUtils.resolveClassName(CONTRIBUTED_HEALTH, null));
|
||||
}
|
||||
return new EndpointObjectMapper() {
|
||||
return new EndpointJsonMapper() {
|
||||
|
||||
@Override
|
||||
public ObjectMapper get() {
|
||||
return objectMapper;
|
||||
public JsonMapper get() {
|
||||
return jsonMapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -18,7 +18,7 @@ package org.springframework.boot.actuate.autoconfigure.endpoint.jmx;
|
|||
|
||||
import javax.management.MBeanServer;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import tools.jackson.databind.ObjectMapper;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.LazyInitializationExcludeFilter;
|
||||
|
|
|
@ -22,10 +22,10 @@ import java.time.format.DateTimeFormatter;
|
|||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import tools.jackson.databind.json.JsonMapper;
|
||||
|
||||
import org.springframework.boot.actuate.endpoint.jackson.EndpointObjectMapper;
|
||||
import org.springframework.boot.actuate.endpoint.jackson.EndpointJsonMapper;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
@ -44,49 +44,49 @@ class JacksonEndpointAutoConfigurationTests {
|
|||
.withConfiguration(AutoConfigurations.of(JacksonEndpointAutoConfiguration.class));
|
||||
|
||||
@Test
|
||||
void endpointObjectMapperWhenNoProperty() {
|
||||
this.runner.run((context) -> assertThat(context).hasSingleBean(EndpointObjectMapper.class));
|
||||
void endpointJsonMapperWhenNoProperty() {
|
||||
this.runner.run((context) -> assertThat(context).hasSingleBean(EndpointJsonMapper.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void endpointObjectMapperWhenPropertyTrue() {
|
||||
void endpointJsonMapperWhenPropertyTrue() {
|
||||
this.runner.withPropertyValues("management.endpoints.jackson.isolated-object-mapper=true")
|
||||
.run((context) -> assertThat(context).hasSingleBean(EndpointObjectMapper.class));
|
||||
.run((context) -> assertThat(context).hasSingleBean(EndpointJsonMapper.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void endpointObjectMapperWhenPropertyFalse() {
|
||||
void endpointJsonMapperWhenPropertyFalse() {
|
||||
this.runner.withPropertyValues("management.endpoints.jackson.isolated-object-mapper=false")
|
||||
.run((context) -> assertThat(context).doesNotHaveBean(EndpointObjectMapper.class));
|
||||
.run((context) -> assertThat(context).doesNotHaveBean(EndpointJsonMapper.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void endpointObjectMapperDoesNotSerializeDatesAsTimestamps() {
|
||||
void endpointJsonMapperDoesNotSerializeDatesAsTimestamps() {
|
||||
this.runner.run((context) -> {
|
||||
ObjectMapper objectMapper = context.getBean(EndpointObjectMapper.class).get();
|
||||
JsonMapper jsonMapper = context.getBean(EndpointJsonMapper.class).get();
|
||||
Instant now = Instant.now();
|
||||
String json = objectMapper.writeValueAsString(Map.of("timestamp", now));
|
||||
String json = jsonMapper.writeValueAsString(Map.of("timestamp", now));
|
||||
assertThat(json).contains(DateTimeFormatter.ISO_INSTANT.format(now));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void endpointObjectMapperDoesNotSerializeDurationsAsTimestamps() {
|
||||
void endpointJsonMapperDoesNotSerializeDurationsAsTimestamps() {
|
||||
this.runner.run((context) -> {
|
||||
ObjectMapper objectMapper = context.getBean(EndpointObjectMapper.class).get();
|
||||
JsonMapper jsonMapper = context.getBean(EndpointJsonMapper.class).get();
|
||||
Duration duration = Duration.ofSeconds(42);
|
||||
String json = objectMapper.writeValueAsString(Map.of("duration", duration));
|
||||
String json = jsonMapper.writeValueAsString(Map.of("duration", duration));
|
||||
assertThat(json).contains(duration.toString());
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void endpointObjectMapperDoesNotSerializeNullValues() {
|
||||
void endpointJsonMapperDoesNotSerializeNullValues() {
|
||||
this.runner.run((context) -> {
|
||||
ObjectMapper objectMapper = context.getBean(EndpointObjectMapper.class).get();
|
||||
JsonMapper jsonMapper = context.getBean(EndpointJsonMapper.class).get();
|
||||
HashMap<String, String> map = new HashMap<>();
|
||||
map.put("key", null);
|
||||
String json = objectMapper.writeValueAsString(map);
|
||||
String json = jsonMapper.writeValueAsString(map);
|
||||
assertThat(json).isEqualTo("{}");
|
||||
});
|
||||
}
|
||||
|
@ -95,16 +95,16 @@ class JacksonEndpointAutoConfigurationTests {
|
|||
static class TestEndpointMapperConfiguration {
|
||||
|
||||
@Bean
|
||||
TestEndpointObjectMapper testEndpointObjectMapper() {
|
||||
return new TestEndpointObjectMapper();
|
||||
TestEndpointJsonMapper testEndpointJsonMapper() {
|
||||
return new TestEndpointJsonMapper();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class TestEndpointObjectMapper implements EndpointObjectMapper {
|
||||
static class TestEndpointJsonMapper implements EndpointJsonMapper {
|
||||
|
||||
@Override
|
||||
public ObjectMapper get() {
|
||||
public JsonMapper get() {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
@ -32,8 +32,6 @@ dependencies {
|
|||
optional(project(":module:spring-boot-jsonb"))
|
||||
optional(project(":module:spring-boot-validation"))
|
||||
optional(project(":module:spring-boot-web-server"))
|
||||
optional("com.fasterxml.jackson.core:jackson-databind")
|
||||
optional("com.fasterxml.jackson.datatype:jackson-datatype-jsr310")
|
||||
optional("com.github.ben-manes.caffeine:caffeine")
|
||||
optional("com.google.code.findbugs:jsr305")
|
||||
optional("com.zaxxer:HikariCP")
|
||||
|
@ -57,8 +55,8 @@ dependencies {
|
|||
optional("org.springframework.graphql:spring-graphql")
|
||||
optional("org.springframework.security:spring-security-core")
|
||||
optional("org.springframework.security:spring-security-web")
|
||||
optional("tools.jackson.core:jackson-databind")
|
||||
|
||||
testFixturesApi("com.fasterxml.jackson.datatype:jackson-datatype-jsr310")
|
||||
testFixturesImplementation("org.junit.jupiter:junit-jupiter-api")
|
||||
testFixturesImplementation("org.springframework:spring-test")
|
||||
testFixturesImplementation("org.springframework:spring-webflux")
|
||||
|
|
|
@ -29,30 +29,30 @@ import java.util.function.Predicate;
|
|||
import java.util.stream.Collectors;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude.Include;
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.databind.BeanDescription;
|
||||
import com.fasterxml.jackson.databind.MapperFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.SerializationConfig;
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
import com.fasterxml.jackson.databind.SerializerProvider;
|
||||
import com.fasterxml.jackson.databind.introspect.Annotated;
|
||||
import com.fasterxml.jackson.databind.introspect.AnnotatedMethod;
|
||||
import com.fasterxml.jackson.databind.introspect.JacksonAnnotationIntrospector;
|
||||
import com.fasterxml.jackson.databind.json.JsonMapper;
|
||||
import com.fasterxml.jackson.databind.module.SimpleModule;
|
||||
import com.fasterxml.jackson.databind.ser.BeanPropertyWriter;
|
||||
import com.fasterxml.jackson.databind.ser.BeanSerializerFactory;
|
||||
import com.fasterxml.jackson.databind.ser.BeanSerializerModifier;
|
||||
import com.fasterxml.jackson.databind.ser.PropertyWriter;
|
||||
import com.fasterxml.jackson.databind.ser.SerializerFactory;
|
||||
import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter;
|
||||
import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import tools.jackson.core.JsonGenerator;
|
||||
import tools.jackson.databind.BeanDescription;
|
||||
import tools.jackson.databind.ObjectMapper;
|
||||
import tools.jackson.databind.SerializationConfig;
|
||||
import tools.jackson.databind.SerializationContext;
|
||||
import tools.jackson.databind.SerializationFeature;
|
||||
import tools.jackson.databind.cfg.MapperConfig;
|
||||
import tools.jackson.databind.introspect.Annotated;
|
||||
import tools.jackson.databind.introspect.AnnotatedMethod;
|
||||
import tools.jackson.databind.introspect.DefaultAccessorNamingStrategy;
|
||||
import tools.jackson.databind.introspect.JacksonAnnotationIntrospector;
|
||||
import tools.jackson.databind.json.JsonMapper;
|
||||
import tools.jackson.databind.module.SimpleModule;
|
||||
import tools.jackson.databind.ser.BeanPropertyWriter;
|
||||
import tools.jackson.databind.ser.BeanSerializerFactory;
|
||||
import tools.jackson.databind.ser.PropertyWriter;
|
||||
import tools.jackson.databind.ser.SerializerFactory;
|
||||
import tools.jackson.databind.ser.ValueSerializerModifier;
|
||||
import tools.jackson.databind.ser.std.SimpleBeanPropertyFilter;
|
||||
import tools.jackson.databind.ser.std.SimpleFilterProvider;
|
||||
import tools.jackson.databind.ser.std.ToStringSerializer;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.boot.actuate.endpoint.OperationResponseBody;
|
||||
|
@ -180,13 +180,10 @@ public class ConfigurationPropertiesReportEndpoint implements ApplicationContext
|
|||
*/
|
||||
protected void configureJsonMapper(JsonMapper.Builder builder) {
|
||||
builder.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
|
||||
builder.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
|
||||
builder.configure(SerializationFeature.WRITE_DURATIONS_AS_TIMESTAMPS, false);
|
||||
builder.configure(MapperFeature.USE_STD_BEAN_NAMING, true);
|
||||
builder.serializationInclusion(Include.NON_NULL);
|
||||
builder.changeDefaultPropertyInclusion((value) -> value.withValueInclusion(Include.NON_NULL));
|
||||
builder.accessorNaming(new DefaultAccessorNamingStrategy.Provider().withFirstCharAcceptance(true, false));
|
||||
applyConfigurationPropertiesFilter(builder);
|
||||
applySerializationModifier(builder);
|
||||
builder.addModule(new JavaTimeModule());
|
||||
builder.addModule(new ConfigurationPropertiesModule());
|
||||
}
|
||||
|
||||
|
@ -411,8 +408,8 @@ public class ConfigurationPropertiesReportEndpoint implements ApplicationContext
|
|||
private static final class ConfigurationPropertiesAnnotationIntrospector extends JacksonAnnotationIntrospector {
|
||||
|
||||
@Override
|
||||
public Object findFilterId(Annotated a) {
|
||||
Object id = super.findFilterId(a);
|
||||
public Object findFilterId(MapperConfig<?> config, Annotated a) {
|
||||
Object id = super.findFilterId(config, a);
|
||||
if (id == null) {
|
||||
id = CONFIGURATION_PROPERTIES_FILTER_ID;
|
||||
}
|
||||
|
@ -450,7 +447,7 @@ public class ConfigurationPropertiesReportEndpoint implements ApplicationContext
|
|||
}
|
||||
|
||||
@Override
|
||||
public void serializeAsField(Object pojo, JsonGenerator jgen, SerializerProvider provider,
|
||||
public void serializeAsProperty(Object pojo, JsonGenerator jgen, SerializationContext context,
|
||||
PropertyWriter writer) throws Exception {
|
||||
if (writer instanceof BeanPropertyWriter beanPropertyWriter) {
|
||||
try {
|
||||
|
@ -470,7 +467,7 @@ public class ConfigurationPropertiesReportEndpoint implements ApplicationContext
|
|||
return;
|
||||
}
|
||||
}
|
||||
super.serializeAsField(pojo, jgen, provider, writer);
|
||||
super.serializeAsProperty(pojo, jgen, context, writer);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -487,14 +484,14 @@ public class ConfigurationPropertiesReportEndpoint implements ApplicationContext
|
|||
}
|
||||
|
||||
/**
|
||||
* {@link BeanSerializerModifier} to return only relevant configuration properties.
|
||||
* {@link ValueSerializerModifier} to return only relevant configuration properties.
|
||||
*/
|
||||
protected static class GenericSerializerModifier extends BeanSerializerModifier {
|
||||
protected static class GenericSerializerModifier extends ValueSerializerModifier {
|
||||
|
||||
private static final ParameterNameDiscoverer PARAMETER_NAME_DISCOVERER = new DefaultParameterNameDiscoverer();
|
||||
|
||||
@Override
|
||||
public List<BeanPropertyWriter> changeProperties(SerializationConfig config, BeanDescription beanDesc,
|
||||
public List<BeanPropertyWriter> changeProperties(SerializationConfig config, BeanDescription.Supplier beanDesc,
|
||||
List<BeanPropertyWriter> beanProperties) {
|
||||
List<BeanPropertyWriter> result = new ArrayList<>();
|
||||
Class<?> beanClass = beanDesc.getType().getRawClass();
|
||||
|
@ -508,7 +505,7 @@ public class ConfigurationPropertiesReportEndpoint implements ApplicationContext
|
|||
return result;
|
||||
}
|
||||
|
||||
private boolean isCandidate(BeanDescription beanDesc, BeanPropertyWriter writer,
|
||||
private boolean isCandidate(BeanDescription.Supplier beanDesc, BeanPropertyWriter writer,
|
||||
@Nullable Constructor<?> constructor) {
|
||||
if (constructor != null) {
|
||||
Parameter[] parameters = constructor.getParameters();
|
||||
|
@ -529,10 +526,10 @@ public class ConfigurationPropertiesReportEndpoint implements ApplicationContext
|
|||
return isReadable(beanDesc, writer);
|
||||
}
|
||||
|
||||
private boolean isReadable(BeanDescription beanDesc, BeanPropertyWriter writer) {
|
||||
Class<?> parentType = beanDesc.getType().getRawClass();
|
||||
private boolean isReadable(BeanDescription.Supplier beanDesc, BeanPropertyWriter writer) {
|
||||
Class<?> parentType = beanDesc.get().getType().getRawClass();
|
||||
Class<?> type = writer.getType().getRawClass();
|
||||
AnnotatedMethod setter = findSetter(beanDesc, writer);
|
||||
AnnotatedMethod setter = findSetter(beanDesc.get(), writer);
|
||||
// If there's a setter, we assume it's OK to report on the value,
|
||||
// similarly, if there's no setter but the package names match, we assume
|
||||
// that it is a nested class used solely for binding to config props, so it
|
||||
|
|
|
@ -18,8 +18,8 @@ package org.springframework.boot.actuate.endpoint;
|
|||
|
||||
import java.util.Map;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import tools.jackson.databind.ObjectMapper;
|
||||
|
||||
import org.springframework.lang.Contract;
|
||||
|
||||
|
|
|
@ -18,19 +18,19 @@ package org.springframework.boot.actuate.endpoint.jackson;
|
|||
|
||||
import java.util.Set;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import tools.jackson.databind.json.JsonMapper;
|
||||
|
||||
import org.springframework.boot.actuate.endpoint.OperationResponseBody;
|
||||
|
||||
/**
|
||||
* Interface used to supply the {@link ObjectMapper} that should be used when serializing
|
||||
* Interface used to supply the {@link JsonMapper} that should be used when serializing
|
||||
* endpoint results.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @since 3.0.0
|
||||
* @since 4.0.0
|
||||
* @see OperationResponseBody
|
||||
*/
|
||||
public interface EndpointObjectMapper {
|
||||
public interface EndpointJsonMapper {
|
||||
|
||||
/**
|
||||
* The default supported types.
|
||||
|
@ -38,16 +38,15 @@ public interface EndpointObjectMapper {
|
|||
Set<Class<?>> DEFAULT_SUPPORTED_TYPES = Set.of(OperationResponseBody.class);
|
||||
|
||||
/**
|
||||
* Return the {@link ObjectMapper} that should be used to serialize
|
||||
* Return the {@link JsonMapper} that should be used to serialize
|
||||
* {@link OperationResponseBody} endpoint results.
|
||||
* @return the object mapper
|
||||
*/
|
||||
ObjectMapper get();
|
||||
JsonMapper get();
|
||||
|
||||
/**
|
||||
* Return the types that this endpoint mapper supports.
|
||||
* @return the supported types
|
||||
* @since 4.0.0
|
||||
*/
|
||||
default Set<Class<?>> getSupportedTypes() {
|
||||
return DEFAULT_SUPPORTED_TYPES;
|
|
@ -20,9 +20,9 @@ import java.util.Collection;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.fasterxml.jackson.databind.JavaType;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import tools.jackson.databind.JavaType;
|
||||
import tools.jackson.databind.ObjectMapper;
|
||||
|
||||
/**
|
||||
* {@link JmxOperationResponseMapper} that delegates to a Jackson {@link ObjectMapper} to
|
||||
|
|
|
@ -20,6 +20,7 @@ import java.util.Collections;
|
|||
|
||||
import org.json.JSONObject;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import tools.jackson.databind.ObjectMapper;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||
|
@ -69,13 +70,10 @@ class AuditEventTests {
|
|||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings({ "removal", "deprecation" })
|
||||
void jsonFormat() throws Exception {
|
||||
AuditEvent event = new AuditEvent("johannes", "UNKNOWN",
|
||||
Collections.singletonMap("type", (Object) "BadCredentials"));
|
||||
String json = org.springframework.http.converter.json.Jackson2ObjectMapperBuilder.json()
|
||||
.build()
|
||||
.writeValueAsString(event);
|
||||
String json = new ObjectMapper().writeValueAsString(event);
|
||||
JSONObject jsonObject = new JSONObject(json);
|
||||
assertThat(jsonObject.getString("type")).isEqualTo("UNKNOWN");
|
||||
assertThat(jsonObject.getJSONObject("data").getString("type")).isEqualTo("BadCredentials");
|
||||
|
|
|
@ -179,7 +179,7 @@ class ConfigurationPropertiesReportEndpointTests {
|
|||
void descriptorWithMixedCaseProperty() {
|
||||
this.contextRunner.withUserConfiguration(MixedCasePropertiesConfiguration.class)
|
||||
.run(assertProperties("mixedcase",
|
||||
(properties) -> assertThat(properties.get("mIxedCase")).isEqualTo("mixed")));
|
||||
(properties) -> assertThat(properties).containsEntry("mIxedCase", "mixed")));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -23,9 +23,9 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.fasterxml.jackson.databind.JavaType;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import tools.jackson.databind.JavaType;
|
||||
import tools.jackson.databind.ObjectMapper;
|
||||
|
||||
import org.springframework.boot.test.json.BasicJsonTester;
|
||||
|
||||
|
|
|
@ -20,10 +20,10 @@ import java.util.Collections;
|
|||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.fasterxml.jackson.databind.MapperFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.json.JsonMapper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import tools.jackson.databind.MapperFeature;
|
||||
import tools.jackson.databind.ObjectMapper;
|
||||
import tools.jackson.databind.json.JsonMapper;
|
||||
|
||||
import org.springframework.boot.actuate.endpoint.ApiVersion;
|
||||
import org.springframework.boot.health.contributor.Health;
|
||||
|
|
|
@ -16,10 +16,10 @@
|
|||
|
||||
package org.springframework.boot.actuate.health;
|
||||
|
||||
import com.fasterxml.jackson.databind.MapperFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.json.JsonMapper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import tools.jackson.databind.MapperFeature;
|
||||
import tools.jackson.databind.ObjectMapper;
|
||||
import tools.jackson.databind.json.JsonMapper;
|
||||
|
||||
import org.springframework.boot.health.contributor.Health;
|
||||
|
||||
|
|
|
@ -22,10 +22,10 @@ import java.util.LinkedHashSet;
|
|||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.fasterxml.jackson.databind.MapperFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.json.JsonMapper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import tools.jackson.databind.MapperFeature;
|
||||
import tools.jackson.databind.ObjectMapper;
|
||||
import tools.jackson.databind.json.JsonMapper;
|
||||
|
||||
import org.springframework.boot.actuate.endpoint.ApiVersion;
|
||||
import org.springframework.boot.health.contributor.Health;
|
||||
|
|
|
@ -33,6 +33,7 @@ dependencies {
|
|||
optional(project(":core:spring-boot-testcontainers"))
|
||||
optional(project(":module:spring-boot-health"))
|
||||
optional(project(":module:spring-boot-jackson"))
|
||||
optional("com.fasterxml.jackson.core:jackson-databind")
|
||||
optional("org.testcontainers:couchbase")
|
||||
|
||||
dockerTestImplementation(project(":core:spring-boot-test"))
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
package org.springframework.boot.couchbase.autoconfigure;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
|
@ -33,6 +32,7 @@ import com.couchbase.client.java.codec.JsonSerializer;
|
|||
import com.couchbase.client.java.env.ClusterEnvironment;
|
||||
import com.couchbase.client.java.json.JsonValueModule;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.module.SimpleModule;
|
||||
import org.assertj.core.api.InstanceOfAssertFactories;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
|
@ -129,14 +129,14 @@ class CouchbaseAutoConfigurationTests {
|
|||
|
||||
@Test
|
||||
void whenObjectMapperBeanIsDefinedThenClusterEnvironmentObjectMapperIsDerivedFromIt() {
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
objectMapper.registerModule(new SimpleModule("custom"));
|
||||
this.contextRunner.withUserConfiguration(CouchbaseTestConfiguration.class)
|
||||
.withConfiguration(AutoConfigurations.of(JacksonAutoConfiguration.class))
|
||||
.withBean(ObjectMapper.class, () -> objectMapper)
|
||||
.withPropertyValues("spring.couchbase.connection-string=localhost")
|
||||
.run((context) -> {
|
||||
ClusterEnvironment env = context.getBean(ClusterEnvironment.class);
|
||||
Set<Object> expectedModuleIds = new HashSet<>(
|
||||
context.getBean(ObjectMapper.class).getRegisteredModuleIds());
|
||||
expectedModuleIds.add(new JsonValueModule().getTypeId());
|
||||
Set<Object> expectedModuleIds = Set.of("custom", new JsonValueModule().getTypeId());
|
||||
JsonSerializer serializer = env.jsonSerializer();
|
||||
assertThat(serializer).extracting("wrapped")
|
||||
.isInstanceOf(JacksonJsonSerializer.class)
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue