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-gradle-test-support"))
|
||||||
testImplementation(project(":test-support:spring-boot-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("com.tngtech.archunit:archunit-junit5:1.4.0")
|
||||||
testImplementation("net.java.dev.jna:jna-platform")
|
testImplementation("net.java.dev.jna:jna-platform")
|
||||||
testImplementation("org.apache.commons:commons-compress")
|
testImplementation("org.apache.commons:commons-compress")
|
||||||
|
@ -70,6 +68,7 @@ dependencies {
|
||||||
testImplementation("org.jetbrains.kotlin:kotlin-compiler-runner:$kotlinVersion")
|
testImplementation("org.jetbrains.kotlin:kotlin-compiler-runner:$kotlinVersion")
|
||||||
testImplementation("org.jetbrains.kotlin:kotlin-daemon-client:$kotlinVersion")
|
testImplementation("org.jetbrains.kotlin:kotlin-daemon-client:$kotlinVersion")
|
||||||
testImplementation("org.tomlj:tomlj:1.0.0")
|
testImplementation("org.tomlj:tomlj:1.0.0")
|
||||||
|
testImplementation("tools.jackson.core:jackson-databind")
|
||||||
}
|
}
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
|
|
|
@ -22,9 +22,6 @@ import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonView;
|
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 com.sun.jna.Platform;
|
||||||
import io.spring.gradle.dependencymanagement.DependencyManagementPlugin;
|
import io.spring.gradle.dependencymanagement.DependencyManagementPlugin;
|
||||||
import org.antlr.v4.runtime.Lexer;
|
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.project.model.LanguageSettings;
|
||||||
import org.jetbrains.kotlin.tooling.core.KotlinToolingVersion;
|
import org.jetbrains.kotlin.tooling.core.KotlinToolingVersion;
|
||||||
import org.tomlj.Toml;
|
import org.tomlj.Toml;
|
||||||
|
import tools.jackson.core.JsonParser;
|
||||||
|
import tools.jackson.databind.JacksonModule;
|
||||||
|
|
||||||
import org.springframework.asm.ClassVisitor;
|
import org.springframework.asm.ClassVisitor;
|
||||||
import org.springframework.boot.buildpack.platform.build.BuildRequest;
|
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(HttpClientConnectionManager.class)));
|
||||||
classpath.add(new File(pathOfJarContaining(HttpRequest.class)));
|
classpath.add(new File(pathOfJarContaining(HttpRequest.class)));
|
||||||
classpath.add(new File(pathOfJarContaining(HttpVersionPolicy.class)));
|
classpath.add(new File(pathOfJarContaining(HttpVersionPolicy.class)));
|
||||||
classpath.add(new File(pathOfJarContaining(Module.class)));
|
classpath.add(new File(pathOfJarContaining(JacksonModule.class)));
|
||||||
classpath.add(new File(pathOfJarContaining(Versioned.class)));
|
classpath.add(new File(pathOfJarContaining(JsonParser.class)));
|
||||||
classpath.add(new File(pathOfJarContaining(ParameterNamesModule.class)));
|
|
||||||
classpath.add(new File(pathOfJarContaining("com.github.openjson.JSONObject")));
|
classpath.add(new File(pathOfJarContaining("com.github.openjson.JSONObject")));
|
||||||
classpath.add(new File(pathOfJarContaining(JsonView.class)));
|
classpath.add(new File(pathOfJarContaining(JsonView.class)));
|
||||||
classpath.add(new File(pathOfJarContaining(Platform.class)));
|
classpath.add(new File(pathOfJarContaining(Platform.class)));
|
||||||
|
|
|
@ -43,9 +43,9 @@ dependencies {
|
||||||
checkstyle("com.puppycrawl.tools:checkstyle:${checkstyle.toolVersion}")
|
checkstyle("com.puppycrawl.tools:checkstyle:${checkstyle.toolVersion}")
|
||||||
checkstyle("io.spring.javaformat:spring-javaformat-checkstyle:${javaFormatVersion}")
|
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(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.github.node-gradle:gradle-node-plugin:3.5.1")
|
||||||
implementation("com.gradle:develocity-gradle-plugin:3.17.2")
|
implementation("com.gradle:develocity-gradle-plugin:3.17.2")
|
||||||
implementation("com.tngtech.archunit:archunit:1.4.1")
|
implementation("com.tngtech.archunit:archunit:1.4.1")
|
||||||
|
@ -65,6 +65,7 @@ dependencies {
|
||||||
implementation("org.springframework:spring-web")
|
implementation("org.springframework:spring-web")
|
||||||
implementation("org.yaml:snakeyaml:${snakeYamlVersion}")
|
implementation("org.yaml:snakeyaml:${snakeYamlVersion}")
|
||||||
implementation("io.spring.gradle.nullability:nullability-plugin:${nullabilityPluginVersion}")
|
implementation("io.spring.gradle.nullability:nullability-plugin:${nullabilityPluginVersion}")
|
||||||
|
implementation("tools.jackson.core:jackson-databind")
|
||||||
|
|
||||||
testImplementation(platform("org.junit:junit-bom:${junitJupiterVersion}"))
|
testImplementation(platform("org.junit:junit-bom:${junitJupiterVersion}"))
|
||||||
testImplementation("org.assertj:assertj-core:${assertjVersion}")
|
testImplementation("org.assertj:assertj-core:${assertjVersion}")
|
||||||
|
|
|
@ -6,4 +6,11 @@
|
||||||
<module name="io.spring.javaformat.checkstyle.SpringChecks">
|
<module name="io.spring.javaformat.checkstyle.SpringChecks">
|
||||||
<property name="excludes" value="com.puppycrawl.tools.checkstyle.checks.javadoc.JavadocPackageCheck" />
|
<property name="excludes" value="com.puppycrawl.tools.checkstyle.checks.javadoc.JavadocPackageCheck" />
|
||||||
</module>
|
</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;
|
package org.springframework.boot.build;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.UncheckedIOException;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
@ -26,7 +24,6 @@ import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
||||||
import com.github.gradle.node.NodeExtension;
|
import com.github.gradle.node.NodeExtension;
|
||||||
import com.github.gradle.node.npm.task.NpmInstallTask;
|
import com.github.gradle.node.npm.task.NpmInstallTask;
|
||||||
import io.spring.gradle.antora.GenerateAntoraYmlPlugin;
|
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.Copy;
|
||||||
import org.gradle.api.tasks.TaskContainer;
|
import org.gradle.api.tasks.TaskContainer;
|
||||||
import org.gradle.api.tasks.TaskProvider;
|
import org.gradle.api.tasks.TaskProvider;
|
||||||
|
import tools.jackson.databind.ObjectMapper;
|
||||||
|
|
||||||
import org.springframework.boot.build.antora.AntoraAsciidocAttributes;
|
import org.springframework.boot.build.antora.AntoraAsciidocAttributes;
|
||||||
import org.springframework.boot.build.antora.GenerateAntoraPlaybook;
|
import org.springframework.boot.build.antora.GenerateAntoraPlaybook;
|
||||||
|
@ -198,18 +196,13 @@ public class AntoraConventions {
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getUiBundleUrl(Project project) {
|
private String getUiBundleUrl(Project project) {
|
||||||
try {
|
File packageJson = project.getRootProject().file("antora/package.json");
|
||||||
File packageJson = project.getRootProject().file("antora/package.json");
|
ObjectMapper objectMapper = new ObjectMapper();
|
||||||
ObjectMapper objectMapper = new ObjectMapper();
|
Map<?, ?> json = objectMapper.readerFor(Map.class).readValue(packageJson);
|
||||||
Map<?, ?> json = objectMapper.readerFor(Map.class).readValue(packageJson);
|
Map<?, ?> config = (json != null) ? (Map<?, ?>) json.get("config") : null;
|
||||||
Map<?, ?> config = (json != null) ? (Map<?, ?>) json.get("config") : null;
|
String url = (config != null) ? (String) config.get("ui-bundle-url") : 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");
|
||||||
Assert.state(StringUtils.hasText(url.toString()), "package.json has not ui-bundle-url config");
|
return url;
|
||||||
return url;
|
|
||||||
}
|
|
||||||
catch (IOException ex) {
|
|
||||||
throw new UncheckedIOException(ex);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void configureNodeExtension(Project project, NodeExtension nodeExtension) {
|
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-native-build-tools", (String) this.projectProperties.get("nativeBuildToolsVersion"));
|
||||||
attributes.put("version-graal", (String) this.projectProperties.get("graalVersion"));
|
attributes.put("version-graal", (String) this.projectProperties.get("graalVersion"));
|
||||||
addDependencyVersion(attributes, "jackson-annotations", "com.fasterxml.jackson.core:jackson-annotations");
|
addDependencyVersion(attributes, "jackson-annotations", "com.fasterxml.jackson.core:jackson-annotations");
|
||||||
addDependencyVersion(attributes, "jackson-core", "com.fasterxml.jackson.core:jackson-core");
|
addDependencyVersion(attributes, "jackson-core", "tools.jackson.core:jackson-core");
|
||||||
addDependencyVersion(attributes, "jackson-databind", "com.fasterxml.jackson.core:jackson-databind");
|
addDependencyVersion(attributes, "jackson-databind", "tools.jackson.core:jackson-databind");
|
||||||
addDependencyVersion(attributes, "jackson-dataformat-xml",
|
addDependencyVersion(attributes, "jackson-dataformat-xml", "tools.jackson.dataformat:jackson-dataformat-xml");
|
||||||
"com.fasterxml.jackson.dataformat:jackson-dataformat-xml");
|
|
||||||
addSpringDataDependencyVersion(attributes, internal, "spring-data-commons");
|
addSpringDataDependencyVersion(attributes, internal, "spring-data-commons");
|
||||||
addSpringDataDependencyVersion(attributes, internal, "spring-data-couchbase");
|
addSpringDataDependencyVersion(attributes, internal, "spring-data-couchbase");
|
||||||
addSpringDataDependencyVersion(attributes, internal, "spring-data-cassandra");
|
addSpringDataDependencyVersion(attributes, internal, "spring-data-cassandra");
|
||||||
|
|
|
@ -25,10 +25,8 @@ import java.net.URI;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonInclude.Include;
|
import com.fasterxml.jackson.annotation.JsonInclude.Include;
|
||||||
import com.fasterxml.jackson.annotation.JsonSetter;
|
import tools.jackson.databind.ObjectMapper;
|
||||||
import com.fasterxml.jackson.annotation.Nulls;
|
import tools.jackson.databind.json.JsonMapper;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
||||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A resolved bom.
|
* A resolved bom.
|
||||||
|
@ -42,10 +40,9 @@ public record ResolvedBom(Id id, List<ResolvedLibrary> libraries) {
|
||||||
private static final ObjectMapper objectMapper;
|
private static final ObjectMapper objectMapper;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
ObjectMapper mapper = new ObjectMapper().enable(SerializationFeature.INDENT_OUTPUT)
|
objectMapper = JsonMapper.builder()
|
||||||
.setDefaultPropertyInclusion(Include.NON_EMPTY);
|
.changeDefaultPropertyInclusion((value) -> value.withContentInclusion(Include.NON_EMPTY))
|
||||||
mapper.configOverride(List.class).setSetterInfo(JsonSetter.Value.forValueNulls(Nulls.AS_EMPTY));
|
.build();
|
||||||
objectMapper = mapper;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ResolvedBom readFrom(File file) {
|
public static ResolvedBom readFrom(File file) {
|
||||||
|
@ -58,12 +55,7 @@ public record ResolvedBom(Id id, List<ResolvedLibrary> libraries) {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeTo(Writer writer) {
|
public void writeTo(Writer writer) {
|
||||||
try {
|
objectMapper.writeValue(writer, this);
|
||||||
objectMapper.writeValue(writer, this);
|
|
||||||
}
|
|
||||||
catch (IOException ex) {
|
|
||||||
throw new UncheckedIOException(ex);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public record ResolvedLibrary(String name, String version, String versionProperty, List<Id> managedDependencies,
|
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.Base64;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
||||||
|
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.http.converter.json.JacksonJsonHttpMessageConverter;
|
||||||
import org.springframework.web.client.RestTemplate;
|
import org.springframework.web.client.RestTemplate;
|
||||||
import org.springframework.web.util.DefaultUriBuilderFactory;
|
import org.springframework.web.util.DefaultUriBuilderFactory;
|
||||||
import org.springframework.web.util.UriTemplateHandler;
|
import org.springframework.web.util.UriTemplateHandler;
|
||||||
|
@ -61,8 +60,7 @@ final class StandardGitHub implements GitHub {
|
||||||
|
|
||||||
@SuppressWarnings({ "deprecation", "removal" })
|
@SuppressWarnings({ "deprecation", "removal" })
|
||||||
private RestTemplate createRestTemplate() {
|
private RestTemplate createRestTemplate() {
|
||||||
return new RestTemplate(Collections.singletonList(
|
return new RestTemplate(Collections.singletonList(new JacksonJsonHttpMessageConverter()));
|
||||||
new org.springframework.http.converter.json.MappingJackson2HttpMessageConverter(new ObjectMapper())));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,9 +28,6 @@ import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
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.FileTree;
|
||||||
import org.gradle.api.file.RegularFileProperty;
|
import org.gradle.api.file.RegularFileProperty;
|
||||||
import org.gradle.api.tasks.InputFiles;
|
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.SourceTask;
|
||||||
import org.gradle.api.tasks.TaskAction;
|
import org.gradle.api.tasks.TaskAction;
|
||||||
import org.gradle.api.tasks.VerificationException;
|
import org.gradle.api.tasks.VerificationException;
|
||||||
|
import tools.jackson.databind.ObjectMapper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link SourceTask} that checks additional Spring configuration metadata files.
|
* {@link SourceTask} that checks additional Spring configuration metadata files.
|
||||||
|
@ -65,7 +63,7 @@ public abstract class CheckAdditionalSpringConfigurationMetadata extends SourceT
|
||||||
}
|
}
|
||||||
|
|
||||||
@TaskAction
|
@TaskAction
|
||||||
void check() throws JsonParseException, IOException {
|
void check() throws IOException {
|
||||||
Report report = createReport();
|
Report report = createReport();
|
||||||
File reportFile = getReportLocation().get().getAsFile();
|
File reportFile = getReportLocation().get().getAsFile();
|
||||||
Files.write(reportFile.toPath(), report, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
|
Files.write(reportFile.toPath(), report, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
|
||||||
|
@ -76,7 +74,7 @@ public abstract class CheckAdditionalSpringConfigurationMetadata extends SourceT
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private Report createReport() throws IOException, JsonParseException, JsonMappingException {
|
private Report createReport() {
|
||||||
ObjectMapper objectMapper = new ObjectMapper();
|
ObjectMapper objectMapper = new ObjectMapper();
|
||||||
Report report = new Report();
|
Report report = new Report();
|
||||||
for (File file : getSource().getFiles()) {
|
for (File file : getSource().getFiles()) {
|
||||||
|
|
|
@ -26,9 +26,6 @@ import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
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.DefaultTask;
|
||||||
import org.gradle.api.file.RegularFileProperty;
|
import org.gradle.api.file.RegularFileProperty;
|
||||||
import org.gradle.api.provider.ListProperty;
|
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.SourceTask;
|
||||||
import org.gradle.api.tasks.TaskAction;
|
import org.gradle.api.tasks.TaskAction;
|
||||||
import org.gradle.api.tasks.VerificationException;
|
import org.gradle.api.tasks.VerificationException;
|
||||||
|
import tools.jackson.databind.ObjectMapper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link SourceTask} that checks {@code spring-configuration-metadata.json} files.
|
* {@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();
|
public abstract ListProperty<String> getExclusions();
|
||||||
|
|
||||||
@TaskAction
|
@TaskAction
|
||||||
void check() throws JsonParseException, IOException {
|
void check() throws IOException {
|
||||||
Report report = createReport();
|
Report report = createReport();
|
||||||
File reportFile = getReportLocation().get().getAsFile();
|
File reportFile = getReportLocation().get().getAsFile();
|
||||||
Files.write(reportFile.toPath(), report, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
|
Files.write(reportFile.toPath(), report, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
|
||||||
|
@ -76,7 +74,7 @@ public abstract class CheckSpringConfigurationMetadata extends DefaultTask {
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private Report createReport() throws IOException, JsonParseException, JsonMappingException {
|
private Report createReport() {
|
||||||
ObjectMapper objectMapper = new ObjectMapper();
|
ObjectMapper objectMapper = new ObjectMapper();
|
||||||
File file = getMetadataLocation().get().getAsFile();
|
File file = getMetadataLocation().get().getAsFile();
|
||||||
Report report = new Report(this.projectRoot.relativize(file.toPath()));
|
Report report = new Report(this.projectRoot.relativize(file.toPath()));
|
||||||
|
|
|
@ -17,7 +17,6 @@
|
||||||
package org.springframework.boot.build.context.properties;
|
package org.springframework.boot.build.context.properties;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
|
@ -25,7 +24,7 @@ import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import tools.jackson.databind.ObjectMapper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configuration properties read from one or more
|
* Configuration properties read from one or more
|
||||||
|
@ -56,20 +55,15 @@ final class ConfigurationProperties {
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
static ConfigurationProperties fromFiles(Iterable<File> files) {
|
static ConfigurationProperties fromFiles(Iterable<File> files) {
|
||||||
try {
|
ObjectMapper objectMapper = new ObjectMapper();
|
||||||
ObjectMapper objectMapper = new ObjectMapper();
|
List<ConfigurationProperty> properties = new ArrayList<>();
|
||||||
List<ConfigurationProperty> properties = new ArrayList<>();
|
for (File file : files) {
|
||||||
for (File file : files) {
|
Map<String, Object> json = objectMapper.readValue(file, Map.class);
|
||||||
Map<String, Object> json = objectMapper.readValue(file, Map.class);
|
for (Map<String, Object> property : (List<Map<String, Object>>) json.get("properties")) {
|
||||||
for (Map<String, Object> property : (List<Map<String, Object>>) json.get("properties")) {
|
properties.add(ConfigurationProperty.fromJsonProperties(property));
|
||||||
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-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-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-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-core-javadoc=https://javadoc.io/doc/tools.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-databind-javadoc=https://javadoc.io/doc/tools.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-dataformat-xml-javadoc=https://javadoc.io/doc/tools.jackson.dataformat/jackson-dataformat-xml/{version-jackson-dataformat-xml}
|
||||||
|
|
||||||
# === Javadoc Locations ===
|
# === 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-client-api={url-pulsar-client-api-javadoc}
|
||||||
javadoc-location-org-apache-pulsar-reactive-client-api={url-pulsar-client-reactive-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}
|
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-r2dbc={url-spring-data-r2dbc-javadoc}
|
||||||
javadoc-location-org-springframework-data-redis={url-spring-data-redis-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-org-springframework-data-rest={url-spring-data-rest-javadoc}
|
||||||
javadoc-location-com-fasterxml-jackson-annotation={url-jackson-annotations-javadoc}
|
javadoc-location-tools-jackson-core={url-jackson-core-javadoc}
|
||||||
javadoc-location-com-fasterxml-jackson-core={url-jackson-core-javadoc}
|
javadoc-location-tools-jackson-databind={url-jackson-databind-javadoc}
|
||||||
javadoc-location-com-fasterxml-jackson-databind={url-jackson-databind-javadoc}
|
javadoc-location-tools-jackson-dataformat-xml={url-jackson-dataformat-xml-javadoc}
|
||||||
javadoc-location-com-fasterxml-jackson-dataformat-xml={url-jackson-dataformat-xml-javadoc}
|
|
||||||
|
|
||||||
# === API References ===
|
# === API References ===
|
||||||
|
|
||||||
|
|
|
@ -280,12 +280,12 @@ class AntoraAsciidocAttributesTests {
|
||||||
addMockTestcontainersVersion(versions, "rabbitmq", version);
|
addMockTestcontainersVersion(versions, "rabbitmq", version);
|
||||||
addMockTestcontainersVersion(versions, "redpanda", version);
|
addMockTestcontainersVersion(versions, "redpanda", version);
|
||||||
addMockTestcontainersVersion(versions, "r2dbc", version);
|
addMockTestcontainersVersion(versions, "r2dbc", version);
|
||||||
addMockJacksonCoreVersion(versions, "jackson-annotations", version);
|
addMockJackson2CoreVersion(versions, "jackson-annotations", version);
|
||||||
addMockJacksonCoreVersion(versions, "jackson-core", version);
|
addMockJacksonCoreVersion(versions, "jackson-core", version);
|
||||||
addMockJacksonCoreVersion(versions, "jackson-databind", version);
|
addMockJacksonCoreVersion(versions, "jackson-databind", version);
|
||||||
versions.put("org.apache.pulsar:pulsar-client-api", version);
|
versions.put("org.apache.pulsar:pulsar-client-api", version);
|
||||||
versions.put("org.apache.pulsar:pulsar-client-reactive-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;
|
return versions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -297,8 +297,12 @@ class AntoraAsciidocAttributesTests {
|
||||||
versions.put("org.testcontainers:" + artifactId, version);
|
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);
|
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")
|
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("net.java.dev.jna:jna-platform")
|
||||||
implementation("org.apache.commons:commons-compress")
|
implementation("org.apache.commons:commons-compress")
|
||||||
implementation("org.apache.httpcomponents.client5:httpclient5")
|
implementation("org.apache.httpcomponents.client5:httpclient5")
|
||||||
implementation("org.springframework:spring-core")
|
implementation("org.springframework:spring-core")
|
||||||
implementation("org.tomlj:tomlj:1.0.0")
|
implementation("org.tomlj:tomlj:1.0.0")
|
||||||
|
implementation("tools.jackson.core:jackson-databind")
|
||||||
|
|
||||||
testImplementation(project(":test-support:spring-boot-test-support"))
|
testImplementation(project(":test-support:spring-boot-test-support"))
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,10 +23,10 @@ import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.function.Consumer;
|
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 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.Image;
|
||||||
import org.springframework.boot.buildpack.platform.docker.type.ImageConfig;
|
import org.springframework.boot.buildpack.platform.docker.type.ImageConfig;
|
||||||
|
@ -152,7 +152,7 @@ class BuilderMetadata extends MappedObject {
|
||||||
String json = SharedObjectMapper.get().writeValueAsString(getNode());
|
String json = SharedObjectMapper.get().writeValueAsString(getNode());
|
||||||
update.withLabel(LABEL_NAME, json);
|
update.withLabel(LABEL_NAME, json);
|
||||||
}
|
}
|
||||||
catch (JsonProcessingException ex) {
|
catch (JacksonException ex) {
|
||||||
throw new IllegalStateException(ex);
|
throw new IllegalStateException(ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -239,7 +239,7 @@ class BuilderMetadata extends MappedObject {
|
||||||
RunImage(JsonNode node) {
|
RunImage(JsonNode node) {
|
||||||
super(node, MethodHandles.lookup());
|
super(node, MethodHandles.lookup());
|
||||||
this.image = extractImage();
|
this.image = extractImage();
|
||||||
this.mirrors = childrenAt("/mirrors", JsonNode::asText);
|
this.mirrors = childrenAt("/mirrors", JsonNode::asString);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String extractImage() {
|
private String extractImage() {
|
||||||
|
@ -352,7 +352,7 @@ class BuilderMetadata extends MappedObject {
|
||||||
private final ObjectNode copy;
|
private final ObjectNode copy;
|
||||||
|
|
||||||
private Update(BuilderMetadata source) {
|
private Update(BuilderMetadata source) {
|
||||||
this.copy = source.getNode().deepCopy();
|
this.copy = (ObjectNode) source.getNode().deepCopy();
|
||||||
}
|
}
|
||||||
|
|
||||||
private BuilderMetadata run(Consumer<Update> update) {
|
private BuilderMetadata run(Consumer<Update> update) {
|
||||||
|
|
|
@ -21,8 +21,8 @@ import java.lang.invoke.MethodHandles;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
|
||||||
import org.jspecify.annotations.Nullable;
|
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.Image;
|
||||||
import org.springframework.boot.buildpack.platform.docker.type.ImageConfig;
|
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.io.IOException;
|
||||||
import java.lang.invoke.MethodHandles;
|
import java.lang.invoke.MethodHandles;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
|
||||||
import org.jspecify.annotations.Nullable;
|
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.Image;
|
||||||
import org.springframework.boot.buildpack.platform.docker.type.ImageConfig;
|
import org.springframework.boot.buildpack.platform.docker.type.ImageConfig;
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
package org.springframework.boot.buildpack.platform.docker;
|
package org.springframework.boot.buildpack.platform.docker;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
@ -286,10 +287,13 @@ public class DockerApi {
|
||||||
listener.onStart();
|
listener.onStart();
|
||||||
try {
|
try {
|
||||||
try (Response response = http().post(loadUri, "application/x-tar", archive::writeTo)) {
|
try (Response response = http().post(loadUri, "application/x-tar", archive::writeTo)) {
|
||||||
jsonStream().get(response.getContent(), LoadImageUpdateEvent.class, (event) -> {
|
InputStream content = response.getContent();
|
||||||
streamListener.onUpdate(event);
|
if (content != null) {
|
||||||
listener.onUpdate(event);
|
jsonStream().get(content, LoadImageUpdateEvent.class, (event) -> {
|
||||||
});
|
streamListener.onUpdate(event);
|
||||||
|
listener.onUpdate(event);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
streamListener.assertValidResponseReceived();
|
streamListener.assertValidResponseReceived();
|
||||||
}
|
}
|
||||||
|
@ -395,7 +399,7 @@ public class DockerApi {
|
||||||
: buildUrl("/containers/create");
|
: buildUrl("/containers/create");
|
||||||
try (Response response = http().post(createUri, "application/json", config::writeTo)) {
|
try (Response response = http().post(createUri, "application/json", config::writeTo)) {
|
||||||
return ContainerReference
|
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 java.lang.invoke.MethodHandles;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
|
||||||
import org.jspecify.annotations.Nullable;
|
import org.jspecify.annotations.Nullable;
|
||||||
|
import tools.jackson.databind.JsonNode;
|
||||||
|
|
||||||
import org.springframework.boot.buildpack.platform.json.MappedObject;
|
import org.springframework.boot.buildpack.platform.json.MappedObject;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
|
@ -28,10 +28,10 @@ import java.util.HexFormat;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.function.Supplier;
|
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 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.MappedObject;
|
||||||
import org.springframework.boot.buildpack.platform.json.SharedObjectMapper;
|
import org.springframework.boot.buildpack.platform.json.SharedObjectMapper;
|
||||||
|
@ -120,7 +120,7 @@ final class DockerConfigurationMetadata {
|
||||||
try {
|
try {
|
||||||
return DockerConfig.fromJson(readPathContent(path));
|
return DockerConfig.fromJson(readPathContent(path));
|
||||||
}
|
}
|
||||||
catch (JsonProcessingException ex) {
|
catch (JacksonException ex) {
|
||||||
throw new IllegalStateException("Error parsing Docker configuration file '" + path + "'", ex);
|
throw new IllegalStateException("Error parsing Docker configuration file '" + path + "'", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -142,7 +142,7 @@ final class DockerConfigurationMetadata {
|
||||||
}
|
}
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
catch (JsonProcessingException ex) {
|
catch (JacksonException ex) {
|
||||||
throw new IllegalStateException("Error parsing Docker context metadata file '" + metaPath + "'", ex);
|
throw new IllegalStateException("Error parsing Docker context metadata file '" + metaPath + "'", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -181,7 +181,7 @@ final class DockerConfigurationMetadata {
|
||||||
super(node, MethodHandles.lookup());
|
super(node, MethodHandles.lookup());
|
||||||
this.currentContext = valueAt("/currentContext", String.class);
|
this.currentContext = valueAt("/currentContext", String.class);
|
||||||
this.credsStore = valueAt("/credsStore", 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);
|
this.auths = mapAt("/auths", Auth::new);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -201,7 +201,7 @@ final class DockerConfigurationMetadata {
|
||||||
return this.auths;
|
return this.auths;
|
||||||
}
|
}
|
||||||
|
|
||||||
static DockerConfig fromJson(String json) throws JsonProcessingException {
|
static DockerConfig fromJson(String json) {
|
||||||
return new DockerConfig(SharedObjectMapper.get().readTree(json));
|
return new DockerConfig(SharedObjectMapper.get().readTree(json));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -285,7 +285,7 @@ final class DockerConfigurationMetadata {
|
||||||
return new DockerContext(this.getNode(), tlsPath);
|
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);
|
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 java.util.Base64;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
|
||||||
import org.jspecify.annotations.Nullable;
|
import org.jspecify.annotations.Nullable;
|
||||||
|
import tools.jackson.core.JacksonException;
|
||||||
|
|
||||||
import org.springframework.boot.buildpack.platform.json.SharedObjectMapper;
|
import org.springframework.boot.buildpack.platform.json.SharedObjectMapper;
|
||||||
|
|
||||||
|
@ -44,7 +44,7 @@ class JsonEncodedDockerRegistryAuthentication implements DockerRegistryAuthentic
|
||||||
try {
|
try {
|
||||||
this.authHeader = Base64.getUrlEncoder().encodeToString(SharedObjectMapper.get().writeValueAsBytes(this));
|
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);
|
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.HttpRequest;
|
||||||
import org.apache.hc.core5.http.io.entity.AbstractHttpEntity;
|
import org.apache.hc.core5.http.io.entity.AbstractHttpEntity;
|
||||||
import org.jspecify.annotations.Nullable;
|
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.Content;
|
||||||
import org.springframework.boot.buildpack.platform.io.IOConsumer;
|
import org.springframework.boot.buildpack.platform.io.IOConsumer;
|
||||||
|
@ -196,7 +197,7 @@ abstract class HttpClientTransport implements HttpTransport {
|
||||||
try {
|
try {
|
||||||
return SharedObjectMapper.get().readValue(content, Errors.class);
|
return SharedObjectMapper.get().readValue(content, Errors.class);
|
||||||
}
|
}
|
||||||
catch (IOException ex) {
|
catch (JacksonException ex) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -209,7 +210,7 @@ abstract class HttpClientTransport implements HttpTransport {
|
||||||
Message message = SharedObjectMapper.get().readValue(content, Message.class);
|
Message message = SharedObjectMapper.get().readValue(content, Message.class);
|
||||||
return (message.getMessage() != null) ? message : null;
|
return (message.getMessage() != null) ? message : null;
|
||||||
}
|
}
|
||||||
catch (IOException ex) {
|
catch (JacksonException ex) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ package org.springframework.boot.buildpack.platform.docker.type;
|
||||||
|
|
||||||
import java.lang.invoke.MethodHandles;
|
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.boot.buildpack.platform.json.MappedObject;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
|
@ -26,10 +26,10 @@ import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.function.Consumer;
|
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 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.boot.buildpack.platform.json.SharedObjectMapper;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
@ -51,7 +51,7 @@ public class ContainerConfig {
|
||||||
|
|
||||||
ContainerConfig(@Nullable String user, ImageReference image, String command, List<String> args,
|
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,
|
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.notNull(image, "'image' must not be null");
|
||||||
Assert.hasText(command, "'command' must not be empty");
|
Assert.hasText(command, "'command' must not be empty");
|
||||||
ObjectMapper objectMapper = SharedObjectMapper.get();
|
ObjectMapper objectMapper = SharedObjectMapper.get();
|
||||||
|
@ -135,14 +135,9 @@ public class ContainerConfig {
|
||||||
|
|
||||||
private ContainerConfig run(Consumer<Update> update) {
|
private ContainerConfig run(Consumer<Update> update) {
|
||||||
update.accept(this);
|
update.accept(this);
|
||||||
try {
|
Assert.state(this.command != null, "'command' must not be null");
|
||||||
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,
|
||||||
return new ContainerConfig(this.user, this.image, this.command, this.args, this.labels, this.bindings,
|
this.env, this.networkMode, this.securityOptions);
|
||||||
this.env, this.networkMode, this.securityOptions);
|
|
||||||
}
|
|
||||||
catch (IOException ex) {
|
|
||||||
throw new IllegalStateException(ex);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -20,9 +20,9 @@ import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.lang.invoke.MethodHandles;
|
import java.lang.invoke.MethodHandles;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
|
||||||
import com.fasterxml.jackson.databind.node.NullNode;
|
|
||||||
import org.jspecify.annotations.Nullable;
|
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.boot.buildpack.platform.json.MappedObject;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
|
@ -23,8 +23,8 @@ import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
|
||||||
import org.jspecify.annotations.Nullable;
|
import org.jspecify.annotations.Nullable;
|
||||||
|
import tools.jackson.databind.JsonNode;
|
||||||
|
|
||||||
import org.springframework.boot.buildpack.platform.json.MappedObject;
|
import org.springframework.boot.buildpack.platform.json.MappedObject;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
@ -54,7 +54,7 @@ public class Image extends MappedObject {
|
||||||
|
|
||||||
Image(JsonNode node) {
|
Image(JsonNode node) {
|
||||||
super(node, MethodHandles.lookup());
|
super(node, MethodHandles.lookup());
|
||||||
this.digests = childrenAt("/RepoDigests", JsonNode::asText);
|
this.digests = childrenAt("/RepoDigests", JsonNode::asString);
|
||||||
this.config = new ImageConfig(getNode().at("/Config"));
|
this.config = new ImageConfig(getNode().at("/Config"));
|
||||||
this.layers = extractLayers(valueAt("/RootFS/Layers", String[].class));
|
this.layers = extractLayers(valueAt("/RootFS/Layers", String[].class));
|
||||||
this.os = valueAt("/Os", String.class);
|
this.os = valueAt("/Os", String.class);
|
||||||
|
|
|
@ -29,11 +29,11 @@ import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.function.Consumer;
|
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 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.Content;
|
||||||
import org.springframework.boot.buildpack.platform.io.IOConsumer;
|
import org.springframework.boot.buildpack.platform.io.IOConsumer;
|
||||||
|
@ -173,11 +173,11 @@ public class ImageArchive implements TarArchive {
|
||||||
private ObjectNode createConfig(List<LayerId> writtenLayers) {
|
private ObjectNode createConfig(List<LayerId> writtenLayers) {
|
||||||
ObjectNode config = this.objectMapper.createObjectNode();
|
ObjectNode config = this.objectMapper.createObjectNode();
|
||||||
config.set("Config", this.imageConfig.getNodeCopy());
|
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("History", createHistory(writtenLayers));
|
||||||
config.set("Os", config.textNode(this.os));
|
config.set("Os", config.stringNode(this.os));
|
||||||
config.set("Architecture", config.textNode(this.architecture));
|
config.set("Architecture", config.stringNode(this.architecture));
|
||||||
config.set("Variant", config.textNode(this.variant));
|
config.set("Variant", config.stringNode(this.variant));
|
||||||
config.set("RootFS", createRootFs(writtenLayers));
|
config.set("RootFS", createRootFs(writtenLayers));
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
|
@ -212,7 +212,7 @@ public class ImageArchive implements TarArchive {
|
||||||
private ArrayNode createManifest(String config, List<LayerId> writtenLayers) {
|
private ArrayNode createManifest(String config, List<LayerId> writtenLayers) {
|
||||||
ArrayNode manifest = this.objectMapper.createArrayNode();
|
ArrayNode manifest = this.objectMapper.createArrayNode();
|
||||||
ObjectNode entry = manifest.addObject();
|
ObjectNode entry = manifest.addObject();
|
||||||
entry.set("Config", entry.textNode(config));
|
entry.set("Config", entry.stringNode(config));
|
||||||
entry.set("Layers", getManifestLayers(writtenLayers));
|
entry.set("Layers", getManifestLayers(writtenLayers));
|
||||||
if (this.tag != null) {
|
if (this.tag != null) {
|
||||||
entry.set("RepoTags", entry.arrayNode().add(this.tag.toString()));
|
entry.set("RepoTags", entry.arrayNode().add(this.tag.toString()));
|
||||||
|
|
|
@ -21,7 +21,7 @@ import java.io.InputStream;
|
||||||
import java.lang.invoke.MethodHandles;
|
import java.lang.invoke.MethodHandles;
|
||||||
import java.util.List;
|
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.boot.buildpack.platform.json.MappedObject;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
|
@ -22,7 +22,7 @@ import java.lang.invoke.MethodHandles;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
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.boot.buildpack.platform.json.MappedObject;
|
||||||
|
|
||||||
|
|
|
@ -22,9 +22,9 @@ import java.util.LinkedHashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
|
||||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
|
||||||
import org.jspecify.annotations.Nullable;
|
import org.jspecify.annotations.Nullable;
|
||||||
|
import tools.jackson.databind.JsonNode;
|
||||||
|
import tools.jackson.databind.node.ObjectNode;
|
||||||
|
|
||||||
import org.springframework.boot.buildpack.platform.json.MappedObject;
|
import org.springframework.boot.buildpack.platform.json.MappedObject;
|
||||||
|
|
||||||
|
@ -111,7 +111,7 @@ public class ImageConfig extends MappedObject {
|
||||||
private final ObjectNode copy;
|
private final ObjectNode copy;
|
||||||
|
|
||||||
private Update(ImageConfig source) {
|
private Update(ImageConfig source) {
|
||||||
this.copy = source.getNode().deepCopy();
|
this.copy = (ObjectNode) source.getNode().deepCopy();
|
||||||
}
|
}
|
||||||
|
|
||||||
private ImageConfig run(Consumer<Update> update) {
|
private ImageConfig run(Consumer<Update> update) {
|
||||||
|
|
|
@ -21,8 +21,8 @@ import java.io.InputStream;
|
||||||
import java.lang.invoke.MethodHandles;
|
import java.lang.invoke.MethodHandles;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
|
||||||
import org.jspecify.annotations.Nullable;
|
import org.jspecify.annotations.Nullable;
|
||||||
|
import tools.jackson.databind.JsonNode;
|
||||||
|
|
||||||
import org.springframework.boot.buildpack.platform.json.MappedObject;
|
import org.springframework.boot.buildpack.platform.json.MappedObject;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
|
@ -22,8 +22,8 @@ import java.lang.invoke.MethodHandles;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
|
||||||
import org.jspecify.annotations.Nullable;
|
import org.jspecify.annotations.Nullable;
|
||||||
|
import tools.jackson.databind.JsonNode;
|
||||||
|
|
||||||
import org.springframework.boot.buildpack.platform.json.MappedObject;
|
import org.springframework.boot.buildpack.platform.json.MappedObject;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
|
@ -20,12 +20,11 @@ import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.function.Consumer;
|
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 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.
|
* 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
|
* @throws IOException on IO error
|
||||||
*/
|
*/
|
||||||
public <T> void get(InputStream content, Class<T> type, Consumer<T> consumer) throws IOException {
|
public <T> void get(InputStream content, Class<T> type, Consumer<T> consumer) throws IOException {
|
||||||
JsonFactory jsonFactory = this.objectMapper.getFactory();
|
try (JsonParser parser = this.objectMapper.createParser(content)) {
|
||||||
try (JsonParser parser = jsonFactory.createParser(content)) {
|
|
||||||
while (!parser.isClosed()) {
|
while (!parser.isClosed()) {
|
||||||
JsonToken token = parser.nextToken();
|
JsonToken token = parser.nextToken();
|
||||||
if (token != null && token != JsonToken.END_OBJECT) {
|
if (token != null && token != JsonToken.END_OBJECT) {
|
||||||
|
@ -79,9 +77,9 @@ public class JsonStream {
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@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)) {
|
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()) {
|
if (node == null || node.isMissingNode() || node.isEmpty()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,9 +30,10 @@ import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
||||||
import org.jspecify.annotations.Nullable;
|
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.Assert;
|
||||||
import org.springframework.util.StreamUtils;
|
import org.springframework.util.StreamUtils;
|
||||||
|
@ -111,7 +112,7 @@ public class MappedObject {
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
List<T> children = new ArrayList<>();
|
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);
|
return Collections.unmodifiableList(children);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -146,7 +147,7 @@ public class MappedObject {
|
||||||
try {
|
try {
|
||||||
return SharedObjectMapper.get().treeToValue(result, type);
|
return SharedObjectMapper.get().treeToValue(result, type);
|
||||||
}
|
}
|
||||||
catch (IOException ex) {
|
catch (JacksonException ex) {
|
||||||
throw new IllegalStateException(ex);
|
throw new IllegalStateException(ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,11 +16,12 @@
|
||||||
|
|
||||||
package org.springframework.boot.buildpack.platform.json;
|
package org.springframework.boot.buildpack.platform.json;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
import tools.jackson.core.json.JsonWriteFeature;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import tools.jackson.databind.DeserializationFeature;
|
||||||
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
|
import tools.jackson.databind.ObjectMapper;
|
||||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
import tools.jackson.databind.PropertyNamingStrategies;
|
||||||
import com.fasterxml.jackson.module.paramnames.ParameterNamesModule;
|
import tools.jackson.databind.SerializationFeature;
|
||||||
|
import tools.jackson.databind.json.JsonMapper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides access to a shared pre-configured {@link ObjectMapper}.
|
* Provides access to a shared pre-configured {@link ObjectMapper}.
|
||||||
|
@ -33,12 +34,12 @@ public final class SharedObjectMapper {
|
||||||
private static final ObjectMapper INSTANCE;
|
private static final ObjectMapper INSTANCE;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
ObjectMapper objectMapper = new ObjectMapper();
|
INSTANCE = JsonMapper.builder()
|
||||||
objectMapper.registerModule(new ParameterNamesModule());
|
.enable(SerializationFeature.INDENT_OUTPUT)
|
||||||
objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
|
.disable(DeserializationFeature.FAIL_ON_TRAILING_TOKENS)
|
||||||
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
.disable(JsonWriteFeature.ESCAPE_FORWARD_SLASHES)
|
||||||
objectMapper.setPropertyNamingStrategy(PropertyNamingStrategies.LOWER_CAMEL_CASE);
|
.propertyNamingStrategy(PropertyNamingStrategies.LOWER_CAMEL_CASE)
|
||||||
INSTANCE = objectMapper;
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
private SharedObjectMapper() {
|
private SharedObjectMapper() {
|
||||||
|
|
|
@ -26,9 +26,6 @@ import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
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 com.sun.jna.Platform;
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
@ -37,6 +34,8 @@ import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.params.ParameterizedTest;
|
import org.junit.jupiter.params.ParameterizedTest;
|
||||||
import org.mockito.stubbing.Answer;
|
import org.mockito.stubbing.Answer;
|
||||||
import org.skyscreamer.jsonassert.JSONAssert;
|
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;
|
||||||
import org.springframework.boot.buildpack.platform.docker.DockerApi.ContainerApi;
|
import org.springframework.boot.buildpack.platform.docker.DockerApi.ContainerApi;
|
||||||
|
@ -482,7 +481,7 @@ class LifecycleTests {
|
||||||
return (invocation) -> {
|
return (invocation) -> {
|
||||||
ContainerConfig config = invocation.getArgument(0, ContainerConfig.class);
|
ContainerConfig config = invocation.getArgument(0, ContainerConfig.class);
|
||||||
ArrayNode command = getCommand(config);
|
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);
|
this.configs.put(name, config);
|
||||||
if (invocation.getArguments().length > 2) {
|
if (invocation.getArguments().length > 2) {
|
||||||
this.content.put(name, invocation.getArgument(2, ContainerContent.class));
|
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());
|
JsonNode node = SharedObjectMapper.get().readTree(config.toString());
|
||||||
return (ArrayNode) node.at("/Cmd");
|
return (ArrayNode) node.at("/Cmd");
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,10 +24,10 @@ import java.util.HashMap;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import com.fasterxml.jackson.core.type.TypeReference;
|
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
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.docker.type.ImageReference;
|
||||||
import org.springframework.boot.buildpack.platform.json.SharedObjectMapper;
|
import org.springframework.boot.buildpack.platform.json.SharedObjectMapper;
|
||||||
|
|
|
@ -16,8 +16,6 @@
|
||||||
|
|
||||||
package org.springframework.boot.buildpack.platform.docker.type;
|
package org.springframework.boot.buildpack.platform.docker.type;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import org.springframework.boot.buildpack.platform.json.AbstractJsonTests;
|
import org.springframework.boot.buildpack.platform.json.AbstractJsonTests;
|
||||||
|
@ -32,7 +30,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||||
class ImageArchiveIndexTests extends AbstractJsonTests {
|
class ImageArchiveIndexTests extends AbstractJsonTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void loadJson() throws IOException {
|
void loadJson() {
|
||||||
String content = getContentAsString("image-archive-index.json");
|
String content = getContentAsString("image-archive-index.json");
|
||||||
ImageArchiveIndex index = getIndex(content);
|
ImageArchiveIndex index = getIndex(content);
|
||||||
assertThat(index.getSchemaVersion()).isEqualTo(2);
|
assertThat(index.getSchemaVersion()).isEqualTo(2);
|
||||||
|
@ -43,7 +41,7 @@ class ImageArchiveIndexTests extends AbstractJsonTests {
|
||||||
.isEqualTo("sha256:3bbe02431d8e5124ffe816ec27bf6508b50edd1d10218be1a03e799a186b9004");
|
.isEqualTo("sha256:3bbe02431d8e5124ffe816ec27bf6508b50edd1d10218be1a03e799a186b9004");
|
||||||
}
|
}
|
||||||
|
|
||||||
private ImageArchiveIndex getIndex(String content) throws IOException {
|
private ImageArchiveIndex getIndex(String content) {
|
||||||
return new ImageArchiveIndex(getObjectMapper().readTree(content));
|
return new ImageArchiveIndex(getObjectMapper().readTree(content));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
|
|
||||||
package org.springframework.boot.buildpack.platform.docker.type;
|
package org.springframework.boot.buildpack.platform.docker.type;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
@ -35,7 +34,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||||
class ImageArchiveManifestTests extends AbstractJsonTests {
|
class ImageArchiveManifestTests extends AbstractJsonTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void getLayersReturnsLayers() throws Exception {
|
void getLayersReturnsLayers() {
|
||||||
String content = getContentAsString("image-archive-manifest.json");
|
String content = getContentAsString("image-archive-manifest.json");
|
||||||
ImageArchiveManifest manifest = getManifest(content);
|
ImageArchiveManifest manifest = getManifest(content);
|
||||||
List<String> expectedLayers = new ArrayList<>();
|
List<String> expectedLayers = new ArrayList<>();
|
||||||
|
@ -49,7 +48,7 @@ class ImageArchiveManifestTests extends AbstractJsonTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void getLayersWithNoLayersReturnsEmptyList() throws Exception {
|
void getLayersWithNoLayersReturnsEmptyList() {
|
||||||
String content = "[{\"Layers\": []}]";
|
String content = "[{\"Layers\": []}]";
|
||||||
ImageArchiveManifest manifest = getManifest(content);
|
ImageArchiveManifest manifest = getManifest(content);
|
||||||
assertThat(manifest.getEntries()).hasSize(1);
|
assertThat(manifest.getEntries()).hasSize(1);
|
||||||
|
@ -57,13 +56,13 @@ class ImageArchiveManifestTests extends AbstractJsonTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void getLayersWithEmptyManifestReturnsEmptyList() throws Exception {
|
void getLayersWithEmptyManifestReturnsEmptyList() {
|
||||||
String content = "[]";
|
String content = "[]";
|
||||||
ImageArchiveManifest manifest = getManifest(content);
|
ImageArchiveManifest manifest = getManifest(content);
|
||||||
assertThat(manifest.getEntries()).isEmpty();
|
assertThat(manifest.getEntries()).isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
private ImageArchiveManifest getManifest(String content) throws IOException {
|
private ImageArchiveManifest getManifest(String content) {
|
||||||
return new ImageArchiveManifest(getObjectMapper().readTree(content));
|
return new ImageArchiveManifest(getObjectMapper().readTree(content));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
|
|
||||||
package org.springframework.boot.buildpack.platform.docker.type;
|
package org.springframework.boot.buildpack.platform.docker.type;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
@ -35,7 +34,7 @@ import static org.assertj.core.api.Assertions.entry;
|
||||||
class ImageConfigTests extends AbstractJsonTests {
|
class ImageConfigTests extends AbstractJsonTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void getEnvContainsParsedValues() throws Exception {
|
void getEnvContainsParsedValues() {
|
||||||
ImageConfig imageConfig = getImageConfig();
|
ImageConfig imageConfig = getImageConfig();
|
||||||
Map<String, String> env = imageConfig.getEnv();
|
Map<String, String> env = imageConfig.getEnv();
|
||||||
assertThat(env).contains(entry("PATH", "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"),
|
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
|
@Test
|
||||||
void whenConfigHasNoEnvThenImageConfigEnvIsEmpty() throws Exception {
|
void whenConfigHasNoEnvThenImageConfigEnvIsEmpty() {
|
||||||
ImageConfig imageConfig = getMinimalImageConfig();
|
ImageConfig imageConfig = getMinimalImageConfig();
|
||||||
Map<String, String> env = imageConfig.getEnv();
|
Map<String, String> env = imageConfig.getEnv();
|
||||||
assertThat(env).isEmpty();
|
assertThat(env).isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void whenConfigHasNoLabelsThenImageConfigLabelsIsEmpty() throws Exception {
|
void whenConfigHasNoLabelsThenImageConfigLabelsIsEmpty() {
|
||||||
ImageConfig imageConfig = getMinimalImageConfig();
|
ImageConfig imageConfig = getMinimalImageConfig();
|
||||||
Map<String, String> env = imageConfig.getLabels();
|
Map<String, String> env = imageConfig.getLabels();
|
||||||
assertThat(env).isEmpty();
|
assertThat(env).isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void getLabelsReturnsLabels() throws Exception {
|
void getLabelsReturnsLabels() {
|
||||||
ImageConfig imageConfig = getImageConfig();
|
ImageConfig imageConfig = getImageConfig();
|
||||||
Map<String, String> labels = imageConfig.getLabels();
|
Map<String, String> labels = imageConfig.getLabels();
|
||||||
assertThat(labels).hasSize(4).contains(entry("io.buildpacks.stack.id", "org.cloudfoundry.stacks.cflinuxfs3"));
|
assertThat(labels).hasSize(4).contains(entry("io.buildpacks.stack.id", "org.cloudfoundry.stacks.cflinuxfs3"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void updateWithLabelUpdatesLabels() throws Exception {
|
void updateWithLabelUpdatesLabels() {
|
||||||
ImageConfig imageConfig = getImageConfig();
|
ImageConfig imageConfig = getImageConfig();
|
||||||
ImageConfig updatedImageConfig = imageConfig
|
ImageConfig updatedImageConfig = imageConfig
|
||||||
.copy((update) -> update.withLabel("io.buildpacks.stack.id", "test"));
|
.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"));
|
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")));
|
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")));
|
return new ImageConfig(getObjectMapper().readTree(getContent("minimal-image-config.json")));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,8 +16,6 @@
|
||||||
|
|
||||||
package org.springframework.boot.buildpack.platform.docker.type;
|
package org.springframework.boot.buildpack.platform.docker.type;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import org.springframework.boot.buildpack.platform.json.AbstractJsonTests;
|
import org.springframework.boot.buildpack.platform.json.AbstractJsonTests;
|
||||||
|
@ -32,7 +30,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||||
class ManifestListTests extends AbstractJsonTests {
|
class ManifestListTests extends AbstractJsonTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void loadJsonFromDistributionManifestList() throws IOException {
|
void loadJsonFromDistributionManifestList() {
|
||||||
String content = getContentAsString("distribution-manifest-list.json");
|
String content = getContentAsString("distribution-manifest-list.json");
|
||||||
ManifestList manifestList = getManifestList(content);
|
ManifestList manifestList = getManifestList(content);
|
||||||
assertThat(manifestList.getSchemaVersion()).isEqualTo(2);
|
assertThat(manifestList.getSchemaVersion()).isEqualTo(2);
|
||||||
|
@ -40,7 +38,7 @@ class ManifestListTests extends AbstractJsonTests {
|
||||||
assertThat(manifestList.getManifests()).hasSize(2);
|
assertThat(manifestList.getManifests()).hasSize(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ManifestList getManifestList(String content) throws IOException {
|
private ManifestList getManifestList(String content) {
|
||||||
return new ManifestList(getObjectMapper().readTree(content));
|
return new ManifestList(getObjectMapper().readTree(content));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,8 +16,6 @@
|
||||||
|
|
||||||
package org.springframework.boot.buildpack.platform.docker.type;
|
package org.springframework.boot.buildpack.platform.docker.type;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import org.springframework.boot.buildpack.platform.json.AbstractJsonTests;
|
import org.springframework.boot.buildpack.platform.json.AbstractJsonTests;
|
||||||
|
@ -32,7 +30,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||||
class ManifestTests extends AbstractJsonTests {
|
class ManifestTests extends AbstractJsonTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void loadJsonFromDistributionManifest() throws IOException {
|
void loadJsonFromDistributionManifest() {
|
||||||
String content = getContentAsString("distribution-manifest.json");
|
String content = getContentAsString("distribution-manifest.json");
|
||||||
Manifest manifestList = getManifest(content);
|
Manifest manifestList = getManifest(content);
|
||||||
assertThat(manifestList.getSchemaVersion()).isEqualTo(2);
|
assertThat(manifestList.getSchemaVersion()).isEqualTo(2);
|
||||||
|
@ -41,7 +39,7 @@ class ManifestTests extends AbstractJsonTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void loadJsonFromImageManifest() throws IOException {
|
void loadJsonFromImageManifest() {
|
||||||
String content = getContentAsString("image-manifest.json");
|
String content = getContentAsString("image-manifest.json");
|
||||||
Manifest manifestList = getManifest(content);
|
Manifest manifestList = getManifest(content);
|
||||||
assertThat(manifestList.getSchemaVersion()).isEqualTo(2);
|
assertThat(manifestList.getSchemaVersion()).isEqualTo(2);
|
||||||
|
@ -49,7 +47,7 @@ class ManifestTests extends AbstractJsonTests {
|
||||||
assertThat(manifestList.getLayers()).hasSize(1);
|
assertThat(manifestList.getLayers()).hasSize(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Manifest getManifest(String content) throws IOException {
|
private Manifest getManifest(String content) {
|
||||||
return new Manifest(getObjectMapper().readTree(content));
|
return new Manifest(getObjectMapper().readTree(content));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ import java.io.UncheckedIOException;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import tools.jackson.databind.ObjectMapper;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
|
|
@ -20,8 +20,8 @@ import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
import tools.jackson.databind.node.ObjectNode;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
@ -44,7 +44,7 @@ class JsonStreamTests extends AbstractJsonTests {
|
||||||
List<ObjectNode> result = new ArrayList<>();
|
List<ObjectNode> result = new ArrayList<>();
|
||||||
this.jsonStream.get(getContent("stream.json"), result::add);
|
this.jsonStream.get(getContent("stream.json"), result::add);
|
||||||
assertThat(result).hasSize(595);
|
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");
|
.contains("Status: Downloaded newer image for paketo-buildpacks/cnb:base");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,8 +20,8 @@ import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.lang.invoke.MethodHandles;
|
import java.lang.invoke.MethodHandles;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
import tools.jackson.databind.JsonNode;
|
||||||
|
|
||||||
import org.springframework.boot.buildpack.platform.json.MappedObjectTests.TestMappedObject.Person;
|
import org.springframework.boot.buildpack.platform.json.MappedObjectTests.TestMappedObject.Person;
|
||||||
|
|
||||||
|
|
|
@ -16,12 +16,11 @@
|
||||||
|
|
||||||
package org.springframework.boot.buildpack.platform.json;
|
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 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;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
@ -36,14 +35,14 @@ class SharedObjectMapperTests {
|
||||||
void getReturnsConfiguredObjectMapper() {
|
void getReturnsConfiguredObjectMapper() {
|
||||||
ObjectMapper mapper = SharedObjectMapper.get();
|
ObjectMapper mapper = SharedObjectMapper.get();
|
||||||
assertThat(mapper).isNotNull();
|
assertThat(mapper).isNotNull();
|
||||||
assertThat(mapper.getRegisteredModuleIds()).contains(new ParameterNamesModule().getTypeId());
|
assertThat(
|
||||||
assertThat(SerializationFeature.INDENT_OUTPUT
|
SerializationFeature.INDENT_OUTPUT.enabledIn(mapper.serializationConfig().getSerializationFeatures()))
|
||||||
.enabledIn(mapper.getSerializationConfig().getSerializationFeatures())).isTrue();
|
.isTrue();
|
||||||
assertThat(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES
|
assertThat(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES
|
||||||
.enabledIn(mapper.getDeserializationConfig().getDeserializationFeatures())).isFalse();
|
.enabledIn(mapper.deserializationConfig().getDeserializationFeatures())).isFalse();
|
||||||
assertThat(mapper.getSerializationConfig().getPropertyNamingStrategy())
|
assertThat(mapper.serializationConfig().getPropertyNamingStrategy())
|
||||||
.isEqualTo(PropertyNamingStrategies.LOWER_CAMEL_CASE);
|
.isEqualTo(PropertyNamingStrategies.LOWER_CAMEL_CASE);
|
||||||
assertThat(mapper.getDeserializationConfig().getPropertyNamingStrategy())
|
assertThat(mapper.deserializationConfig().getPropertyNamingStrategy())
|
||||||
.isEqualTo(PropertyNamingStrategies.LOWER_CAMEL_CASE);
|
.isEqualTo(PropertyNamingStrategies.LOWER_CAMEL_CASE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -45,10 +45,10 @@ dependencies {
|
||||||
testImplementation(project(":test-support:spring-boot-test-support"))
|
testImplementation(project(":test-support:spring-boot-test-support"))
|
||||||
testImplementation(testFixtures(project(":core:spring-boot")))
|
testImplementation(testFixtures(project(":core:spring-boot")))
|
||||||
testImplementation("ch.qos.logback:logback-classic")
|
testImplementation("ch.qos.logback:logback-classic")
|
||||||
testImplementation("com.fasterxml.jackson.core:jackson-databind")
|
|
||||||
testImplementation("io.projectreactor:reactor-core")
|
testImplementation("io.projectreactor:reactor-core")
|
||||||
testImplementation("org.springframework:spring-context-support")
|
testImplementation("org.springframework:spring-context-support")
|
||||||
testImplementation("org.springframework.security:spring-security-config")
|
testImplementation("org.springframework.security:spring-security-config")
|
||||||
|
testImplementation("tools.jackson.core:jackson-databind")
|
||||||
|
|
||||||
testRuntimeOnly("com.github.ben-manes.caffeine:caffeine")
|
testRuntimeOnly("com.github.ben-manes.caffeine:caffeine")
|
||||||
testRuntimeOnly("org.springframework:spring-webflux")
|
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.aop.framework.autoproxy.AutoProxyUtils;
|
||||||
import org.springframework.beans.factory.config.BeanDefinition;
|
import org.springframework.beans.factory.config.BeanDefinition;
|
||||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
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.test.context.runner.ApplicationContextRunner;
|
||||||
import org.springframework.boot.testsupport.classpath.ClassPathExclusions;
|
import org.springframework.boot.testsupport.classpath.ClassPathExclusions;
|
||||||
|
|
||||||
|
@ -40,16 +42,18 @@ class NonAspectJAopAutoConfigurationTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void whenAspectJIsAbsentAndProxyTargetClassIsEnabledProxyCreatorBeanIsDefined() {
|
void whenAspectJIsAbsentAndProxyTargetClassIsEnabledProxyCreatorBeanIsDefined() {
|
||||||
this.contextRunner.run((context) -> {
|
this.contextRunner.withInitializer(ConditionEvaluationReportLoggingListener.forLogLevel(LogLevel.INFO))
|
||||||
BeanDefinition defaultProxyConfig = context.getBeanFactory()
|
.run((context) -> {
|
||||||
.getBeanDefinition(AutoProxyUtils.DEFAULT_PROXY_CONFIG_BEAN_NAME);
|
BeanDefinition defaultProxyConfig = context.getBeanFactory()
|
||||||
assertThat(defaultProxyConfig.getPropertyValues().get("proxyTargetClass")).isEqualTo(Boolean.TRUE);
|
.getBeanDefinition(AutoProxyUtils.DEFAULT_PROXY_CONFIG_BEAN_NAME);
|
||||||
});
|
assertThat(defaultProxyConfig.getPropertyValues().get("proxyTargetClass")).isEqualTo(Boolean.TRUE);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void whenAspectJIsAbsentAndProxyTargetClassIsDisabledNoProxyCreatorBeanIsDefined() {
|
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)
|
.run((context) -> assertThat(context).doesNotHaveBean(AutoProxyUtils.DEFAULT_PROXY_CONFIG_BEAN_NAME)
|
||||||
.doesNotHaveBean(AopConfigUtils.AUTO_PROXY_CREATOR_BEAN_NAME));
|
.doesNotHaveBean(AopConfigUtils.AUTO_PROXY_CREATOR_BEAN_NAME));
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,8 +16,8 @@
|
||||||
|
|
||||||
package org.springframework.boot.autoconfigure.condition;
|
package org.springframework.boot.autoconfigure.condition;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
import tools.jackson.databind.ObjectMapper;
|
||||||
|
|
||||||
import org.springframework.boot.autoconfigure.condition.OnBeanCondition.BeanTypeDeductionException;
|
import org.springframework.boot.autoconfigure.condition.OnBeanCondition.BeanTypeDeductionException;
|
||||||
import org.springframework.boot.testsupport.classpath.ClassPathExclusions;
|
import org.springframework.boot.testsupport.classpath.ClassPathExclusions;
|
||||||
|
|
|
@ -28,8 +28,7 @@ description = "Spring Boot Docker Compose"
|
||||||
dependencies {
|
dependencies {
|
||||||
api(project(":core:spring-boot-autoconfigure"))
|
api(project(":core:spring-boot-autoconfigure"))
|
||||||
|
|
||||||
implementation("com.fasterxml.jackson.core:jackson-databind")
|
implementation("tools.jackson.core:jackson-databind")
|
||||||
implementation("com.fasterxml.jackson.module:jackson-module-parameter-names")
|
|
||||||
|
|
||||||
dockerTestImplementation(project(":test-support:spring-boot-docker-test-support"))
|
dockerTestImplementation(project(":test-support:spring-boot-docker-test-support"))
|
||||||
|
|
||||||
|
|
|
@ -16,16 +16,14 @@
|
||||||
|
|
||||||
package org.springframework.boot.docker.compose.core;
|
package org.springframework.boot.docker.compose.core;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
import tools.jackson.databind.DeserializationFeature;
|
||||||
import com.fasterxml.jackson.databind.JavaType;
|
import tools.jackson.databind.JavaType;
|
||||||
import com.fasterxml.jackson.databind.MapperFeature;
|
import tools.jackson.databind.MapperFeature;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import tools.jackson.databind.ObjectMapper;
|
||||||
import com.fasterxml.jackson.databind.json.JsonMapper;
|
import tools.jackson.databind.json.JsonMapper;
|
||||||
import com.fasterxml.jackson.module.paramnames.ParameterNamesModule;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Support class used to handle JSON returned from the {@link DockerCli}.
|
* Support class used to handle JSON returned from the {@link DockerCli}.
|
||||||
|
@ -40,7 +38,6 @@ final class DockerJson {
|
||||||
.defaultLocale(Locale.ENGLISH)
|
.defaultLocale(Locale.ENGLISH)
|
||||||
.enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES)
|
.enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES)
|
||||||
.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
|
.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
|
||||||
.addModule(new ParameterNamesModule())
|
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
private DockerJson() {
|
private DockerJson() {
|
||||||
|
@ -74,12 +71,7 @@ final class DockerJson {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static <T> T deserialize(String json, JavaType type) {
|
private static <T> T deserialize(String json, JavaType type) {
|
||||||
try {
|
return objectMapper.readValue(json.trim(), type);
|
||||||
return objectMapper.readValue(json.trim(), type);
|
|
||||||
}
|
|
||||||
catch (IOException ex) {
|
|
||||||
throw new DockerOutputParseException(json, ex);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,6 +64,7 @@ class ConnectionNamePredicateTests {
|
||||||
assertThat(predicateOf("redis")).accepts(sourceOf("myhost.com/library/redis"));
|
assertThat(predicateOf("redis")).accepts(sourceOf("myhost.com/library/redis"));
|
||||||
assertThat(predicateOf("redis")).accepts(sourceOf("myhost.com:8080/library/redis"));
|
assertThat(predicateOf("redis")).accepts(sourceOf("myhost.com:8080/library/redis"));
|
||||||
assertThat(predicateOf("redis")).rejects(sourceOf("internalhost:8080/redis"));
|
assertThat(predicateOf("redis")).rejects(sourceOf("internalhost:8080/redis"));
|
||||||
|
assertThat(predicateOf("redis")).accepts(sourceOf("docker.my-company.com/library/redis:latest"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -27,7 +27,6 @@ dependencies {
|
||||||
api(project(":core:spring-boot"))
|
api(project(":core:spring-boot"))
|
||||||
api("org.springframework:spring-test")
|
api("org.springframework:spring-test")
|
||||||
|
|
||||||
optional("com.fasterxml.jackson.core:jackson-databind")
|
|
||||||
optional("com.google.code.gson:gson")
|
optional("com.google.code.gson:gson")
|
||||||
optional("com.jayway.jsonpath:json-path")
|
optional("com.jayway.jsonpath:json-path")
|
||||||
optional("io.projectreactor.netty:reactor-netty-http")
|
optional("io.projectreactor.netty:reactor-netty-http")
|
||||||
|
@ -44,6 +43,7 @@ dependencies {
|
||||||
optional("org.springframework:spring-web")
|
optional("org.springframework:spring-web")
|
||||||
optional("org.springframework:spring-webflux")
|
optional("org.springframework:spring-webflux")
|
||||||
optional("org.springframework.graphql:spring-graphql-test")
|
optional("org.springframework.graphql:spring-graphql-test")
|
||||||
|
optional("tools.jackson.core:jackson-databind")
|
||||||
|
|
||||||
testImplementation(project(":test-support:spring-boot-test-support"))
|
testImplementation(project(":test-support:spring-boot-test-support"))
|
||||||
testImplementation("ch.qos.logback:logback-classic")
|
testImplementation("ch.qos.logback:logback-classic")
|
||||||
|
|
|
@ -18,16 +18,29 @@ package org.springframework.boot.test.json;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
import java.io.Reader;
|
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.Configuration;
|
||||||
import com.jayway.jsonpath.spi.json.JacksonJsonProvider;
|
import com.jayway.jsonpath.InvalidJsonException;
|
||||||
import com.jayway.jsonpath.spi.mapper.JacksonMappingProvider;
|
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 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.beans.factory.ObjectFactory;
|
||||||
import org.springframework.core.ResolvableType;
|
import org.springframework.core.ResolvableType;
|
||||||
|
@ -35,14 +48,14 @@ import org.springframework.util.Assert;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* AssertJ based JSON tester backed by Jackson. Usually instantiated via
|
* 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 {
|
* public class ExampleObjectJsonTests {
|
||||||
*
|
*
|
||||||
* private JacksonTester<ExampleObject> json;
|
* private JacksonTester<ExampleObject> json;
|
||||||
*
|
*
|
||||||
* @Before
|
* @Before
|
||||||
* public void setup() {
|
* public void setup() {
|
||||||
* ObjectMapper objectMapper = new ObjectMapper();
|
* JsonMapper jsonMapper = new JsonMapper();
|
||||||
* JacksonTester.initFields(this, objectMapper);
|
* JacksonTester.initFields(this, objectMapper);
|
||||||
* }
|
* }
|
||||||
*
|
*
|
||||||
|
@ -65,42 +78,44 @@ import org.springframework.util.Assert;
|
||||||
*/
|
*/
|
||||||
public class JacksonTester<T> extends AbstractJsonMarshalTester<T> {
|
public class JacksonTester<T> extends AbstractJsonMarshalTester<T> {
|
||||||
|
|
||||||
private final ObjectMapper objectMapper;
|
private final JsonMapper jsonMapper;
|
||||||
|
|
||||||
private @Nullable Class<?> view;
|
private @Nullable Class<?> view;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new {@link JacksonTester} instance.
|
* 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) {
|
protected JacksonTester(JsonMapper jsonMapper) {
|
||||||
Assert.notNull(objectMapper, "'objectMapper' must not be null");
|
Assert.notNull(jsonMapper, "'objectMapper' must not be null");
|
||||||
this.objectMapper = objectMapper;
|
this.jsonMapper = jsonMapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new {@link JacksonTester} instance.
|
* Create a new {@link JacksonTester} instance.
|
||||||
* @param resourceLoadClass the source class used to load resources
|
* @param resourceLoadClass the source class used to load resources
|
||||||
* @param type the type under test
|
* @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) {
|
public JacksonTester(Class<?> resourceLoadClass, ResolvableType type, JsonMapper jsonMapper) {
|
||||||
this(resourceLoadClass, type, objectMapper, null);
|
this(resourceLoadClass, type, jsonMapper, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public JacksonTester(Class<?> resourceLoadClass, ResolvableType type, ObjectMapper objectMapper,
|
public JacksonTester(Class<?> resourceLoadClass, ResolvableType type, JsonMapper jsonMapper,
|
||||||
@Nullable Class<?> view) {
|
@Nullable Class<?> view) {
|
||||||
super(resourceLoadClass, type);
|
super(resourceLoadClass, type);
|
||||||
Assert.notNull(objectMapper, "'objectMapper' must not be null");
|
Assert.notNull(jsonMapper, "'jsonMapper' must not be null");
|
||||||
this.objectMapper = objectMapper;
|
this.jsonMapper = jsonMapper;
|
||||||
this.view = view;
|
this.view = view;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected JsonContent<T> getJsonContent(String json) {
|
protected JsonContent<T> getJsonContent(String json) {
|
||||||
Configuration configuration = Configuration.builder()
|
Configuration configuration = Configuration.builder()
|
||||||
.jsonProvider(new JacksonJsonProvider(this.objectMapper))
|
.jsonProvider(new JacksonJsonProvider(this.jsonMapper))
|
||||||
.mappingProvider(new JacksonMappingProvider(this.objectMapper))
|
.mappingProvider(new JacksonMappingProvider(this.jsonMapper))
|
||||||
.build();
|
.build();
|
||||||
Class<?> resourceLoadClass = getResourceLoadClass();
|
Class<?> resourceLoadClass = getResourceLoadClass();
|
||||||
Assert.state(resourceLoadClass != null, "'resourceLoadClass' must not be null");
|
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) {
|
private ObjectReader getObjectReader(ResolvableType type) {
|
||||||
ObjectReader objectReader = this.objectMapper.readerFor(getType(type));
|
ObjectReader objectReader = this.jsonMapper.readerFor(getType(type));
|
||||||
if (this.view != null) {
|
if (this.view != null) {
|
||||||
return objectReader.withView(this.view);
|
return objectReader.withView(this.view);
|
||||||
}
|
}
|
||||||
|
@ -131,7 +146,7 @@ public class JacksonTester<T> extends AbstractJsonMarshalTester<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
private ObjectWriter getObjectWriter(ResolvableType type) {
|
private ObjectWriter getObjectWriter(ResolvableType type) {
|
||||||
ObjectWriter objectWriter = this.objectMapper.writerFor(getType(type));
|
ObjectWriter objectWriter = this.jsonMapper.writerFor(getType(type));
|
||||||
if (this.view != null) {
|
if (this.view != null) {
|
||||||
return objectWriter.withView(this.view);
|
return objectWriter.withView(this.view);
|
||||||
}
|
}
|
||||||
|
@ -139,29 +154,31 @@ public class JacksonTester<T> extends AbstractJsonMarshalTester<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
private JavaType getType(ResolvableType type) {
|
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
|
* Utility method to initialize {@link JacksonTester} fields. See {@link JacksonTester
|
||||||
* class-level documentation} for example usage.
|
* class-level documentation} for example usage.
|
||||||
* @param testInstance the test instance
|
* @param testInstance the test instance
|
||||||
* @param objectMapper the object mapper
|
* @param jsonMapper the JSON mapper
|
||||||
* @see #initFields(Object, ObjectMapper)
|
* @since 4.0.0
|
||||||
|
* @see #initFields(Object, JsonMapper)
|
||||||
*/
|
*/
|
||||||
public static void initFields(Object testInstance, ObjectMapper objectMapper) {
|
public static void initFields(Object testInstance, JsonMapper jsonMapper) {
|
||||||
new JacksonFieldInitializer().initFields(testInstance, objectMapper);
|
new JacksonFieldInitializer().initFields(testInstance, jsonMapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility method to initialize {@link JacksonTester} fields. See {@link JacksonTester
|
* Utility method to initialize {@link JacksonTester} fields. See {@link JacksonTester
|
||||||
* class-level documentation} for example usage.
|
* class-level documentation} for example usage.
|
||||||
* @param testInstance the test instance
|
* @param testInstance the test instance
|
||||||
* @param objectMapperFactory a factory to create the object mapper
|
* @param jsonMapperFactory a factory to create the JSON mapper
|
||||||
* @see #initFields(Object, ObjectMapper)
|
* @since 4.0.0
|
||||||
|
* @see #initFields(Object, JsonMapper)
|
||||||
*/
|
*/
|
||||||
public static void initFields(Object testInstance, ObjectFactory<ObjectMapper> objectMapperFactory) {
|
public static void initFields(Object testInstance, ObjectFactory<JsonMapper> jsonMapperFactory) {
|
||||||
new JacksonFieldInitializer().initFields(testInstance, objectMapperFactory);
|
new JacksonFieldInitializer().initFields(testInstance, jsonMapperFactory);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -175,13 +192,13 @@ public class JacksonTester<T> extends AbstractJsonMarshalTester<T> {
|
||||||
ResolvableType type = getType();
|
ResolvableType type = getType();
|
||||||
Assert.state(resourceLoadClass != null, "'resourceLoadClass' must not be null");
|
Assert.state(resourceLoadClass != null, "'resourceLoadClass' must not be null");
|
||||||
Assert.state(type != null, "'type' 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.
|
* {@link FieldInitializer} for Jackson.
|
||||||
*/
|
*/
|
||||||
private static class JacksonFieldInitializer extends FieldInitializer<ObjectMapper> {
|
private static class JacksonFieldInitializer extends FieldInitializer<JsonMapper> {
|
||||||
|
|
||||||
protected JacksonFieldInitializer() {
|
protected JacksonFieldInitializer() {
|
||||||
super(JacksonTester.class);
|
super(JacksonTester.class);
|
||||||
|
@ -189,10 +206,115 @@ public class JacksonTester<T> extends AbstractJsonMarshalTester<T> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected AbstractJsonMarshalTester<Object> createTester(Class<?> resourceLoadClass, ResolvableType type,
|
protected AbstractJsonMarshalTester<Object> createTester(Class<?> resourceLoadClass, ResolvableType type,
|
||||||
ObjectMapper marshaller) {
|
JsonMapper marshaller) {
|
||||||
return new JacksonTester<>(resourceLoadClass, type, 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.List;
|
||||||
import java.util.Map;
|
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.assertj.core.api.InstanceOfAssertFactories;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
import tools.jackson.databind.MapperFeature;
|
||||||
|
import tools.jackson.databind.json.JsonMapper;
|
||||||
|
|
||||||
import org.springframework.core.io.ByteArrayResource;
|
import org.springframework.core.io.ByteArrayResource;
|
||||||
|
|
||||||
|
@ -55,14 +54,14 @@ class JacksonTesterIntegrationTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void typicalTest() throws Exception {
|
void typicalTest() throws Exception {
|
||||||
JacksonTester.initFields(this, new ObjectMapper());
|
JacksonTester.initFields(this, new JsonMapper());
|
||||||
String example = JSON;
|
String example = JSON;
|
||||||
assertThat(this.simpleJson.parse(example).getObject().getName()).isEqualTo("Spring");
|
assertThat(this.simpleJson.parse(example).getObject().getName()).isEqualTo("Spring");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void typicalListTest() throws Exception {
|
void typicalListTest() throws Exception {
|
||||||
JacksonTester.initFields(this, new ObjectMapper());
|
JacksonTester.initFields(this, new JsonMapper());
|
||||||
String example = "[" + JSON + "]";
|
String example = "[" + JSON + "]";
|
||||||
assertThat(this.listJson.parse(example)).asInstanceOf(InstanceOfAssertFactories.LIST).hasSize(1);
|
assertThat(this.listJson.parse(example)).asInstanceOf(InstanceOfAssertFactories.LIST).hasSize(1);
|
||||||
assertThat(this.listJson.parse(example).getObject().get(0).getName()).isEqualTo("Spring");
|
assertThat(this.listJson.parse(example).getObject().get(0).getName()).isEqualTo("Spring");
|
||||||
|
@ -70,7 +69,7 @@ class JacksonTesterIntegrationTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void typicalMapTest() throws Exception {
|
void typicalMapTest() throws Exception {
|
||||||
JacksonTester.initFields(this, new ObjectMapper());
|
JacksonTester.initFields(this, new JsonMapper());
|
||||||
Map<String, Integer> map = new LinkedHashMap<>();
|
Map<String, Integer> map = new LinkedHashMap<>();
|
||||||
map.put("a", 1);
|
map.put("a", 1);
|
||||||
map.put("b", 2);
|
map.put("b", 2);
|
||||||
|
@ -79,7 +78,7 @@ class JacksonTesterIntegrationTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void stringLiteral() throws Exception {
|
void stringLiteral() throws Exception {
|
||||||
JacksonTester.initFields(this, new ObjectMapper());
|
JacksonTester.initFields(this, new JsonMapper());
|
||||||
String stringWithSpecialCharacters = "myString";
|
String stringWithSpecialCharacters = "myString";
|
||||||
assertThat(this.stringJson.write(stringWithSpecialCharacters)).extractingJsonPathStringValue("@")
|
assertThat(this.stringJson.write(stringWithSpecialCharacters)).extractingJsonPathStringValue("@")
|
||||||
.isEqualTo(stringWithSpecialCharacters);
|
.isEqualTo(stringWithSpecialCharacters);
|
||||||
|
@ -87,7 +86,7 @@ class JacksonTesterIntegrationTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void parseSpecialCharactersTest() throws Exception {
|
void parseSpecialCharactersTest() throws Exception {
|
||||||
JacksonTester.initFields(this, new ObjectMapper());
|
JacksonTester.initFields(this, new JsonMapper());
|
||||||
// Confirms that the handling of special characters is symmetrical between
|
// Confirms that the handling of special characters is symmetrical between
|
||||||
// the serialization (through the JacksonTester) and the parsing (through
|
// the serialization (through the JacksonTester) and the parsing (through
|
||||||
// json-path). By default json-path uses SimpleJson as its parser, which has a
|
// 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 java.util.List;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
import tools.jackson.databind.json.JsonMapper;
|
||||||
|
|
||||||
import org.springframework.core.ResolvableType;
|
import org.springframework.core.ResolvableType;
|
||||||
|
|
||||||
|
@ -35,14 +35,14 @@ class JacksonTesterTests extends AbstractJsonMarshalTesterTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void initFieldsWhenTestIsNullShouldThrowException() {
|
void initFieldsWhenTestIsNullShouldThrowException() {
|
||||||
assertThatIllegalArgumentException().isThrownBy(() -> JacksonTester.initFields(null, new ObjectMapper()))
|
assertThatIllegalArgumentException().isThrownBy(() -> JacksonTester.initFields(null, new JsonMapper()))
|
||||||
.withMessageContaining("'testInstance' must not be null");
|
.withMessageContaining("'testInstance' must not be null");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void initFieldsWhenMarshallerIsNullShouldThrowException() {
|
void initFieldsWhenMarshallerIsNullShouldThrowException() {
|
||||||
assertThatIllegalArgumentException()
|
assertThatIllegalArgumentException()
|
||||||
.isThrownBy(() -> JacksonTester.initFields(new InitFieldsTestClass(), (ObjectMapper) null))
|
.isThrownBy(() -> JacksonTester.initFields(new InitFieldsTestClass(), (JsonMapper) null))
|
||||||
.withMessageContaining("'marshaller' must not be null");
|
.withMessageContaining("'marshaller' must not be null");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@ class JacksonTesterTests extends AbstractJsonMarshalTesterTests {
|
||||||
InitFieldsTestClass test = new InitFieldsTestClass();
|
InitFieldsTestClass test = new InitFieldsTestClass();
|
||||||
assertThat(test.test).isNull();
|
assertThat(test.test).isNull();
|
||||||
assertThat(test.base).isNull();
|
assertThat(test.base).isNull();
|
||||||
JacksonTester.initFields(test, new ObjectMapper());
|
JacksonTester.initFields(test, new JsonMapper());
|
||||||
assertThat(test.test).isNotNull();
|
assertThat(test.test).isNotNull();
|
||||||
assertThat(test.base).isNotNull();
|
assertThat(test.base).isNotNull();
|
||||||
assertThat(test.test.getType().resolve()).isEqualTo(List.class);
|
assertThat(test.test.getType().resolve()).isEqualTo(List.class);
|
||||||
|
@ -60,7 +60,7 @@ class JacksonTesterTests extends AbstractJsonMarshalTesterTests {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected AbstractJsonMarshalTester<Object> createTester(Class<?> resourceLoadClass, ResolvableType type) {
|
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 {
|
abstract static class InitFieldsBaseClass {
|
||||||
|
@ -68,7 +68,7 @@ class JacksonTesterTests extends AbstractJsonMarshalTesterTests {
|
||||||
public JacksonTester<ExampleObject> base;
|
public JacksonTester<ExampleObject> base;
|
||||||
|
|
||||||
public JacksonTester<ExampleObject> baseSet = new JacksonTester<>(InitFieldsBaseClass.class,
|
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<List<ExampleObject>> test;
|
||||||
|
|
||||||
public JacksonTester<ExampleObject> testSet = new JacksonTester<>(InitFieldsBaseClass.class,
|
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")
|
api("org.springframework:spring-context")
|
||||||
|
|
||||||
optional("ch.qos.logback:logback-classic")
|
optional("ch.qos.logback:logback-classic")
|
||||||
optional("com.fasterxml.jackson.core:jackson-databind")
|
|
||||||
optional("com.google.code.gson:gson")
|
optional("com.google.code.gson:gson")
|
||||||
optional("io.projectreactor:reactor-core")
|
optional("io.projectreactor:reactor-core")
|
||||||
optional("jakarta.servlet:jakarta.servlet-api")
|
optional("jakarta.servlet:jakarta.servlet-api")
|
||||||
|
@ -49,6 +48,7 @@ dependencies {
|
||||||
optional("org.springframework:spring-test")
|
optional("org.springframework:spring-test")
|
||||||
optional("org.springframework:spring-web")
|
optional("org.springframework:spring-web")
|
||||||
optional("org.yaml:snakeyaml")
|
optional("org.yaml:snakeyaml")
|
||||||
|
optional("tools.jackson.core:jackson-databind")
|
||||||
|
|
||||||
testFixturesCompileOnly(project(":test-support:spring-boot-test-support"))
|
testFixturesCompileOnly(project(":test-support:spring-boot-test-support"))
|
||||||
|
|
||||||
|
|
|
@ -19,9 +19,9 @@ package org.springframework.boot.json;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import com.fasterxml.jackson.core.type.TypeReference;
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
||||||
import org.jspecify.annotations.Nullable;
|
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}.
|
* 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}
|
* @return a {@link JsonParser}
|
||||||
*/
|
*/
|
||||||
public static JsonParser getJsonParser() {
|
public static JsonParser getJsonParser() {
|
||||||
if (ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper", null)) {
|
if (ClassUtils.isPresent("tools.jackson.databind.ObjectMapper", null)) {
|
||||||
return new JacksonJsonParser();
|
return new JacksonJsonParser();
|
||||||
}
|
}
|
||||||
if (ClassUtils.isPresent("com.google.gson.Gson", null)) {
|
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.ConfigDataLocationRuntimeHints,\
|
||||||
org.springframework.boot.context.config.ConfigDataPropertiesRuntimeHints,\
|
org.springframework.boot.context.config.ConfigDataPropertiesRuntimeHints,\
|
||||||
org.springframework.boot.env.PropertySourceRuntimeHints,\
|
org.springframework.boot.env.PropertySourceRuntimeHints,\
|
||||||
org.springframework.boot.json.JacksonRuntimeHints,\
|
|
||||||
org.springframework.boot.logging.java.JavaLoggingSystemRuntimeHints,\
|
org.springframework.boot.logging.java.JavaLoggingSystemRuntimeHints,\
|
||||||
org.springframework.boot.logging.logback.LogbackRuntimeHints,\
|
org.springframework.boot.logging.logback.LogbackRuntimeHints,\
|
||||||
org.springframework.boot.logging.structured.ElasticCommonSchemaProperties$ElasticCommonSchemaPropertiesRuntimeHints,\
|
org.springframework.boot.logging.structured.ElasticCommonSchemaProperties$ElasticCommonSchemaPropertiesRuntimeHints,\
|
||||||
|
|
|
@ -16,12 +16,10 @@
|
||||||
|
|
||||||
package org.springframework.boot.json;
|
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.Disabled;
|
||||||
import org.junit.jupiter.api.Test;
|
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.any;
|
||||||
import static org.mockito.ArgumentMatchers.eq;
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
|
@ -43,7 +41,7 @@ class JacksonJsonParserTests extends AbstractJsonParserTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
void instanceWithSpecificObjectMapper() throws IOException {
|
void instanceWithSpecificObjectMapper() {
|
||||||
ObjectMapper objectMapper = spy(new ObjectMapper());
|
ObjectMapper objectMapper = spy(new ObjectMapper());
|
||||||
new JacksonJsonParser(objectMapper).parseMap("{}");
|
new JacksonJsonParser(objectMapper).parseMap("{}");
|
||||||
then(objectMapper).should().readValue(eq("{}"), any(TypeReference.class));
|
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.HashMap;
|
||||||
import java.util.Map;
|
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.Level;
|
||||||
import org.apache.logging.log4j.core.impl.MutableLogEvent;
|
import org.apache.logging.log4j.core.impl.MutableLogEvent;
|
||||||
import org.apache.logging.log4j.message.SimpleMessage;
|
import org.apache.logging.log4j.message.SimpleMessage;
|
||||||
import org.assertj.core.api.Assertions;
|
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.junit.jupiter.MockitoExtension;
|
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.MockStructuredLoggingJsonMembersCustomizerBuilder;
|
||||||
import org.springframework.boot.logging.structured.StructuredLoggingJsonMembersCustomizer;
|
import org.springframework.boot.logging.structured.StructuredLoggingJsonMembersCustomizer;
|
||||||
|
@ -79,14 +77,8 @@ abstract class AbstractStructuredLoggingTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Map<String, Object> deserialize(String json) {
|
protected Map<String, Object> deserialize(String json) {
|
||||||
try {
|
return OBJECT_MAPPER.readValue(json, new TypeReference<>() {
|
||||||
return OBJECT_MAPPER.readValue(json, new TypeReference<>() {
|
});
|
||||||
});
|
|
||||||
}
|
|
||||||
catch (JsonProcessingException ex) {
|
|
||||||
Assertions.fail("Failed to deserialize JSON: " + json, ex);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,6 @@ import java.util.logging.Handler;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
@ -333,15 +332,16 @@ class Log4J2LoggingSystemTests extends AbstractLoggingSystemTests {
|
||||||
// No classes, only XML
|
// No classes, only XML
|
||||||
Arguments.of(Collections.emptyList(), List.of(".xml")),
|
Arguments.of(Collections.emptyList(), List.of(".xml")),
|
||||||
// Log4j Core 2
|
// Log4j Core 2
|
||||||
Arguments.of(List.of(JsonConfigurationFactory.class.getName(), ObjectMapper.class.getName()),
|
Arguments.of(List.of(JsonConfigurationFactory.class.getName(),
|
||||||
List.of(".json", ".jsn", ".xml")),
|
"com.fasterxml.jackson.databind.ObjectMapper"), List.of(".json", ".jsn", ".xml")),
|
||||||
Arguments.of(List.of(PropertiesConfigurationFactory.class.getName(),
|
Arguments.of(List.of(PropertiesConfigurationFactory.class.getName(),
|
||||||
PropertiesConfigurationBuilder.class.getName()), List.of(".properties", ".xml")),
|
PropertiesConfigurationBuilder.class.getName()), List.of(".properties", ".xml")),
|
||||||
Arguments.of(List.of(YamlConfigurationFactory.class.getName(),
|
Arguments.of(List.of(YamlConfigurationFactory.class.getName(),
|
||||||
"com.fasterxml.jackson.dataformat.yaml.YAMLMapper"), List.of(".yaml", ".yml", ".xml")),
|
"com.fasterxml.jackson.dataformat.yaml.YAMLMapper"), List.of(".yaml", ".yml", ".xml")),
|
||||||
Arguments.of(List.of(JsonConfigurationFactory.class.getName(), ObjectMapper.class.getName(),
|
Arguments.of(List.of(JsonConfigurationFactory.class.getName(),
|
||||||
PropertiesConfigurationFactory.class.getName(), PropertiesConfigurationBuilder.class.getName(),
|
"com.fasterxml.jackson.databind.ObjectMapper", PropertiesConfigurationFactory.class.getName(),
|
||||||
YamlConfigurationFactory.class.getName(), "com.fasterxml.jackson.dataformat.yaml.YAMLMapper"),
|
PropertiesConfigurationBuilder.class.getName(), YamlConfigurationFactory.class.getName(),
|
||||||
|
"com.fasterxml.jackson.dataformat.yaml.YAMLMapper"),
|
||||||
List.of(".properties", ".yaml", ".yml", ".json", ".jsn", ".xml")),
|
List.of(".properties", ".yaml", ".yml", ".json", ".jsn", ".xml")),
|
||||||
// Log4j Core 3
|
// Log4j Core 3
|
||||||
Arguments.of(List.of(JsonConfigurationFactory.class.getName(),
|
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.pattern.ThrowableProxyConverter;
|
||||||
import ch.qos.logback.classic.spi.LoggingEvent;
|
import ch.qos.logback.classic.spi.LoggingEvent;
|
||||||
import ch.qos.logback.classic.spi.ThrowableProxy;
|
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.AfterEach;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
@ -38,6 +34,8 @@ import org.mockito.junit.jupiter.MockitoExtension;
|
||||||
import org.slf4j.Marker;
|
import org.slf4j.Marker;
|
||||||
import org.slf4j.event.KeyValuePair;
|
import org.slf4j.event.KeyValuePair;
|
||||||
import org.slf4j.helpers.BasicMarkerFactory;
|
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.MockStructuredLoggingJsonMembersCustomizerBuilder;
|
||||||
import org.springframework.boot.logging.structured.StructuredLoggingJsonMembersCustomizer;
|
import org.springframework.boot.logging.structured.StructuredLoggingJsonMembersCustomizer;
|
||||||
|
@ -122,14 +120,8 @@ abstract class AbstractStructuredLoggingTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Map<String, Object> deserialize(String json) {
|
protected Map<String, Object> deserialize(String json) {
|
||||||
try {
|
return OBJECT_MAPPER.readValue(json, new TypeReference<>() {
|
||||||
return OBJECT_MAPPER.readValue(json, new TypeReference<>() {
|
});
|
||||||
});
|
|
||||||
}
|
|
||||||
catch (JsonProcessingException ex) {
|
|
||||||
Assertions.fail("Failed to deserialize JSON: " + json, ex);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,9 +18,8 @@ package org.springframework.boot.web.error;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
import tools.jackson.databind.ObjectMapper;
|
||||||
|
|
||||||
import org.springframework.context.MessageSourceResolvable;
|
import org.springframework.context.MessageSourceResolvable;
|
||||||
import org.springframework.context.support.DefaultMessageSourceResolvable;
|
import org.springframework.context.support.DefaultMessageSourceResolvable;
|
||||||
|
@ -46,7 +45,7 @@ class ErrorTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void errorCauseDoesNotAppearInJson() throws JsonProcessingException {
|
void errorCauseDoesNotAppearInJson() {
|
||||||
String json = new ObjectMapper()
|
String json = new ObjectMapper()
|
||||||
.writeValueAsString(Error.wrapIfNecessary(List.of(new CustomMessageSourceResolvable("code"))));
|
.writeValueAsString(Error.wrapIfNecessary(List.of(new CustomMessageSourceResolvable("code"))));
|
||||||
assertThat(json).doesNotContain("some detail");
|
assertThat(json).doesNotContain("some detail");
|
||||||
|
|
|
@ -16,15 +16,14 @@
|
||||||
|
|
||||||
package org.springframework.boot.actuate.docs;
|
package org.springframework.boot.actuate.docs;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import tools.jackson.databind.SerializationFeature;
|
||||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
import tools.jackson.databind.json.JsonMapper;
|
||||||
|
|
||||||
import org.springframework.beans.BeansException;
|
import org.springframework.beans.BeansException;
|
||||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
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.jackson.JacksonEndpointAutoConfiguration;
|
||||||
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;
|
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;
|
||||||
import org.springframework.boot.actuate.docs.AbstractEndpointDocumentationTests.BaseDocumentationConfiguration;
|
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.ImportAutoConfiguration;
|
||||||
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
|
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
|
||||||
import org.springframework.boot.http.converter.autoconfigure.HttpMessageConvertersAutoConfiguration;
|
import org.springframework.boot.http.converter.autoconfigure.HttpMessageConvertersAutoConfiguration;
|
||||||
|
@ -77,29 +76,24 @@ public abstract class AbstractEndpointDocumentationTests {
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
protected <T> OperationPreprocessor limit(Predicate<T> filter, String... keys) {
|
protected <T> OperationPreprocessor limit(Predicate<T> filter, String... keys) {
|
||||||
return new ContentModifyingOperationPreprocessor((content, mediaType) -> {
|
return new ContentModifyingOperationPreprocessor((content, mediaType) -> {
|
||||||
ObjectMapper objectMapper = new ObjectMapper().enable(SerializationFeature.INDENT_OUTPUT);
|
JsonMapper objectMapper = JsonMapper.builder().enable(SerializationFeature.INDENT_OUTPUT).build();
|
||||||
try {
|
Map<String, Object> payload = objectMapper.readValue(content, Map.class);
|
||||||
Map<String, Object> payload = objectMapper.readValue(content, Map.class);
|
Object target = payload;
|
||||||
Object target = payload;
|
Map<Object, Object> parent = null;
|
||||||
Map<Object, Object> parent = null;
|
for (String key : keys) {
|
||||||
for (String key : keys) {
|
if (!(target instanceof Map)) {
|
||||||
if (!(target instanceof Map)) {
|
throw new IllegalStateException();
|
||||||
throw new IllegalStateException();
|
|
||||||
}
|
|
||||||
parent = (Map<Object, Object>) target;
|
|
||||||
target = parent.get(key);
|
|
||||||
}
|
}
|
||||||
if (target instanceof Map) {
|
parent = (Map<Object, Object>) target;
|
||||||
parent.put(keys[keys.length - 1], select((Map<String, Object>) target, filter));
|
target = parent.get(key);
|
||||||
}
|
|
||||||
else {
|
|
||||||
parent.put(keys[keys.length - 1], select((List<Object>) target, filter));
|
|
||||||
}
|
|
||||||
return objectMapper.writeValueAsBytes(payload);
|
|
||||||
}
|
}
|
||||||
catch (IOException ex) {
|
if (target instanceof Map) {
|
||||||
throw new IllegalStateException(ex);
|
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 {
|
static class BaseDocumentationConfiguration {
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
static BeanPostProcessor endpointObjectMapperBeanPostProcessor() {
|
static BeanPostProcessor endpointJsonMapperBeanPostProcessor() {
|
||||||
return new BeanPostProcessor() {
|
return new BeanPostProcessor() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
|
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
|
||||||
if (bean instanceof EndpointObjectMapper) {
|
if (bean instanceof EndpointJsonMapper) {
|
||||||
return (EndpointObjectMapper) () -> ((EndpointObjectMapper) bean).get()
|
return (EndpointJsonMapper) () -> ((EndpointJsonMapper) bean).get()
|
||||||
.enable(SerializationFeature.INDENT_OUTPUT);
|
.rebuild()
|
||||||
|
.enable(SerializationFeature.INDENT_OUTPUT)
|
||||||
|
.build();
|
||||||
}
|
}
|
||||||
return bean;
|
return bean;
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
|
|
||||||
package org.springframework.boot.actuate.docs.env;
|
package org.springframework.boot.actuate.docs.env;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -24,9 +23,10 @@ import java.util.Set;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
||||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
|
||||||
import org.junit.jupiter.api.Test;
|
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.docs.MockMvcEndpointDocumentationTests;
|
||||||
import org.springframework.boot.actuate.endpoint.Show;
|
import org.springframework.boot.actuate.endpoint.Show;
|
||||||
|
@ -116,24 +116,19 @@ class EnvironmentEndpointDocumentationTests extends MockMvcEndpointDocumentation
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private byte[] filterProperties(byte[] content, MediaType mediaType) {
|
private byte[] filterProperties(byte[] content, MediaType mediaType) {
|
||||||
ObjectMapper objectMapper = new ObjectMapper().enable(SerializationFeature.INDENT_OUTPUT);
|
ObjectMapper objectMapper = JsonMapper.builder().enable(SerializationFeature.INDENT_OUTPUT).build();
|
||||||
try {
|
Map<String, Object> payload = objectMapper.readValue(content, Map.class);
|
||||||
Map<String, Object> payload = objectMapper.readValue(content, Map.class);
|
List<Map<String, Object>> propertySources = (List<Map<String, Object>>) payload.get("propertySources");
|
||||||
List<Map<String, Object>> propertySources = (List<Map<String, Object>>) payload.get("propertySources");
|
for (Map<String, Object> propertySource : propertySources) {
|
||||||
for (Map<String, Object> propertySource : propertySources) {
|
Map<String, String> properties = (Map<String, String>) propertySource.get("properties");
|
||||||
Map<String, String> properties = (Map<String, String>) propertySource.get("properties");
|
Set<String> filteredKeys = properties.keySet()
|
||||||
Set<String> filteredKeys = properties.keySet()
|
.stream()
|
||||||
.stream()
|
.filter(this::retainKey)
|
||||||
.filter(this::retainKey)
|
.limit(3)
|
||||||
.limit(3)
|
.collect(Collectors.toSet());
|
||||||
.collect(Collectors.toSet());
|
properties.keySet().retainAll(filteredKeys);
|
||||||
properties.keySet().retainAll(filteredKeys);
|
|
||||||
}
|
|
||||||
return objectMapper.writeValueAsBytes(payload);
|
|
||||||
}
|
|
||||||
catch (IOException ex) {
|
|
||||||
throw new IllegalStateException(ex);
|
|
||||||
}
|
}
|
||||||
|
return objectMapper.writeValueAsBytes(payload);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean retainKey(String key) {
|
private boolean retainKey(String key) {
|
||||||
|
|
|
@ -34,7 +34,6 @@ import org.springframework.restdocs.payload.FieldDescriptor;
|
||||||
import org.springframework.session.FindByIndexNameSessionRepository;
|
import org.springframework.session.FindByIndexNameSessionRepository;
|
||||||
import org.springframework.session.MapSession;
|
import org.springframework.session.MapSession;
|
||||||
import org.springframework.session.Session;
|
import org.springframework.session.Session;
|
||||||
import org.springframework.test.context.TestPropertySource;
|
|
||||||
import org.springframework.test.context.bean.override.mockito.MockitoBean;
|
import org.springframework.test.context.bean.override.mockito.MockitoBean;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
@ -51,7 +50,6 @@ import static org.springframework.restdocs.request.RequestDocumentation.queryPar
|
||||||
*
|
*
|
||||||
* @author Andy Wilkinson
|
* @author Andy Wilkinson
|
||||||
*/
|
*/
|
||||||
@TestPropertySource(properties = "spring.jackson.serialization.write-dates-as-timestamps=false")
|
|
||||||
class SessionsEndpointDocumentationTests extends MockMvcEndpointDocumentationTests {
|
class SessionsEndpointDocumentationTests extends MockMvcEndpointDocumentationTests {
|
||||||
|
|
||||||
private static final Session sessionOne = createSession(Instant.now().minusSeconds(60 * 60 * 12),
|
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.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: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-jsonmapper[#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.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-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-responsebody-rendering[#howto.spring-mvc.customize-responsebody-rendering]
|
||||||
* xref:how-to:spring-mvc.adoc#howto.spring-mvc.customize-view-resolvers[#howto-customize-view-resolvers]
|
* 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]]
|
[[howto.spring-mvc.write-json-rest-service]]
|
||||||
== Write a 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[]
|
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.
|
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]
|
[source,xml]
|
||||||
----
|
----
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.fasterxml.jackson.dataformat</groupId>
|
<groupId>tools.jackson.dataformat</groupId>
|
||||||
<artifactId>jackson-dataformat-xml</artifactId>
|
<artifactId>jackson-dataformat-xml</artifactId>
|
||||||
</dependency>
|
</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]]
|
[[howto.spring-mvc.customize-jackson-jsonmapper]]
|
||||||
== Customize the Jackson ObjectMapper
|
== 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.
|
You can configure the javadoc:tools.jackson.databind.JsonMapper[] by using the environment.
|
||||||
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.
|
|
||||||
Jackson provides an extensive suite of on/off features that can be used to configure various aspects of its processing.
|
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:
|
These features are described in several enums (in Jackson) that map onto properties in the environment:
|
||||||
|
|
||||||
|===
|
|===
|
||||||
| Enum | Property | Values
|
| Enum | Property | Values
|
||||||
|
|
||||||
| javadoc:com.fasterxml.jackson.databind.cfg.EnumFeature[]
|
| javadoc:tools.jackson.databind.cfg.EnumFeature[]
|
||||||
| `spring.jackson.datatype.enum.<feature_name>`
|
| `spring.jackson.datatype.enum.<feature_name>`
|
||||||
| `true`, `false`
|
| `true`, `false`
|
||||||
|
|
||||||
| javadoc:com.fasterxml.jackson.databind.cfg.JsonNodeFeature[]
|
| javadoc:tools.jackson.databind.cfg.JsonNodeFeature[]
|
||||||
| `spring.jackson.datatype.json-node.<feature_name>`
|
| `spring.jackson.datatype.json-node.<feature_name>`
|
||||||
| `true`, `false`
|
| `true`, `false`
|
||||||
|
|
||||||
| javadoc:com.fasterxml.jackson.databind.DeserializationFeature[]
|
| javadoc:tools.jackson.databind.DeserializationFeature[]
|
||||||
| `spring.jackson.deserialization.<feature_name>`
|
| `spring.jackson.deserialization.<feature_name>`
|
||||||
| `true`, `false`
|
| `true`, `false`
|
||||||
|
|
||||||
| javadoc:com.fasterxml.jackson.core.JsonGenerator$Feature[]
|
| javadoc:tools.jackson.databind.MapperFeature[]
|
||||||
| `spring.jackson.generator.<feature_name>`
|
|
||||||
| `true`, `false`
|
|
||||||
|
|
||||||
| javadoc:com.fasterxml.jackson.databind.MapperFeature[]
|
|
||||||
| `spring.jackson.mapper.<feature_name>`
|
| `spring.jackson.mapper.<feature_name>`
|
||||||
| `true`, `false`
|
| `true`, `false`
|
||||||
|
|
||||||
| javadoc:com.fasterxml.jackson.core.JsonParser$Feature[]
|
| javadoc:tools.jackson.core.JsonReadFeature[]
|
||||||
| `spring.jackson.parser.<feature_name>`
|
| `spring.jackson.read.<feature_name>`
|
||||||
| `true`, `false`
|
| `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>`
|
| `spring.jackson.serialization.<feature_name>`
|
||||||
| `true`, `false`
|
| `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`.
|
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`.
|
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.
|
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.
|
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].
|
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.
|
||||||
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.
|
|
||||||
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).
|
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.
|
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]).
|
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.
|
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.
|
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[]).
|
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:
|
Spring Boot provides integration with three JSON mapping libraries:
|
||||||
|
|
||||||
- Gson
|
- Gson
|
||||||
- Jackson
|
- Jackson 3
|
||||||
- JSON-B
|
- JSON-B
|
||||||
|
|
||||||
Jackson is the preferred and default library.
|
Jackson is the preferred and default library.
|
||||||
|
@ -15,18 +15,18 @@ Jackson is the preferred and default library.
|
||||||
== Jackson
|
== Jackson
|
||||||
|
|
||||||
Auto-configuration for Jackson is provided and Jackson is part of `spring-boot-starter-json`.
|
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.
|
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-objectmapper[customizing the configuration of the javadoc:com.fasterxml.jackson.databind.ObjectMapper[]].
|
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]]
|
[[features.json.jackson.custom-serializers-and-deserializers]]
|
||||||
=== 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.
|
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:
|
You can also use it on classes that contain serializers/deserializers as inner classes, as shown in the following example:
|
||||||
|
|
||||||
include-code::MyJsonComponent[]
|
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.
|
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.
|
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.
|
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.JsonObjectSerializer[] and javadoc:org.springframework.boot.jackson.JsonObjectDeserializer[] in the API documentation for details.
|
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[]
|
include-code::object/MyJsonComponent[]
|
||||||
|
|
||||||
|
@ -47,7 +47,7 @@ include-code::object/MyJsonComponent[]
|
||||||
=== Mixins
|
=== Mixins
|
||||||
|
|
||||||
Jackson has support for mixins that can be used to mix additional annotations into those already declared on a target class.
|
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[].
|
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.
|
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:
|
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`
|
* `Gson`
|
||||||
* `Jsonb`
|
* `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: 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.
|
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: 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.
|
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
|
= 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.
|
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 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: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 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].
|
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.
|
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`.
|
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;
|
package org.springframework.boot.docs.features.json.jackson.customserializersanddeserializers;
|
||||||
|
|
||||||
import java.io.IOException;
|
import tools.jackson.core.JsonGenerator;
|
||||||
|
import tools.jackson.core.JsonParser;
|
||||||
import com.fasterxml.jackson.core.JsonGenerator;
|
import tools.jackson.databind.DeserializationContext;
|
||||||
import com.fasterxml.jackson.core.JsonParser;
|
import tools.jackson.databind.JsonNode;
|
||||||
import com.fasterxml.jackson.core.ObjectCodec;
|
import tools.jackson.databind.SerializationContext;
|
||||||
import com.fasterxml.jackson.databind.DeserializationContext;
|
import tools.jackson.databind.ValueDeserializer;
|
||||||
import com.fasterxml.jackson.databind.JsonDeserializer;
|
import tools.jackson.databind.ValueSerializer;
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
|
||||||
import com.fasterxml.jackson.databind.JsonSerializer;
|
|
||||||
import com.fasterxml.jackson.databind.SerializerProvider;
|
|
||||||
|
|
||||||
import org.springframework.boot.jackson.JsonComponent;
|
import org.springframework.boot.jackson.JsonComponent;
|
||||||
|
|
||||||
@JsonComponent
|
@JsonComponent
|
||||||
public class MyJsonComponent {
|
public class MyJsonComponent {
|
||||||
|
|
||||||
public static class Serializer extends JsonSerializer<MyObject> {
|
public static class Serializer extends ValueSerializer<MyObject> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void serialize(MyObject value, JsonGenerator jgen, SerializerProvider serializers) throws IOException {
|
public void serialize(MyObject value, JsonGenerator jgen, SerializationContext context) {
|
||||||
jgen.writeStartObject();
|
jgen.writeStartObject();
|
||||||
jgen.writeStringField("name", value.getName());
|
jgen.writeStringProperty("name", value.getName());
|
||||||
jgen.writeNumberField("age", value.getAge());
|
jgen.writeNumberProperty("age", value.getAge());
|
||||||
jgen.writeEndObject();
|
jgen.writeEndObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Deserializer extends JsonDeserializer<MyObject> {
|
public static class Deserializer extends ValueDeserializer<MyObject> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MyObject deserialize(JsonParser jsonParser, DeserializationContext ctxt) throws IOException {
|
public MyObject deserialize(JsonParser jsonParser, DeserializationContext ctxt) {
|
||||||
ObjectCodec codec = jsonParser.getCodec();
|
JsonNode tree = jsonParser.readValueAsTree();
|
||||||
JsonNode tree = codec.readTree(jsonParser);
|
String name = tree.get("name").stringValue();
|
||||||
String name = tree.get("name").textValue();
|
|
||||||
int age = tree.get("age").intValue();
|
int age = tree.get("age").intValue();
|
||||||
return new MyObject(name, age);
|
return new MyObject(name, age);
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,38 +16,33 @@
|
||||||
|
|
||||||
package org.springframework.boot.docs.features.json.jackson.customserializersanddeserializers.object;
|
package org.springframework.boot.docs.features.json.jackson.customserializersanddeserializers.object;
|
||||||
|
|
||||||
import java.io.IOException;
|
import tools.jackson.core.JsonGenerator;
|
||||||
|
import tools.jackson.core.JsonParser;
|
||||||
import com.fasterxml.jackson.core.JsonGenerator;
|
import tools.jackson.databind.DeserializationContext;
|
||||||
import com.fasterxml.jackson.core.JsonParser;
|
import tools.jackson.databind.JsonNode;
|
||||||
import com.fasterxml.jackson.core.ObjectCodec;
|
import tools.jackson.databind.SerializationContext;
|
||||||
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.JsonComponent;
|
||||||
import org.springframework.boot.jackson.JsonObjectDeserializer;
|
import org.springframework.boot.jackson.ObjectValueDeserializer;
|
||||||
import org.springframework.boot.jackson.JsonObjectSerializer;
|
import org.springframework.boot.jackson.ObjectValueSerializer;
|
||||||
|
|
||||||
@JsonComponent
|
@JsonComponent
|
||||||
public class MyJsonComponent {
|
public class MyJsonComponent {
|
||||||
|
|
||||||
public static class Serializer extends JsonObjectSerializer<MyObject> {
|
public static class Serializer extends ObjectValueSerializer<MyObject> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void serializeObject(MyObject value, JsonGenerator jgen, SerializerProvider provider)
|
protected void serializeObject(MyObject value, JsonGenerator jgen, SerializationContext context) {
|
||||||
throws IOException {
|
jgen.writeStringProperty("name", value.getName());
|
||||||
jgen.writeStringField("name", value.getName());
|
jgen.writeNumberProperty("age", value.getAge());
|
||||||
jgen.writeNumberField("age", value.getAge());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Deserializer extends JsonObjectDeserializer<MyObject> {
|
public static class Deserializer extends ObjectValueDeserializer<MyObject> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected MyObject deserializeObject(JsonParser jsonParser, DeserializationContext context, ObjectCodec codec,
|
protected MyObject deserializeObject(JsonParser jsonParser, DeserializationContext context, JsonNode tree) {
|
||||||
JsonNode tree) throws IOException {
|
|
||||||
String name = nullSafeValue(tree.get("name"), String.class);
|
String name = nullSafeValue(tree.get("name"), String.class);
|
||||||
int age = nullSafeValue(tree.get("age"), Integer.class);
|
int age = nullSafeValue(tree.get("age"), Integer.class);
|
||||||
return new MyObject(name, age);
|
return new MyObject(name, age);
|
||||||
|
|
|
@ -16,36 +16,32 @@
|
||||||
|
|
||||||
package org.springframework.boot.docs.features.json.jackson.customserializersanddeserializers
|
package org.springframework.boot.docs.features.json.jackson.customserializersanddeserializers
|
||||||
|
|
||||||
import com.fasterxml.jackson.core.JsonGenerator
|
import tools.jackson.core.JsonGenerator
|
||||||
import com.fasterxml.jackson.core.JsonParser
|
import tools.jackson.core.JsonParser
|
||||||
import com.fasterxml.jackson.core.JsonProcessingException
|
import tools.jackson.databind.DeserializationContext
|
||||||
import com.fasterxml.jackson.databind.DeserializationContext
|
import tools.jackson.databind.JsonNode
|
||||||
import com.fasterxml.jackson.databind.JsonDeserializer
|
import tools.jackson.databind.SerializationContext
|
||||||
import com.fasterxml.jackson.databind.JsonNode
|
import tools.jackson.databind.ValueDeserializer
|
||||||
import com.fasterxml.jackson.databind.JsonSerializer
|
import tools.jackson.databind.ValueSerializer
|
||||||
import com.fasterxml.jackson.databind.SerializerProvider
|
|
||||||
import org.springframework.boot.jackson.JsonComponent
|
import org.springframework.boot.jackson.JsonComponent
|
||||||
import java.io.IOException
|
|
||||||
|
|
||||||
@JsonComponent
|
@JsonComponent
|
||||||
class MyJsonComponent {
|
class MyJsonComponent {
|
||||||
|
|
||||||
class Serializer : JsonSerializer<MyObject>() {
|
class Serializer : ValueSerializer<MyObject>() {
|
||||||
@Throws(IOException::class)
|
override fun serialize(value: MyObject, jgen: JsonGenerator, serializers: SerializationContext) {
|
||||||
override fun serialize(value: MyObject, jgen: JsonGenerator, serializers: SerializerProvider) {
|
|
||||||
jgen.writeStartObject()
|
jgen.writeStartObject()
|
||||||
jgen.writeStringField("name", value.name)
|
jgen.writeStringProperty("name", value.name)
|
||||||
jgen.writeNumberField("age", value.age)
|
jgen.writeNumberProperty("age", value.age)
|
||||||
jgen.writeEndObject()
|
jgen.writeEndObject()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Deserializer : JsonDeserializer<MyObject>() {
|
class Deserializer : ValueDeserializer<MyObject>() {
|
||||||
@Throws(IOException::class, JsonProcessingException::class)
|
|
||||||
override fun deserialize(jsonParser: JsonParser, ctxt: DeserializationContext): MyObject {
|
override fun deserialize(jsonParser: JsonParser, ctxt: DeserializationContext): MyObject {
|
||||||
val codec = jsonParser.codec
|
val tree = jsonParser.readValueAsTree<JsonNode>()
|
||||||
val tree = codec.readTree<JsonNode>(jsonParser)
|
val name = tree["name"].stringValue()
|
||||||
val name = tree["name"].textValue()
|
|
||||||
val age = tree["age"].intValue()
|
val age = tree["age"].intValue()
|
||||||
return MyObject(name, age)
|
return MyObject(name, age)
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,32 +16,29 @@
|
||||||
|
|
||||||
package org.springframework.boot.docs.features.json.jackson.customserializersanddeserializers.`object`
|
package org.springframework.boot.docs.features.json.jackson.customserializersanddeserializers.`object`
|
||||||
|
|
||||||
import com.fasterxml.jackson.core.JsonGenerator
|
import tools.jackson.core.JsonGenerator
|
||||||
import com.fasterxml.jackson.core.JsonParser
|
import tools.jackson.core.JsonParser
|
||||||
import com.fasterxml.jackson.core.ObjectCodec
|
import tools.jackson.databind.DeserializationContext
|
||||||
import com.fasterxml.jackson.databind.DeserializationContext
|
import tools.jackson.databind.JsonNode
|
||||||
import com.fasterxml.jackson.databind.JsonNode
|
import tools.jackson.databind.SerializationContext
|
||||||
import com.fasterxml.jackson.databind.SerializerProvider
|
|
||||||
import org.springframework.boot.jackson.JsonComponent
|
import org.springframework.boot.jackson.JsonComponent;
|
||||||
import org.springframework.boot.jackson.JsonObjectDeserializer
|
import org.springframework.boot.jackson.ObjectValueDeserializer
|
||||||
import org.springframework.boot.jackson.JsonObjectSerializer
|
import org.springframework.boot.jackson.ObjectValueSerializer
|
||||||
import java.io.IOException
|
|
||||||
|
|
||||||
@JsonComponent
|
@JsonComponent
|
||||||
class MyJsonComponent {
|
class MyJsonComponent {
|
||||||
|
|
||||||
class Serializer : JsonObjectSerializer<MyObject>() {
|
class Serializer : ObjectValueSerializer<MyObject>() {
|
||||||
@Throws(IOException::class)
|
override fun serializeObject(value: MyObject, jgen: JsonGenerator, context: SerializationContext) {
|
||||||
override fun serializeObject(value: MyObject, jgen: JsonGenerator, provider: SerializerProvider) {
|
jgen.writeStringProperty("name", value.name)
|
||||||
jgen.writeStringField("name", value.name)
|
jgen.writeNumberProperty("age", value.age)
|
||||||
jgen.writeNumberField("age", value.age)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Deserializer : JsonObjectDeserializer<MyObject>() {
|
class Deserializer : ObjectValueDeserializer<MyObject>() {
|
||||||
@Throws(IOException::class)
|
|
||||||
override fun deserializeObject(jsonParser: JsonParser, context: DeserializationContext,
|
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 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")
|
val age = nullSafeValue(tree["age"], Int::class.java) ?: throw IllegalStateException("age is null")
|
||||||
return MyObject(name, age)
|
return MyObject(name, age)
|
||||||
|
|
|
@ -11,7 +11,8 @@ checkstyleToolVersion=10.12.4
|
||||||
commonsCodecVersion=1.19.0
|
commonsCodecVersion=1.19.0
|
||||||
graalVersion=22.3
|
graalVersion=22.3
|
||||||
hamcrestVersion=3.0
|
hamcrestVersion=3.0
|
||||||
jacksonVersion=2.20.0-rc1
|
jackson2Version=2.20.0
|
||||||
|
jacksonVersion=3.0.0-rc8
|
||||||
javaFormatVersion=0.0.47
|
javaFormatVersion=0.0.47
|
||||||
junitJupiterVersion=5.13.4
|
junitJupiterVersion=5.13.4
|
||||||
kotlinVersion=2.2.0
|
kotlinVersion=2.2.0
|
||||||
|
|
|
@ -43,4 +43,5 @@ dependencies {
|
||||||
testImplementation("net.minidev:json-smart")
|
testImplementation("net.minidev:json-smart")
|
||||||
testImplementation("org.springframework.security:spring-security-web")
|
testImplementation("org.springframework.security:spring-security-web")
|
||||||
testRuntimeOnly("ch.qos.logback:logback-classic")
|
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;
|
package org.springframework.boot.actuate.metrics;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
||||||
import io.micrometer.core.instrument.MeterRegistry;
|
import io.micrometer.core.instrument.MeterRegistry;
|
||||||
import io.micrometer.core.instrument.MockClock;
|
import io.micrometer.core.instrument.MockClock;
|
||||||
import io.micrometer.core.instrument.binder.jvm.JvmMemoryMetrics;
|
import io.micrometer.core.instrument.binder.jvm.JvmMemoryMetrics;
|
||||||
import io.micrometer.core.instrument.simple.SimpleConfig;
|
import io.micrometer.core.instrument.simple.SimpleConfig;
|
||||||
import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
|
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.actuate.endpoint.web.test.WebEndpointTest;
|
||||||
import org.springframework.boot.micrometer.metrics.actuate.endpoint.MetricsEndpoint;
|
import org.springframework.boot.micrometer.metrics.actuate.endpoint.MetricsEndpoint;
|
||||||
|
@ -49,7 +48,7 @@ class MetricsEndpointWebIntegrationTests {
|
||||||
|
|
||||||
@WebEndpointTest
|
@WebEndpointTest
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
void listNames(WebTestClient client) throws IOException {
|
void listNames(WebTestClient client) {
|
||||||
String responseBody = client.get()
|
String responseBody = client.get()
|
||||||
.uri("/actuator/metrics")
|
.uri("/actuator/metrics")
|
||||||
.exchange()
|
.exchange()
|
||||||
|
|
|
@ -16,6 +16,12 @@
|
||||||
|
|
||||||
package org.springframework.boot.activemq.autoconfigure;
|
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 jakarta.jms.ConnectionFactory;
|
||||||
import org.apache.activemq.ActiveMQConnectionFactory;
|
import org.apache.activemq.ActiveMQConnectionFactory;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
@ -47,6 +53,14 @@ class ActiveMQAutoConfigurationTests {
|
||||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||||
.withConfiguration(AutoConfigurations.of(ActiveMQAutoConfiguration.class, JmsAutoConfiguration.class));
|
.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
|
@Test
|
||||||
void brokerIsEmbeddedByDefault() {
|
void brokerIsEmbeddedByDefault() {
|
||||||
this.contextRunner.withUserConfiguration(EmptyConfiguration.class).run((context) -> {
|
this.contextRunner.withUserConfiguration(EmptyConfiguration.class).run((context) -> {
|
||||||
|
|
|
@ -29,13 +29,11 @@ dependencies {
|
||||||
api(project(":core:spring-boot-autoconfigure"))
|
api(project(":core:spring-boot-autoconfigure"))
|
||||||
api(project(":module:spring-boot-actuator"))
|
api(project(":module:spring-boot-actuator"))
|
||||||
|
|
||||||
implementation("com.fasterxml.jackson.core:jackson-databind")
|
implementation("tools.jackson.core:jackson-databind")
|
||||||
implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310")
|
|
||||||
|
|
||||||
optional(project(":module:spring-boot-health"))
|
optional(project(":module:spring-boot-health"))
|
||||||
optional(project(":module:spring-boot-web-server"))
|
optional(project(":module:spring-boot-web-server"))
|
||||||
|
|
||||||
optional("com.fasterxml.jackson.core:jackson-databind")
|
|
||||||
optional("io.micrometer:micrometer-core")
|
optional("io.micrometer:micrometer-core")
|
||||||
optional("io.projectreactor:reactor-core")
|
optional("io.projectreactor:reactor-core")
|
||||||
optional("jakarta.servlet:jakarta.servlet-api")
|
optional("jakarta.servlet:jakarta.servlet-api")
|
||||||
|
|
|
@ -20,17 +20,15 @@ import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonInclude.Include;
|
import com.fasterxml.jackson.annotation.JsonInclude.Include;
|
||||||
import com.fasterxml.jackson.databind.MapperFeature;
|
import tools.jackson.databind.ObjectMapper;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import tools.jackson.databind.json.JsonMapper;
|
||||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
|
||||||
|
|
||||||
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.AutoConfiguration;
|
||||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
|
|
||||||
import org.springframework.util.ClassUtils;
|
import org.springframework.util.ClassUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -40,30 +38,27 @@ import org.springframework.util.ClassUtils;
|
||||||
* @since 3.0.0
|
* @since 3.0.0
|
||||||
*/
|
*/
|
||||||
@AutoConfiguration
|
@AutoConfiguration
|
||||||
@SuppressWarnings("removal")
|
|
||||||
public final class JacksonEndpointAutoConfiguration {
|
public final class JacksonEndpointAutoConfiguration {
|
||||||
|
|
||||||
private static final String CONTRIBUTED_HEALTH = "org.springframework.boot.health.contributor.ContributedHealth";
|
private static final String CONTRIBUTED_HEALTH = "org.springframework.boot.health.contributor.ContributedHealth";
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@ConditionalOnBooleanProperty(name = "management.endpoints.jackson.isolated-object-mapper", matchIfMissing = true)
|
@ConditionalOnBooleanProperty(name = "management.endpoints.jackson.isolated-object-mapper", matchIfMissing = true)
|
||||||
@ConditionalOnClass({ ObjectMapper.class, Jackson2ObjectMapperBuilder.class })
|
@ConditionalOnClass(ObjectMapper.class)
|
||||||
EndpointObjectMapper endpointObjectMapper() {
|
EndpointJsonMapper endpointJsonMapper() {
|
||||||
ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.json()
|
JsonMapper jsonMapper = JsonMapper.builder()
|
||||||
.featuresToEnable(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY)
|
.changeDefaultPropertyInclusion(
|
||||||
.featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS,
|
(value) -> value.withValueInclusion(Include.NON_NULL).withContentInclusion(Include.NON_NULL))
|
||||||
SerializationFeature.WRITE_DURATIONS_AS_TIMESTAMPS)
|
|
||||||
.serializationInclusion(Include.NON_NULL)
|
|
||||||
.build();
|
.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)) {
|
if (ClassUtils.isPresent(CONTRIBUTED_HEALTH, null)) {
|
||||||
supportedTypes.add(ClassUtils.resolveClassName(CONTRIBUTED_HEALTH, null));
|
supportedTypes.add(ClassUtils.resolveClassName(CONTRIBUTED_HEALTH, null));
|
||||||
}
|
}
|
||||||
return new EndpointObjectMapper() {
|
return new EndpointJsonMapper() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ObjectMapper get() {
|
public JsonMapper get() {
|
||||||
return objectMapper;
|
return jsonMapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -18,7 +18,7 @@ package org.springframework.boot.actuate.autoconfigure.endpoint.jmx;
|
||||||
|
|
||||||
import javax.management.MBeanServer;
|
import javax.management.MBeanServer;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import tools.jackson.databind.ObjectMapper;
|
||||||
|
|
||||||
import org.springframework.beans.factory.ObjectProvider;
|
import org.springframework.beans.factory.ObjectProvider;
|
||||||
import org.springframework.boot.LazyInitializationExcludeFilter;
|
import org.springframework.boot.LazyInitializationExcludeFilter;
|
||||||
|
|
|
@ -22,10 +22,10 @@ import java.time.format.DateTimeFormatter;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
||||||
import org.junit.jupiter.api.Test;
|
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.autoconfigure.AutoConfigurations;
|
||||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
|
@ -44,49 +44,49 @@ class JacksonEndpointAutoConfigurationTests {
|
||||||
.withConfiguration(AutoConfigurations.of(JacksonEndpointAutoConfiguration.class));
|
.withConfiguration(AutoConfigurations.of(JacksonEndpointAutoConfiguration.class));
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void endpointObjectMapperWhenNoProperty() {
|
void endpointJsonMapperWhenNoProperty() {
|
||||||
this.runner.run((context) -> assertThat(context).hasSingleBean(EndpointObjectMapper.class));
|
this.runner.run((context) -> assertThat(context).hasSingleBean(EndpointJsonMapper.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void endpointObjectMapperWhenPropertyTrue() {
|
void endpointJsonMapperWhenPropertyTrue() {
|
||||||
this.runner.withPropertyValues("management.endpoints.jackson.isolated-object-mapper=true")
|
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
|
@Test
|
||||||
void endpointObjectMapperWhenPropertyFalse() {
|
void endpointJsonMapperWhenPropertyFalse() {
|
||||||
this.runner.withPropertyValues("management.endpoints.jackson.isolated-object-mapper=false")
|
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
|
@Test
|
||||||
void endpointObjectMapperDoesNotSerializeDatesAsTimestamps() {
|
void endpointJsonMapperDoesNotSerializeDatesAsTimestamps() {
|
||||||
this.runner.run((context) -> {
|
this.runner.run((context) -> {
|
||||||
ObjectMapper objectMapper = context.getBean(EndpointObjectMapper.class).get();
|
JsonMapper jsonMapper = context.getBean(EndpointJsonMapper.class).get();
|
||||||
Instant now = Instant.now();
|
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));
|
assertThat(json).contains(DateTimeFormatter.ISO_INSTANT.format(now));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void endpointObjectMapperDoesNotSerializeDurationsAsTimestamps() {
|
void endpointJsonMapperDoesNotSerializeDurationsAsTimestamps() {
|
||||||
this.runner.run((context) -> {
|
this.runner.run((context) -> {
|
||||||
ObjectMapper objectMapper = context.getBean(EndpointObjectMapper.class).get();
|
JsonMapper jsonMapper = context.getBean(EndpointJsonMapper.class).get();
|
||||||
Duration duration = Duration.ofSeconds(42);
|
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());
|
assertThat(json).contains(duration.toString());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void endpointObjectMapperDoesNotSerializeNullValues() {
|
void endpointJsonMapperDoesNotSerializeNullValues() {
|
||||||
this.runner.run((context) -> {
|
this.runner.run((context) -> {
|
||||||
ObjectMapper objectMapper = context.getBean(EndpointObjectMapper.class).get();
|
JsonMapper jsonMapper = context.getBean(EndpointJsonMapper.class).get();
|
||||||
HashMap<String, String> map = new HashMap<>();
|
HashMap<String, String> map = new HashMap<>();
|
||||||
map.put("key", null);
|
map.put("key", null);
|
||||||
String json = objectMapper.writeValueAsString(map);
|
String json = jsonMapper.writeValueAsString(map);
|
||||||
assertThat(json).isEqualTo("{}");
|
assertThat(json).isEqualTo("{}");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -95,16 +95,16 @@ class JacksonEndpointAutoConfigurationTests {
|
||||||
static class TestEndpointMapperConfiguration {
|
static class TestEndpointMapperConfiguration {
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
TestEndpointObjectMapper testEndpointObjectMapper() {
|
TestEndpointJsonMapper testEndpointJsonMapper() {
|
||||||
return new TestEndpointObjectMapper();
|
return new TestEndpointJsonMapper();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static class TestEndpointObjectMapper implements EndpointObjectMapper {
|
static class TestEndpointJsonMapper implements EndpointJsonMapper {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ObjectMapper get() {
|
public JsonMapper get() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,8 +32,6 @@ dependencies {
|
||||||
optional(project(":module:spring-boot-jsonb"))
|
optional(project(":module:spring-boot-jsonb"))
|
||||||
optional(project(":module:spring-boot-validation"))
|
optional(project(":module:spring-boot-validation"))
|
||||||
optional(project(":module:spring-boot-web-server"))
|
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.github.ben-manes.caffeine:caffeine")
|
||||||
optional("com.google.code.findbugs:jsr305")
|
optional("com.google.code.findbugs:jsr305")
|
||||||
optional("com.zaxxer:HikariCP")
|
optional("com.zaxxer:HikariCP")
|
||||||
|
@ -57,8 +55,8 @@ dependencies {
|
||||||
optional("org.springframework.graphql:spring-graphql")
|
optional("org.springframework.graphql:spring-graphql")
|
||||||
optional("org.springframework.security:spring-security-core")
|
optional("org.springframework.security:spring-security-core")
|
||||||
optional("org.springframework.security:spring-security-web")
|
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.junit.jupiter:junit-jupiter-api")
|
||||||
testFixturesImplementation("org.springframework:spring-test")
|
testFixturesImplementation("org.springframework:spring-test")
|
||||||
testFixturesImplementation("org.springframework:spring-webflux")
|
testFixturesImplementation("org.springframework:spring-webflux")
|
||||||
|
|
|
@ -29,30 +29,30 @@ import java.util.function.Predicate;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonInclude.Include;
|
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.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
import org.jspecify.annotations.Nullable;
|
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.beans.BeansException;
|
||||||
import org.springframework.boot.actuate.endpoint.OperationResponseBody;
|
import org.springframework.boot.actuate.endpoint.OperationResponseBody;
|
||||||
|
@ -180,13 +180,10 @@ public class ConfigurationPropertiesReportEndpoint implements ApplicationContext
|
||||||
*/
|
*/
|
||||||
protected void configureJsonMapper(JsonMapper.Builder builder) {
|
protected void configureJsonMapper(JsonMapper.Builder builder) {
|
||||||
builder.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
|
builder.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
|
||||||
builder.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
|
builder.changeDefaultPropertyInclusion((value) -> value.withValueInclusion(Include.NON_NULL));
|
||||||
builder.configure(SerializationFeature.WRITE_DURATIONS_AS_TIMESTAMPS, false);
|
builder.accessorNaming(new DefaultAccessorNamingStrategy.Provider().withFirstCharAcceptance(true, false));
|
||||||
builder.configure(MapperFeature.USE_STD_BEAN_NAMING, true);
|
|
||||||
builder.serializationInclusion(Include.NON_NULL);
|
|
||||||
applyConfigurationPropertiesFilter(builder);
|
applyConfigurationPropertiesFilter(builder);
|
||||||
applySerializationModifier(builder);
|
applySerializationModifier(builder);
|
||||||
builder.addModule(new JavaTimeModule());
|
|
||||||
builder.addModule(new ConfigurationPropertiesModule());
|
builder.addModule(new ConfigurationPropertiesModule());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -411,8 +408,8 @@ public class ConfigurationPropertiesReportEndpoint implements ApplicationContext
|
||||||
private static final class ConfigurationPropertiesAnnotationIntrospector extends JacksonAnnotationIntrospector {
|
private static final class ConfigurationPropertiesAnnotationIntrospector extends JacksonAnnotationIntrospector {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object findFilterId(Annotated a) {
|
public Object findFilterId(MapperConfig<?> config, Annotated a) {
|
||||||
Object id = super.findFilterId(a);
|
Object id = super.findFilterId(config, a);
|
||||||
if (id == null) {
|
if (id == null) {
|
||||||
id = CONFIGURATION_PROPERTIES_FILTER_ID;
|
id = CONFIGURATION_PROPERTIES_FILTER_ID;
|
||||||
}
|
}
|
||||||
|
@ -450,7 +447,7 @@ public class ConfigurationPropertiesReportEndpoint implements ApplicationContext
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void serializeAsField(Object pojo, JsonGenerator jgen, SerializerProvider provider,
|
public void serializeAsProperty(Object pojo, JsonGenerator jgen, SerializationContext context,
|
||||||
PropertyWriter writer) throws Exception {
|
PropertyWriter writer) throws Exception {
|
||||||
if (writer instanceof BeanPropertyWriter beanPropertyWriter) {
|
if (writer instanceof BeanPropertyWriter beanPropertyWriter) {
|
||||||
try {
|
try {
|
||||||
|
@ -470,7 +467,7 @@ public class ConfigurationPropertiesReportEndpoint implements ApplicationContext
|
||||||
return;
|
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();
|
private static final ParameterNameDiscoverer PARAMETER_NAME_DISCOVERER = new DefaultParameterNameDiscoverer();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<BeanPropertyWriter> changeProperties(SerializationConfig config, BeanDescription beanDesc,
|
public List<BeanPropertyWriter> changeProperties(SerializationConfig config, BeanDescription.Supplier beanDesc,
|
||||||
List<BeanPropertyWriter> beanProperties) {
|
List<BeanPropertyWriter> beanProperties) {
|
||||||
List<BeanPropertyWriter> result = new ArrayList<>();
|
List<BeanPropertyWriter> result = new ArrayList<>();
|
||||||
Class<?> beanClass = beanDesc.getType().getRawClass();
|
Class<?> beanClass = beanDesc.getType().getRawClass();
|
||||||
|
@ -508,7 +505,7 @@ public class ConfigurationPropertiesReportEndpoint implements ApplicationContext
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isCandidate(BeanDescription beanDesc, BeanPropertyWriter writer,
|
private boolean isCandidate(BeanDescription.Supplier beanDesc, BeanPropertyWriter writer,
|
||||||
@Nullable Constructor<?> constructor) {
|
@Nullable Constructor<?> constructor) {
|
||||||
if (constructor != null) {
|
if (constructor != null) {
|
||||||
Parameter[] parameters = constructor.getParameters();
|
Parameter[] parameters = constructor.getParameters();
|
||||||
|
@ -529,10 +526,10 @@ public class ConfigurationPropertiesReportEndpoint implements ApplicationContext
|
||||||
return isReadable(beanDesc, writer);
|
return isReadable(beanDesc, writer);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isReadable(BeanDescription beanDesc, BeanPropertyWriter writer) {
|
private boolean isReadable(BeanDescription.Supplier beanDesc, BeanPropertyWriter writer) {
|
||||||
Class<?> parentType = beanDesc.getType().getRawClass();
|
Class<?> parentType = beanDesc.get().getType().getRawClass();
|
||||||
Class<?> type = writer.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,
|
// 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
|
// 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
|
// 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 java.util.Map;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
||||||
import org.jspecify.annotations.Nullable;
|
import org.jspecify.annotations.Nullable;
|
||||||
|
import tools.jackson.databind.ObjectMapper;
|
||||||
|
|
||||||
import org.springframework.lang.Contract;
|
import org.springframework.lang.Contract;
|
||||||
|
|
||||||
|
|
|
@ -18,19 +18,19 @@ package org.springframework.boot.actuate.endpoint.jackson;
|
||||||
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import tools.jackson.databind.json.JsonMapper;
|
||||||
|
|
||||||
import org.springframework.boot.actuate.endpoint.OperationResponseBody;
|
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.
|
* endpoint results.
|
||||||
*
|
*
|
||||||
* @author Phillip Webb
|
* @author Phillip Webb
|
||||||
* @since 3.0.0
|
* @since 4.0.0
|
||||||
* @see OperationResponseBody
|
* @see OperationResponseBody
|
||||||
*/
|
*/
|
||||||
public interface EndpointObjectMapper {
|
public interface EndpointJsonMapper {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The default supported types.
|
* The default supported types.
|
||||||
|
@ -38,16 +38,15 @@ public interface EndpointObjectMapper {
|
||||||
Set<Class<?>> DEFAULT_SUPPORTED_TYPES = Set.of(OperationResponseBody.class);
|
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.
|
* {@link OperationResponseBody} endpoint results.
|
||||||
* @return the object mapper
|
* @return the object mapper
|
||||||
*/
|
*/
|
||||||
ObjectMapper get();
|
JsonMapper get();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the types that this endpoint mapper supports.
|
* Return the types that this endpoint mapper supports.
|
||||||
* @return the supported types
|
* @return the supported types
|
||||||
* @since 4.0.0
|
|
||||||
*/
|
*/
|
||||||
default Set<Class<?>> getSupportedTypes() {
|
default Set<Class<?>> getSupportedTypes() {
|
||||||
return DEFAULT_SUPPORTED_TYPES;
|
return DEFAULT_SUPPORTED_TYPES;
|
|
@ -20,9 +20,9 @@ import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.JavaType;
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
||||||
import org.jspecify.annotations.Nullable;
|
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
|
* {@link JmxOperationResponseMapper} that delegates to a Jackson {@link ObjectMapper} to
|
||||||
|
|
|
@ -20,6 +20,7 @@ import java.util.Collections;
|
||||||
|
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
import org.junit.jupiter.api.Test;
|
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.assertThat;
|
||||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||||
|
@ -69,13 +70,10 @@ class AuditEventTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@SuppressWarnings({ "removal", "deprecation" })
|
|
||||||
void jsonFormat() throws Exception {
|
void jsonFormat() throws Exception {
|
||||||
AuditEvent event = new AuditEvent("johannes", "UNKNOWN",
|
AuditEvent event = new AuditEvent("johannes", "UNKNOWN",
|
||||||
Collections.singletonMap("type", (Object) "BadCredentials"));
|
Collections.singletonMap("type", (Object) "BadCredentials"));
|
||||||
String json = org.springframework.http.converter.json.Jackson2ObjectMapperBuilder.json()
|
String json = new ObjectMapper().writeValueAsString(event);
|
||||||
.build()
|
|
||||||
.writeValueAsString(event);
|
|
||||||
JSONObject jsonObject = new JSONObject(json);
|
JSONObject jsonObject = new JSONObject(json);
|
||||||
assertThat(jsonObject.getString("type")).isEqualTo("UNKNOWN");
|
assertThat(jsonObject.getString("type")).isEqualTo("UNKNOWN");
|
||||||
assertThat(jsonObject.getJSONObject("data").getString("type")).isEqualTo("BadCredentials");
|
assertThat(jsonObject.getJSONObject("data").getString("type")).isEqualTo("BadCredentials");
|
||||||
|
|
|
@ -179,7 +179,7 @@ class ConfigurationPropertiesReportEndpointTests {
|
||||||
void descriptorWithMixedCaseProperty() {
|
void descriptorWithMixedCaseProperty() {
|
||||||
this.contextRunner.withUserConfiguration(MixedCasePropertiesConfiguration.class)
|
this.contextRunner.withUserConfiguration(MixedCasePropertiesConfiguration.class)
|
||||||
.run(assertProperties("mixedcase",
|
.run(assertProperties("mixedcase",
|
||||||
(properties) -> assertThat(properties.get("mIxedCase")).isEqualTo("mixed")));
|
(properties) -> assertThat(properties).containsEntry("mIxedCase", "mixed")));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -23,9 +23,9 @@ import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.JavaType;
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
import tools.jackson.databind.JavaType;
|
||||||
|
import tools.jackson.databind.ObjectMapper;
|
||||||
|
|
||||||
import org.springframework.boot.test.json.BasicJsonTester;
|
import org.springframework.boot.test.json.BasicJsonTester;
|
||||||
|
|
||||||
|
|
|
@ -20,10 +20,10 @@ import java.util.Collections;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.Map;
|
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 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.actuate.endpoint.ApiVersion;
|
||||||
import org.springframework.boot.health.contributor.Health;
|
import org.springframework.boot.health.contributor.Health;
|
||||||
|
|
|
@ -16,10 +16,10 @@
|
||||||
|
|
||||||
package org.springframework.boot.actuate.health;
|
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 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;
|
import org.springframework.boot.health.contributor.Health;
|
||||||
|
|
||||||
|
|
|
@ -22,10 +22,10 @@ import java.util.LinkedHashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
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 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.actuate.endpoint.ApiVersion;
|
||||||
import org.springframework.boot.health.contributor.Health;
|
import org.springframework.boot.health.contributor.Health;
|
||||||
|
|
|
@ -33,6 +33,7 @@ dependencies {
|
||||||
optional(project(":core:spring-boot-testcontainers"))
|
optional(project(":core:spring-boot-testcontainers"))
|
||||||
optional(project(":module:spring-boot-health"))
|
optional(project(":module:spring-boot-health"))
|
||||||
optional(project(":module:spring-boot-jackson"))
|
optional(project(":module:spring-boot-jackson"))
|
||||||
|
optional("com.fasterxml.jackson.core:jackson-databind")
|
||||||
optional("org.testcontainers:couchbase")
|
optional("org.testcontainers:couchbase")
|
||||||
|
|
||||||
dockerTestImplementation(project(":core:spring-boot-test"))
|
dockerTestImplementation(project(":core:spring-boot-test"))
|
||||||
|
|
|
@ -17,7 +17,6 @@
|
||||||
package org.springframework.boot.couchbase.autoconfigure;
|
package org.springframework.boot.couchbase.autoconfigure;
|
||||||
|
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.function.Consumer;
|
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.env.ClusterEnvironment;
|
||||||
import com.couchbase.client.java.json.JsonValueModule;
|
import com.couchbase.client.java.json.JsonValueModule;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.fasterxml.jackson.databind.module.SimpleModule;
|
||||||
import org.assertj.core.api.InstanceOfAssertFactories;
|
import org.assertj.core.api.InstanceOfAssertFactories;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
@ -129,14 +129,14 @@ class CouchbaseAutoConfigurationTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void whenObjectMapperBeanIsDefinedThenClusterEnvironmentObjectMapperIsDerivedFromIt() {
|
void whenObjectMapperBeanIsDefinedThenClusterEnvironmentObjectMapperIsDerivedFromIt() {
|
||||||
|
ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
objectMapper.registerModule(new SimpleModule("custom"));
|
||||||
this.contextRunner.withUserConfiguration(CouchbaseTestConfiguration.class)
|
this.contextRunner.withUserConfiguration(CouchbaseTestConfiguration.class)
|
||||||
.withConfiguration(AutoConfigurations.of(JacksonAutoConfiguration.class))
|
.withBean(ObjectMapper.class, () -> objectMapper)
|
||||||
.withPropertyValues("spring.couchbase.connection-string=localhost")
|
.withPropertyValues("spring.couchbase.connection-string=localhost")
|
||||||
.run((context) -> {
|
.run((context) -> {
|
||||||
ClusterEnvironment env = context.getBean(ClusterEnvironment.class);
|
ClusterEnvironment env = context.getBean(ClusterEnvironment.class);
|
||||||
Set<Object> expectedModuleIds = new HashSet<>(
|
Set<Object> expectedModuleIds = Set.of("custom", new JsonValueModule().getTypeId());
|
||||||
context.getBean(ObjectMapper.class).getRegisteredModuleIds());
|
|
||||||
expectedModuleIds.add(new JsonValueModule().getTypeId());
|
|
||||||
JsonSerializer serializer = env.jsonSerializer();
|
JsonSerializer serializer = env.jsonSerializer();
|
||||||
assertThat(serializer).extracting("wrapped")
|
assertThat(serializer).extracting("wrapped")
|
||||||
.isInstanceOf(JacksonJsonSerializer.class)
|
.isInstanceOf(JacksonJsonSerializer.class)
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue