mirror of
https://github.com/spring-projects/spring-boot.git
synced 2026-10-02 23:39:34 +00:00
Add Jackson2Tester support
See gh-47688
This commit is contained in:
@@ -27,7 +27,7 @@ dependencies {
|
||||
api(project(":core:spring-boot"))
|
||||
api("org.springframework:spring-test")
|
||||
|
||||
optional("tools.jackson.core:jackson-databind")
|
||||
optional("com.fasterxml.jackson.core:jackson-databind")
|
||||
optional("com.google.code.gson:gson")
|
||||
optional("com.jayway.jsonpath:json-path")
|
||||
optional("jakarta.json.bind:jakarta.json.bind-api")
|
||||
@@ -45,6 +45,7 @@ dependencies {
|
||||
optional("org.seleniumhq.selenium:selenium-api")
|
||||
optional("org.skyscreamer:jsonassert")
|
||||
optional("org.springframework:spring-web")
|
||||
optional("tools.jackson.core:jackson-databind")
|
||||
|
||||
testImplementation(project(":test-support:spring-boot-test-support"))
|
||||
testImplementation("ch.qos.logback:logback-classic")
|
||||
|
||||
+207
@@ -0,0 +1,207 @@
|
||||
/*
|
||||
* 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.test.json;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.Reader;
|
||||
|
||||
import com.fasterxml.jackson.databind.JavaType;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.ObjectReader;
|
||||
import com.fasterxml.jackson.databind.ObjectWriter;
|
||||
import com.jayway.jsonpath.Configuration;
|
||||
import com.jayway.jsonpath.spi.json.JacksonJsonProvider;
|
||||
import com.jayway.jsonpath.spi.mapper.JacksonMappingProvider;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.beans.factory.ObjectFactory;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* AssertJ based JSON tester backed by Jackson 2. Usually instantiated via
|
||||
* {@link #initFields(Object, ObjectMapper)}, for example: <pre class="code">
|
||||
* public class ExampleObjectJsonTests {
|
||||
*
|
||||
* private Jackson2Tester<ExampleObject> json;
|
||||
*
|
||||
* @Before
|
||||
* public void setup() {
|
||||
* ObjectMapper objectMapper = new ObjectMapper();
|
||||
* Jackson2Tester.initFields(this, objectMapper);
|
||||
* }
|
||||
*
|
||||
* @Test
|
||||
* public void testWriteJson() throws IOException {
|
||||
* ExampleObject object = //...
|
||||
* assertThat(json.write(object)).isEqualToJson("expected.json");
|
||||
* }
|
||||
*
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* See {@link AbstractJsonMarshalTester} for more details.
|
||||
*
|
||||
* @param <T> the type under test
|
||||
* @author Phillip Webb
|
||||
* @author Madhura Bhave
|
||||
* @author Diego Berrueta
|
||||
* @since 4.0.0
|
||||
* @deprecated since 4.0.0 for removal in 4.2.0 in favor of Jackson 3.
|
||||
*/
|
||||
@Deprecated(since = "4.0.0", forRemoval = true)
|
||||
public class Jackson2Tester<T> extends AbstractJsonMarshalTester<T> {
|
||||
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
private @Nullable Class<?> view;
|
||||
|
||||
/**
|
||||
* Create a new {@link Jackson2Tester} instance.
|
||||
* @param objectMapper the Jackson object mapper
|
||||
*/
|
||||
protected Jackson2Tester(ObjectMapper objectMapper) {
|
||||
Assert.notNull(objectMapper, "'objectMapper' must not be null");
|
||||
this.objectMapper = objectMapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link Jackson2Tester} instance.
|
||||
* @param resourceLoadClass the source class used to load resources
|
||||
* @param type the type under test
|
||||
* @param objectMapper the Jackson object mapper
|
||||
*/
|
||||
public Jackson2Tester(Class<?> resourceLoadClass, ResolvableType type, ObjectMapper objectMapper) {
|
||||
this(resourceLoadClass, type, objectMapper, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link Jackson2Tester} instance.
|
||||
* @param resourceLoadClass the source class used to load resources
|
||||
* @param type the type under test
|
||||
* @param objectMapper the Jackson object mapper
|
||||
* @param view the JSON view
|
||||
*/
|
||||
public Jackson2Tester(Class<?> resourceLoadClass, ResolvableType type, ObjectMapper objectMapper,
|
||||
@Nullable Class<?> view) {
|
||||
super(resourceLoadClass, type);
|
||||
Assert.notNull(objectMapper, "'objectMapper' must not be null");
|
||||
this.objectMapper = objectMapper;
|
||||
this.view = view;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JsonContent<T> getJsonContent(String json) {
|
||||
Configuration configuration = Configuration.builder()
|
||||
.jsonProvider(new JacksonJsonProvider(this.objectMapper))
|
||||
.mappingProvider(new JacksonMappingProvider(this.objectMapper))
|
||||
.build();
|
||||
Class<?> resourceLoadClass = getResourceLoadClass();
|
||||
Assert.state(resourceLoadClass != null, "'resourceLoadClass' must not be null");
|
||||
return new JsonContent<>(resourceLoadClass, getType(), json, configuration);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected T readObject(InputStream inputStream, ResolvableType type) throws IOException {
|
||||
return getObjectReader(type).readValue(inputStream);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected T readObject(Reader reader, ResolvableType type) throws IOException {
|
||||
return getObjectReader(type).readValue(reader);
|
||||
}
|
||||
|
||||
private ObjectReader getObjectReader(ResolvableType type) {
|
||||
ObjectReader objectReader = this.objectMapper.readerFor(getType(type));
|
||||
if (this.view != null) {
|
||||
return objectReader.withView(this.view);
|
||||
}
|
||||
return objectReader;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String writeObject(T value, ResolvableType type) throws IOException {
|
||||
return getObjectWriter(type).writeValueAsString(value);
|
||||
}
|
||||
|
||||
private ObjectWriter getObjectWriter(ResolvableType type) {
|
||||
ObjectWriter objectWriter = this.objectMapper.writerFor(getType(type));
|
||||
if (this.view != null) {
|
||||
return objectWriter.withView(this.view);
|
||||
}
|
||||
return objectWriter;
|
||||
}
|
||||
|
||||
private JavaType getType(ResolvableType type) {
|
||||
return this.objectMapper.constructType(type.getType());
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method to initialize {@link Jackson2Tester} fields. See
|
||||
* {@link Jackson2Tester class-level documentation} for example usage.
|
||||
* @param testInstance the test instance
|
||||
* @param objectMapper the JSON mapper
|
||||
* @see #initFields(Object, ObjectMapper)
|
||||
*/
|
||||
public static void initFields(Object testInstance, ObjectMapper objectMapper) {
|
||||
new Jackson2FieldInitializer().initFields(testInstance, objectMapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method to initialize {@link Jackson2Tester} fields. See
|
||||
* {@link Jackson2Tester class-level documentation} for example usage.
|
||||
* @param testInstance the test instance
|
||||
* @param objectMapperFactory a factory to create the object mapper
|
||||
* @see #initFields(Object, ObjectMapper)
|
||||
*/
|
||||
public static void initFields(Object testInstance, ObjectFactory<ObjectMapper> objectMapperFactory) {
|
||||
new Jackson2FieldInitializer().initFields(testInstance, objectMapperFactory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new instance of {@link Jackson2Tester} with the view that should be used
|
||||
* for json serialization/deserialization.
|
||||
* @param view the view class
|
||||
* @return the new instance
|
||||
*/
|
||||
public Jackson2Tester<T> forView(Class<?> view) {
|
||||
Class<?> resourceLoadClass = getResourceLoadClass();
|
||||
ResolvableType type = getType();
|
||||
Assert.state(resourceLoadClass != null, "'resourceLoadClass' must not be null");
|
||||
Assert.state(type != null, "'type' must not be null");
|
||||
return new Jackson2Tester<>(resourceLoadClass, type, this.objectMapper, view);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link FieldInitializer} for Jackson.
|
||||
*/
|
||||
private static class Jackson2FieldInitializer extends FieldInitializer<ObjectMapper> {
|
||||
|
||||
protected Jackson2FieldInitializer() {
|
||||
super(Jackson2Tester.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AbstractJsonMarshalTester<Object> createTester(Class<?> resourceLoadClass, ResolvableType type,
|
||||
ObjectMapper marshaller) {
|
||||
return new Jackson2Tester<>(resourceLoadClass, type, marshaller);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+8
@@ -103,6 +103,14 @@ public class JacksonTester<T> extends AbstractJsonMarshalTester<T> {
|
||||
this(resourceLoadClass, type, jsonMapper, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link JacksonTester} instance.
|
||||
* @param resourceLoadClass the source class used to load resources
|
||||
* @param type the type under test
|
||||
* @param jsonMapper the Jackson JSON mapper
|
||||
* @param view the JSON view
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public JacksonTester(Class<?> resourceLoadClass, ResolvableType type, JsonMapper jsonMapper,
|
||||
@Nullable Class<?> view) {
|
||||
super(resourceLoadClass, type);
|
||||
|
||||
+92
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* 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.test.json;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.core.ResolvableType;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Tests for {@link Jackson2Tester}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @deprecated since 4.0.0 for removal in 4.2.0 in favor of JacksonTesterTests
|
||||
*/
|
||||
@Deprecated(since = "4.0.0", forRemoval = true)
|
||||
@SuppressWarnings("removal")
|
||||
class Jackson2TesterTests extends AbstractJsonMarshalTesterTests {
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("NullAway") // Test null check
|
||||
void initFieldsWhenTestIsNullShouldThrowException() {
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> Jackson2Tester.initFields(null, new ObjectMapper()))
|
||||
.withMessageContaining("'testInstance' must not be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("NullAway") // Test null check
|
||||
void initFieldsWhenMarshallerIsNullShouldThrowException() {
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(() -> Jackson2Tester.initFields(new InitFieldsTestClass(), (ObjectMapper) null))
|
||||
.withMessageContaining("'marshaller' must not be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
void initFieldsShouldSetNullFields() {
|
||||
InitFieldsTestClass test = new InitFieldsTestClass();
|
||||
assertThat(test.test).isNull();
|
||||
assertThat(test.base).isNull();
|
||||
Jackson2Tester.initFields(test, new ObjectMapper());
|
||||
assertThat(test.test).isNotNull();
|
||||
assertThat(test.base).isNotNull();
|
||||
ResolvableType type = test.test.getType();
|
||||
assertThat(type).isNotNull();
|
||||
assertThat(type.resolve()).isEqualTo(List.class);
|
||||
assertThat(type.resolveGeneric()).isEqualTo(ExampleObject.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AbstractJsonMarshalTester<Object> createTester(Class<?> resourceLoadClass, ResolvableType type) {
|
||||
return new org.springframework.boot.test.json.Jackson2Tester<>(resourceLoadClass, type, new ObjectMapper());
|
||||
}
|
||||
|
||||
abstract static class InitFieldsBaseClass {
|
||||
|
||||
public org.springframework.boot.test.json.@Nullable Jackson2Tester<ExampleObject> base;
|
||||
|
||||
public org.springframework.boot.test.json.Jackson2Tester<ExampleObject> baseSet = new org.springframework.boot.test.json.Jackson2Tester<>(
|
||||
InitFieldsBaseClass.class, ResolvableType.forClass(ExampleObject.class), new ObjectMapper());
|
||||
|
||||
}
|
||||
|
||||
static class InitFieldsTestClass extends InitFieldsBaseClass {
|
||||
|
||||
public org.springframework.boot.test.json.@Nullable Jackson2Tester<List<ExampleObject>> test;
|
||||
|
||||
public org.springframework.boot.test.json.Jackson2Tester<ExampleObject> testSet = new org.springframework.boot.test.json.Jackson2Tester<>(
|
||||
InitFieldsBaseClass.class, ResolvableType.forClass(ExampleObject.class), new ObjectMapper());
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* 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.jackson2.autoconfigure;
|
||||
|
||||
import com.fasterxml.jackson.databind.json.JsonMapper;
|
||||
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.test.autoconfigure.TestAutoConfiguration;
|
||||
import org.springframework.boot.test.autoconfigure.json.ConditionalOnJsonTesters;
|
||||
import org.springframework.boot.test.autoconfigure.json.JsonMarshalTesterRuntimeHints;
|
||||
import org.springframework.boot.test.autoconfigure.json.JsonTesterFactoryBean;
|
||||
import org.springframework.boot.test.json.GsonTester;
|
||||
import org.springframework.boot.test.json.JacksonTester;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ImportRuntimeHints;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for {@link GsonTester}.
|
||||
*
|
||||
* @author Phjllip Webb
|
||||
* @deprecated since 4.0.0 for removal in 4.2.0 in favor of Jackson 3.
|
||||
*/
|
||||
@Deprecated(since = "4.0.0", forRemoval = true)
|
||||
@TestAutoConfiguration(after = Jackson2AutoConfiguration.class)
|
||||
@ConditionalOnJsonTesters
|
||||
@SuppressWarnings("removal")
|
||||
final class Jackson2TesterAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
|
||||
@ConditionalOnBean(JsonMapper.class)
|
||||
@ImportRuntimeHints(Jackson2TesterRuntimeHints.class)
|
||||
FactoryBean<JacksonTester<?>> jacksonTesterFactoryBean(JsonMapper mapper) {
|
||||
return new JsonTesterFactoryBean<>(JacksonTester.class, mapper);
|
||||
}
|
||||
|
||||
static class Jackson2TesterRuntimeHints extends JsonMarshalTesterRuntimeHints {
|
||||
|
||||
Jackson2TesterRuntimeHints() {
|
||||
super(JacksonTester.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
org.springframework.boot.jackson.autoconfigure.Jackson2AutoConfiguration
|
||||
+1
@@ -0,0 +1 @@
|
||||
org.springframework.boot.jackson.autoconfigure.Jackson2TesterAutoConfiguration
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
org.springframework.boot.jackson2.JsonComponent
|
||||
com.fasterxml.jackson.databind.Module
|
||||
Reference in New Issue
Block a user