Merge branch 'main' into 34651
This commit is contained in:
commit
3ace6a407e
|
@ -933,13 +933,12 @@ Java::
|
||||||
[source,java,indent=0,subs="verbatim,quotes"]
|
[source,java,indent=0,subs="verbatim,quotes"]
|
||||||
----
|
----
|
||||||
// create a startup step and start recording
|
// create a startup step and start recording
|
||||||
StartupStep scanPackages = getApplicationStartup().start("spring.context.base-packages.scan");
|
try (StartupStep scanPackages = getApplicationStartup().start("spring.context.base-packages.scan")) {
|
||||||
// add tagging information to the current step
|
// add tagging information to the current step
|
||||||
scanPackages.tag("packages", () -> Arrays.toString(basePackages));
|
scanPackages.tag("packages", () -> Arrays.toString(basePackages));
|
||||||
// perform the actual phase we're instrumenting
|
// perform the actual phase we're instrumenting
|
||||||
this.scanner.scan(basePackages);
|
this.scanner.scan(basePackages);
|
||||||
// end the current step
|
}
|
||||||
scanPackages.end();
|
|
||||||
----
|
----
|
||||||
|
|
||||||
Kotlin::
|
Kotlin::
|
||||||
|
@ -947,13 +946,12 @@ Kotlin::
|
||||||
[source,kotlin,indent=0,subs="verbatim,quotes"]
|
[source,kotlin,indent=0,subs="verbatim,quotes"]
|
||||||
----
|
----
|
||||||
// create a startup step and start recording
|
// create a startup step and start recording
|
||||||
val scanPackages = getApplicationStartup().start("spring.context.base-packages.scan")
|
try (val scanPackages = getApplicationStartup().start("spring.context.base-packages.scan")) {
|
||||||
// add tagging information to the current step
|
// add tagging information to the current step
|
||||||
scanPackages.tag("packages", () -> Arrays.toString(basePackages))
|
scanPackages.tag("packages", () -> Arrays.toString(basePackages));
|
||||||
// perform the actual phase we're instrumenting
|
// perform the actual phase we're instrumenting
|
||||||
this.scanner.scan(basePackages)
|
this.scanner.scan(basePackages);
|
||||||
// end the current step
|
}
|
||||||
scanPackages.end()
|
|
||||||
----
|
----
|
||||||
======
|
======
|
||||||
|
|
||||||
|
|
|
@ -261,7 +261,7 @@ Kotlin::
|
||||||
|
|
||||||
This improves on the design of our xref:testing/mockmvc/htmlunit/mah.adoc#spring-mvc-test-server-htmlunit-mah-usage[HtmlUnit test]
|
This improves on the design of our xref:testing/mockmvc/htmlunit/mah.adoc#spring-mvc-test-server-htmlunit-mah-usage[HtmlUnit test]
|
||||||
by leveraging the Page Object Pattern. As we mentioned in
|
by leveraging the Page Object Pattern. As we mentioned in
|
||||||
xref:testing/mockmvc/htmlunit/webdriver.adoc#spring-mvc-test-server-htmlunit-webdriver-why[Why WebDriver and MockMvc?], we can use the Page Object Pattern
|
xref:testing/mockmvc/htmlunit/webdriver.adoc#mockmvc-server-htmlunit-webdriver-why[Why WebDriver and MockMvc?], we can use the Page Object Pattern
|
||||||
with HtmlUnit, but it is much easier with WebDriver. Consider the following
|
with HtmlUnit, but it is much easier with WebDriver. Consider the following
|
||||||
`CreateMessagePage` implementation:
|
`CreateMessagePage` implementation:
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ javaPlatform {
|
||||||
dependencies {
|
dependencies {
|
||||||
api(platform("com.fasterxml.jackson:jackson-bom:2.20.0-rc1"))
|
api(platform("com.fasterxml.jackson:jackson-bom:2.20.0-rc1"))
|
||||||
api(platform("io.micrometer:micrometer-bom:1.16.0-M2"))
|
api(platform("io.micrometer:micrometer-bom:1.16.0-M2"))
|
||||||
api(platform("io.netty:netty-bom:4.2.3.Final"))
|
api(platform("io.netty:netty-bom:4.2.4.Final"))
|
||||||
api(platform("io.projectreactor:reactor-bom:2025.0.0-M6"))
|
api(platform("io.projectreactor:reactor-bom:2025.0.0-M6"))
|
||||||
api(platform("io.rsocket:rsocket-bom:1.1.5"))
|
api(platform("io.rsocket:rsocket-bom:1.1.5"))
|
||||||
api(platform("org.apache.groovy:groovy-bom:5.0.0-rc-1"))
|
api(platform("org.apache.groovy:groovy-bom:5.0.0-rc-1"))
|
||||||
|
@ -20,7 +20,7 @@ dependencies {
|
||||||
api(platform("org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.10.2"))
|
api(platform("org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.10.2"))
|
||||||
api(platform("org.jetbrains.kotlinx:kotlinx-serialization-bom:1.9.0"))
|
api(platform("org.jetbrains.kotlinx:kotlinx-serialization-bom:1.9.0"))
|
||||||
api(platform("org.junit:junit-bom:5.13.4"))
|
api(platform("org.junit:junit-bom:5.13.4"))
|
||||||
api(platform("org.mockito:mockito-bom:5.18.0"))
|
api(platform("org.mockito:mockito-bom:5.19.0"))
|
||||||
api(platform("tools.jackson:jackson-bom:3.0.0-rc8"))
|
api(platform("tools.jackson:jackson-bom:3.0.0-rc8"))
|
||||||
|
|
||||||
constraints {
|
constraints {
|
||||||
|
@ -31,7 +31,7 @@ dependencies {
|
||||||
api("com.google.code.findbugs:findbugs:3.0.1")
|
api("com.google.code.findbugs:findbugs:3.0.1")
|
||||||
api("com.google.code.findbugs:jsr305:3.0.2")
|
api("com.google.code.findbugs:jsr305:3.0.2")
|
||||||
api("com.google.code.gson:gson:2.13.1")
|
api("com.google.code.gson:gson:2.13.1")
|
||||||
api("com.google.protobuf:protobuf-java-util:4.31.1")
|
api("com.google.protobuf:protobuf-java-util:4.32.0")
|
||||||
api("com.h2database:h2:2.3.232")
|
api("com.h2database:h2:2.3.232")
|
||||||
api("com.jayway.jsonpath:json-path:2.9.0")
|
api("com.jayway.jsonpath:json-path:2.9.0")
|
||||||
api("com.networknt:json-schema-validator:1.5.3")
|
api("com.networknt:json-schema-validator:1.5.3")
|
||||||
|
@ -124,7 +124,7 @@ dependencies {
|
||||||
api("org.hibernate.orm:hibernate-core:7.1.0.Final")
|
api("org.hibernate.orm:hibernate-core:7.1.0.Final")
|
||||||
api("org.hibernate.validator:hibernate-validator:9.0.1.Final")
|
api("org.hibernate.validator:hibernate-validator:9.0.1.Final")
|
||||||
api("org.hsqldb:hsqldb:2.7.4")
|
api("org.hsqldb:hsqldb:2.7.4")
|
||||||
api("org.htmlunit:htmlunit:4.14.0")
|
api("org.htmlunit:htmlunit:4.15.0")
|
||||||
api("org.javamoney:moneta:1.4.4")
|
api("org.javamoney:moneta:1.4.4")
|
||||||
api("org.jboss.logging:jboss-logging:3.6.1.Final")
|
api("org.jboss.logging:jboss-logging:3.6.1.Final")
|
||||||
api("org.jruby:jruby:10.0.2.0")
|
api("org.jruby:jruby:10.0.2.0")
|
||||||
|
@ -135,7 +135,7 @@ dependencies {
|
||||||
api("org.python:jython-standalone:2.7.4")
|
api("org.python:jython-standalone:2.7.4")
|
||||||
api("org.quartz-scheduler:quartz:2.3.2")
|
api("org.quartz-scheduler:quartz:2.3.2")
|
||||||
api("org.reactivestreams:reactive-streams:1.0.4")
|
api("org.reactivestreams:reactive-streams:1.0.4")
|
||||||
api("org.seleniumhq.selenium:htmlunit3-driver:4.34.0")
|
api("org.seleniumhq.selenium:htmlunit3-driver:4.35.0")
|
||||||
api("org.seleniumhq.selenium:selenium-java:4.35.0")
|
api("org.seleniumhq.selenium:selenium-java:4.35.0")
|
||||||
api("org.skyscreamer:jsonassert:2.0-rc1")
|
api("org.skyscreamer:jsonassert:2.0-rc1")
|
||||||
api("org.testng:testng:7.11.0")
|
api("org.testng:testng:7.11.0")
|
||||||
|
|
|
@ -514,8 +514,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||||
* to check whether the bean with the given name matches the specified type. Allow
|
* to check whether the bean with the given name matches the specified type. Allow
|
||||||
* additional constraints to be applied to ensure that beans are not created early.
|
* additional constraints to be applied to ensure that beans are not created early.
|
||||||
* @param name the name of the bean to query
|
* @param name the name of the bean to query
|
||||||
* @param typeToMatch the type to match against (as a
|
* @param typeToMatch the type to match against (as a {@code ResolvableType})
|
||||||
* {@code ResolvableType})
|
|
||||||
* @return {@code true} if the bean type matches, {@code false} if it
|
* @return {@code true} if the bean type matches, {@code false} if it
|
||||||
* doesn't match or cannot be determined yet
|
* doesn't match or cannot be determined yet
|
||||||
* @throws NoSuchBeanDefinitionException if there is no bean with the given name
|
* @throws NoSuchBeanDefinitionException if there is no bean with the given name
|
||||||
|
|
|
@ -60,6 +60,7 @@ import org.springframework.beans.factory.BeanFactoryAware;
|
||||||
import org.springframework.beans.factory.BeanFactoryUtils;
|
import org.springframework.beans.factory.BeanFactoryUtils;
|
||||||
import org.springframework.beans.factory.BeanNotOfRequiredTypeException;
|
import org.springframework.beans.factory.BeanNotOfRequiredTypeException;
|
||||||
import org.springframework.beans.factory.CannotLoadBeanClassException;
|
import org.springframework.beans.factory.CannotLoadBeanClassException;
|
||||||
|
import org.springframework.beans.factory.FactoryBean;
|
||||||
import org.springframework.beans.factory.InjectionPoint;
|
import org.springframework.beans.factory.InjectionPoint;
|
||||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||||
import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
|
import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
|
||||||
|
@ -191,8 +192,8 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||||
/** Map from bean name to merged BeanDefinitionHolder. */
|
/** Map from bean name to merged BeanDefinitionHolder. */
|
||||||
private final Map<String, BeanDefinitionHolder> mergedBeanDefinitionHolders = new ConcurrentHashMap<>(256);
|
private final Map<String, BeanDefinitionHolder> mergedBeanDefinitionHolders = new ConcurrentHashMap<>(256);
|
||||||
|
|
||||||
/** Set of bean definition names with a primary marker. */
|
/** Map of bean definition names with a primary marker plus corresponding type. */
|
||||||
private final Set<String> primaryBeanNames = ConcurrentHashMap.newKeySet(16);
|
private final Map<String, Class<?>> primaryBeanNamesWithType = new ConcurrentHashMap<>(16);
|
||||||
|
|
||||||
/** Map of singleton and non-singleton bean names, keyed by dependency type. */
|
/** Map of singleton and non-singleton bean names, keyed by dependency type. */
|
||||||
private final Map<Class<?>, String[]> allBeanNamesByType = new ConcurrentHashMap<>(64);
|
private final Map<Class<?>, String[]> allBeanNamesByType = new ConcurrentHashMap<>(64);
|
||||||
|
@ -1024,7 +1025,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||||
protected void cacheMergedBeanDefinition(RootBeanDefinition mbd, String beanName) {
|
protected void cacheMergedBeanDefinition(RootBeanDefinition mbd, String beanName) {
|
||||||
super.cacheMergedBeanDefinition(mbd, beanName);
|
super.cacheMergedBeanDefinition(mbd, beanName);
|
||||||
if (mbd.isPrimary()) {
|
if (mbd.isPrimary()) {
|
||||||
this.primaryBeanNames.add(beanName);
|
this.primaryBeanNamesWithType.put(beanName, Void.class);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1309,7 +1310,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||||
|
|
||||||
// Cache a primary marker for the given bean.
|
// Cache a primary marker for the given bean.
|
||||||
if (beanDefinition.isPrimary()) {
|
if (beanDefinition.isPrimary()) {
|
||||||
this.primaryBeanNames.add(beanName);
|
this.primaryBeanNamesWithType.put(beanName, Void.class);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1401,7 +1402,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||||
destroySingleton(beanName);
|
destroySingleton(beanName);
|
||||||
|
|
||||||
// Remove a cached primary marker for the given bean.
|
// Remove a cached primary marker for the given bean.
|
||||||
this.primaryBeanNames.remove(beanName);
|
this.primaryBeanNamesWithType.remove(beanName);
|
||||||
|
|
||||||
// Notify all post-processors that the specified bean definition has been reset.
|
// Notify all post-processors that the specified bean definition has been reset.
|
||||||
for (MergedBeanDefinitionPostProcessor processor : getBeanPostProcessorCache().mergedDefinition) {
|
for (MergedBeanDefinitionPostProcessor processor : getBeanPostProcessorCache().mergedDefinition) {
|
||||||
|
@ -1454,9 +1455,18 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||||
@Override
|
@Override
|
||||||
protected void addSingleton(String beanName, Object singletonObject) {
|
protected void addSingleton(String beanName, Object singletonObject) {
|
||||||
super.addSingleton(beanName, singletonObject);
|
super.addSingleton(beanName, singletonObject);
|
||||||
|
|
||||||
Predicate<Class<?>> filter = (beanType -> beanType != Object.class && beanType.isInstance(singletonObject));
|
Predicate<Class<?>> filter = (beanType -> beanType != Object.class && beanType.isInstance(singletonObject));
|
||||||
this.allBeanNamesByType.keySet().removeIf(filter);
|
this.allBeanNamesByType.keySet().removeIf(filter);
|
||||||
this.singletonBeanNamesByType.keySet().removeIf(filter);
|
this.singletonBeanNamesByType.keySet().removeIf(filter);
|
||||||
|
|
||||||
|
if (this.primaryBeanNamesWithType.containsKey(beanName) && singletonObject.getClass() != NullBean.class) {
|
||||||
|
Class<?> beanType = (singletonObject instanceof FactoryBean<?> fb ?
|
||||||
|
getTypeForFactoryBean(fb) : singletonObject.getClass());
|
||||||
|
if (beanType != null) {
|
||||||
|
this.primaryBeanNamesWithType.put(beanName, beanType);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -2245,8 +2255,12 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||||
* not matching the given bean name.
|
* not matching the given bean name.
|
||||||
*/
|
*/
|
||||||
private boolean hasPrimaryConflict(String beanName, Class<?> dependencyType) {
|
private boolean hasPrimaryConflict(String beanName, Class<?> dependencyType) {
|
||||||
for (String candidate : this.primaryBeanNames) {
|
for (Map.Entry<String, Class<?>> candidate : this.primaryBeanNamesWithType.entrySet()) {
|
||||||
if (isTypeMatch(candidate, dependencyType) && !candidate.equals(beanName)) {
|
String candidateName = candidate.getKey();
|
||||||
|
Class<?> candidateType = candidate.getValue();
|
||||||
|
if (!candidateName.equals(beanName) && (candidateType != Void.class ?
|
||||||
|
dependencyType.isAssignableFrom(candidateType) : // cached singleton class for primary bean
|
||||||
|
isTypeMatch(candidateName, dependencyType))) { // not instantiated yet or not a singleton
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,12 +60,6 @@ class CacheOperationExpressionEvaluatorTests {
|
||||||
private final AnnotationCacheOperationSource source = new AnnotationCacheOperationSource();
|
private final AnnotationCacheOperationSource source = new AnnotationCacheOperationSource();
|
||||||
|
|
||||||
|
|
||||||
private Collection<CacheOperation> getOps(String name) {
|
|
||||||
Method method = ReflectionUtils.findMethod(AnnotatedClass.class, name, Object.class, Object.class);
|
|
||||||
return this.source.getCacheOperations(method, AnnotatedClass.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testMultipleCachingSource() {
|
void testMultipleCachingSource() {
|
||||||
Collection<CacheOperation> ops = getOps("multipleCaching");
|
Collection<CacheOperation> ops = getOps("multipleCaching");
|
||||||
|
@ -144,6 +138,12 @@ class CacheOperationExpressionEvaluatorTests {
|
||||||
assertThat(value).isEqualTo(String.class.getName());
|
assertThat(value).isEqualTo(String.class.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private Collection<CacheOperation> getOps(String name) {
|
||||||
|
Method method = ReflectionUtils.findMethod(AnnotatedClass.class, name, Object.class, Object.class);
|
||||||
|
return this.source.getCacheOperations(method, AnnotatedClass.class);
|
||||||
|
}
|
||||||
|
|
||||||
private EvaluationContext createEvaluationContext(Object result) {
|
private EvaluationContext createEvaluationContext(Object result) {
|
||||||
return createEvaluationContext(result, null);
|
return createEvaluationContext(result, null);
|
||||||
}
|
}
|
||||||
|
|
|
@ -104,6 +104,7 @@ class CachePutEvaluationTests {
|
||||||
assertThat(this.cache.get(anotherValue + 100).get()).as("Wrong value for @CachePut key").isEqualTo(anotherValue);
|
assertThat(this.cache.get(anotherValue + 100).get()).as("Wrong value for @CachePut key").isEqualTo(anotherValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableCaching
|
@EnableCaching
|
||||||
static class Config implements CachingConfigurer {
|
static class Config implements CachingConfigurer {
|
||||||
|
@ -121,8 +122,10 @@ class CachePutEvaluationTests {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@CacheConfig("test")
|
@CacheConfig("test")
|
||||||
public static class SimpleService {
|
public static class SimpleService {
|
||||||
|
|
||||||
private AtomicLong counter = new AtomicLong();
|
private AtomicLong counter = new AtomicLong();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -144,4 +147,5 @@ class CachePutEvaluationTests {
|
||||||
return this.counter.getAndIncrement();
|
return this.counter.getAndIncrement();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,7 @@ import org.jspecify.annotations.Nullable;
|
||||||
* @author Brian Clozel
|
* @author Brian Clozel
|
||||||
* @since 5.3
|
* @since 5.3
|
||||||
*/
|
*/
|
||||||
public interface StartupStep {
|
public interface StartupStep extends AutoCloseable {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the name of the startup step.
|
* Return the name of the startup step.
|
||||||
|
@ -83,6 +83,10 @@ public interface StartupStep {
|
||||||
*/
|
*/
|
||||||
void end();
|
void end();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default void close() {
|
||||||
|
this.end();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Immutable collection of {@link Tag}.
|
* Immutable collection of {@link Tag}.
|
||||||
|
|
|
@ -122,34 +122,72 @@ public class StandardEvaluationContext implements EvaluationContext {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specify the default root context object (including a type descriptor)
|
||||||
|
* against which unqualified properties, methods, etc. should be resolved.
|
||||||
|
* @param rootObject the root object to use
|
||||||
|
* @param typeDescriptor a corresponding type descriptor
|
||||||
|
*/
|
||||||
public void setRootObject(@Nullable Object rootObject, TypeDescriptor typeDescriptor) {
|
public void setRootObject(@Nullable Object rootObject, TypeDescriptor typeDescriptor) {
|
||||||
this.rootObject = new TypedValue(rootObject, typeDescriptor);
|
this.rootObject = new TypedValue(rootObject, typeDescriptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specify the default root context object against which unqualified
|
||||||
|
* properties, methods, etc. should be resolved.
|
||||||
|
* @param rootObject the root object to use
|
||||||
|
*/
|
||||||
public void setRootObject(@Nullable Object rootObject) {
|
public void setRootObject(@Nullable Object rootObject) {
|
||||||
this.rootObject = (rootObject != null ? new TypedValue(rootObject) : TypedValue.NULL);
|
this.rootObject = (rootObject != null ? new TypedValue(rootObject) : TypedValue.NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the configured default root context object against which unqualified
|
||||||
|
* properties, methods, etc. should be resolved (can be {@link TypedValue#NULL}).
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public TypedValue getRootObject() {
|
public TypedValue getRootObject() {
|
||||||
return this.rootObject;
|
return this.rootObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the list of property accessors to use in this evaluation context.
|
||||||
|
* <p>Replaces any previously configured property accessors.
|
||||||
|
*/
|
||||||
public void setPropertyAccessors(List<PropertyAccessor> propertyAccessors) {
|
public void setPropertyAccessors(List<PropertyAccessor> propertyAccessors) {
|
||||||
this.propertyAccessors = propertyAccessors;
|
this.propertyAccessors = propertyAccessors;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the list of property accessors configured in this evaluation context.
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public List<PropertyAccessor> getPropertyAccessors() {
|
public List<PropertyAccessor> getPropertyAccessors() {
|
||||||
return initPropertyAccessors();
|
return initPropertyAccessors();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addPropertyAccessor(PropertyAccessor accessor) {
|
/**
|
||||||
addBeforeDefault(initPropertyAccessors(), accessor);
|
* Add the supplied property accessor to this evaluation context.
|
||||||
|
* @param propertyAccessor the property accessor to add
|
||||||
|
* @see #getPropertyAccessors()
|
||||||
|
* @see #setPropertyAccessors(List)
|
||||||
|
* @see #removePropertyAccessor(PropertyAccessor)
|
||||||
|
*/
|
||||||
|
public void addPropertyAccessor(PropertyAccessor propertyAccessor) {
|
||||||
|
addBeforeDefault(initPropertyAccessors(), propertyAccessor);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean removePropertyAccessor(PropertyAccessor accessor) {
|
/**
|
||||||
return initPropertyAccessors().remove(accessor);
|
* Remove the supplied property accessor from this evaluation context.
|
||||||
|
* @param propertyAccessor the property accessor to remove
|
||||||
|
* @return {@code true} if the property accessor was removed, {@code false}
|
||||||
|
* if the property accessor was not configured in this evaluation context
|
||||||
|
* @see #getPropertyAccessors()
|
||||||
|
* @see #setPropertyAccessors(List)
|
||||||
|
* @see #addPropertyAccessor(PropertyAccessor)
|
||||||
|
*/
|
||||||
|
public boolean removePropertyAccessor(PropertyAccessor propertyAccessor) {
|
||||||
|
return initPropertyAccessors().remove(propertyAccessor);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -191,8 +229,8 @@ public class StandardEvaluationContext implements EvaluationContext {
|
||||||
/**
|
/**
|
||||||
* Remove the supplied index accessor from this evaluation context.
|
* Remove the supplied index accessor from this evaluation context.
|
||||||
* @param indexAccessor the index accessor to remove
|
* @param indexAccessor the index accessor to remove
|
||||||
* @return {@code true} if the index accessor was removed, {@code false} if
|
* @return {@code true} if the index accessor was removed, {@code false}
|
||||||
* the index accessor was not configured in this evaluation context
|
* if the index accessor was not configured in this evaluation context
|
||||||
* @since 6.2
|
* @since 6.2
|
||||||
* @see #getIndexAccessors()
|
* @see #getIndexAccessors()
|
||||||
* @see #setIndexAccessors(List)
|
* @see #setIndexAccessors(List)
|
||||||
|
@ -202,44 +240,96 @@ public class StandardEvaluationContext implements EvaluationContext {
|
||||||
return initIndexAccessors().remove(indexAccessor);
|
return initIndexAccessors().remove(indexAccessor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the list of constructor resolvers to use in this evaluation context.
|
||||||
|
* <p>Replaces any previously configured constructor resolvers.
|
||||||
|
*/
|
||||||
public void setConstructorResolvers(List<ConstructorResolver> constructorResolvers) {
|
public void setConstructorResolvers(List<ConstructorResolver> constructorResolvers) {
|
||||||
this.constructorResolvers = constructorResolvers;
|
this.constructorResolvers = constructorResolvers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the list of constructor resolvers to use in this evaluation context.
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public List<ConstructorResolver> getConstructorResolvers() {
|
public List<ConstructorResolver> getConstructorResolvers() {
|
||||||
return initConstructorResolvers();
|
return initConstructorResolvers();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addConstructorResolver(ConstructorResolver resolver) {
|
/**
|
||||||
addBeforeDefault(initConstructorResolvers(), resolver);
|
* Add the supplied constructor resolver to this evaluation context.
|
||||||
|
* @param constructorResolver the constructor resolver to add
|
||||||
|
* @see #getConstructorResolvers()
|
||||||
|
* @see #setConstructorResolvers(List)
|
||||||
|
* @see #removeConstructorResolver(ConstructorResolver)
|
||||||
|
*/
|
||||||
|
public void addConstructorResolver(ConstructorResolver constructorResolver) {
|
||||||
|
addBeforeDefault(initConstructorResolvers(), constructorResolver);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean removeConstructorResolver(ConstructorResolver resolver) {
|
/**
|
||||||
return initConstructorResolvers().remove(resolver);
|
* Remove the supplied constructor resolver from this evaluation context.
|
||||||
|
* @param constructorResolver the constructor resolver to remove
|
||||||
|
* @return {@code true} if the constructor resolver was removed, {@code false}
|
||||||
|
* if the constructor resolver was not configured in this evaluation context
|
||||||
|
* @see #getConstructorResolvers()
|
||||||
|
* @see #setConstructorResolvers(List)
|
||||||
|
* @see #addConstructorResolver(ConstructorResolver)
|
||||||
|
*/
|
||||||
|
public boolean removeConstructorResolver(ConstructorResolver constructorResolver) {
|
||||||
|
return initConstructorResolvers().remove(constructorResolver);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the list of method resolvers to use in this evaluation context.
|
||||||
|
* <p>Replaces any previously configured method resolvers.
|
||||||
|
*/
|
||||||
public void setMethodResolvers(List<MethodResolver> methodResolvers) {
|
public void setMethodResolvers(List<MethodResolver> methodResolvers) {
|
||||||
this.methodResolvers = methodResolvers;
|
this.methodResolvers = methodResolvers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the list of method resolvers to use in this evaluation context.
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public List<MethodResolver> getMethodResolvers() {
|
public List<MethodResolver> getMethodResolvers() {
|
||||||
return initMethodResolvers();
|
return initMethodResolvers();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addMethodResolver(MethodResolver resolver) {
|
/**
|
||||||
addBeforeDefault(initMethodResolvers(), resolver);
|
* Add the supplied method resolver to this evaluation context.
|
||||||
|
* @param methodResolver the method resolver to add
|
||||||
|
* @see #getMethodResolvers()
|
||||||
|
* @see #setMethodResolvers(List)
|
||||||
|
* @see #removeMethodResolver(MethodResolver)
|
||||||
|
*/
|
||||||
|
public void addMethodResolver(MethodResolver methodResolver) {
|
||||||
|
addBeforeDefault(initMethodResolvers(), methodResolver);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the supplied method resolver from this evaluation context.
|
||||||
|
* @param methodResolver the method resolver to remove
|
||||||
|
* @return {@code true} if the method resolver was removed, {@code false}
|
||||||
|
* if the method resolver was not configured in this evaluation context
|
||||||
|
* @see #getMethodResolvers()
|
||||||
|
* @see #setMethodResolvers(List)
|
||||||
|
* @see #addMethodResolver(MethodResolver)
|
||||||
|
*/
|
||||||
public boolean removeMethodResolver(MethodResolver methodResolver) {
|
public boolean removeMethodResolver(MethodResolver methodResolver) {
|
||||||
return initMethodResolvers().remove(methodResolver);
|
return initMethodResolvers().remove(methodResolver);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setBeanResolver(BeanResolver beanResolver) {
|
/**
|
||||||
|
* Set the {@link BeanResolver} to use for looking up beans, if any.
|
||||||
|
*/
|
||||||
|
public void setBeanResolver(@Nullable BeanResolver beanResolver) {
|
||||||
this.beanResolver = beanResolver;
|
this.beanResolver = beanResolver;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the configured {@link BeanResolver} for looking up beans, if any.
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public @Nullable BeanResolver getBeanResolver() {
|
public @Nullable BeanResolver getBeanResolver() {
|
||||||
return this.beanResolver;
|
return this.beanResolver;
|
||||||
|
@ -276,11 +366,17 @@ public class StandardEvaluationContext implements EvaluationContext {
|
||||||
return this.typeLocator;
|
return this.typeLocator;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the {@link TypeConverter} for value conversion.
|
||||||
|
*/
|
||||||
public void setTypeConverter(TypeConverter typeConverter) {
|
public void setTypeConverter(TypeConverter typeConverter) {
|
||||||
Assert.notNull(typeConverter, "TypeConverter must not be null");
|
Assert.notNull(typeConverter, "TypeConverter must not be null");
|
||||||
this.typeConverter = typeConverter;
|
this.typeConverter = typeConverter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the configured {@link TypeConverter} for value conversion.
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public TypeConverter getTypeConverter() {
|
public TypeConverter getTypeConverter() {
|
||||||
if (this.typeConverter == null) {
|
if (this.typeConverter == null) {
|
||||||
|
@ -289,21 +385,33 @@ public class StandardEvaluationContext implements EvaluationContext {
|
||||||
return this.typeConverter;
|
return this.typeConverter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the {@link TypeComparator} for comparing pairs of objects.
|
||||||
|
*/
|
||||||
public void setTypeComparator(TypeComparator typeComparator) {
|
public void setTypeComparator(TypeComparator typeComparator) {
|
||||||
Assert.notNull(typeComparator, "TypeComparator must not be null");
|
Assert.notNull(typeComparator, "TypeComparator must not be null");
|
||||||
this.typeComparator = typeComparator;
|
this.typeComparator = typeComparator;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the configured {@link TypeComparator} for comparing pairs of objects.
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public TypeComparator getTypeComparator() {
|
public TypeComparator getTypeComparator() {
|
||||||
return this.typeComparator;
|
return this.typeComparator;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the {@link OperatorOverloader} for mathematical operations.
|
||||||
|
*/
|
||||||
public void setOperatorOverloader(OperatorOverloader operatorOverloader) {
|
public void setOperatorOverloader(OperatorOverloader operatorOverloader) {
|
||||||
Assert.notNull(operatorOverloader, "OperatorOverloader must not be null");
|
Assert.notNull(operatorOverloader, "OperatorOverloader must not be null");
|
||||||
this.operatorOverloader = operatorOverloader;
|
this.operatorOverloader = operatorOverloader;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the configured {@link OperatorOverloader} for mathematical operations.
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public OperatorOverloader getOperatorOverloader() {
|
public OperatorOverloader getOperatorOverloader() {
|
||||||
return this.operatorOverloader;
|
return this.operatorOverloader;
|
||||||
|
|
|
@ -32,7 +32,6 @@ import jakarta.jms.Session;
|
||||||
import jakarta.jms.TextMessage;
|
import jakarta.jms.TextMessage;
|
||||||
import org.jspecify.annotations.Nullable;
|
import org.jspecify.annotations.Nullable;
|
||||||
import tools.jackson.databind.JavaType;
|
import tools.jackson.databind.JavaType;
|
||||||
import tools.jackson.databind.ObjectMapper;
|
|
||||||
import tools.jackson.databind.ObjectWriter;
|
import tools.jackson.databind.ObjectWriter;
|
||||||
import tools.jackson.databind.cfg.MapperBuilder;
|
import tools.jackson.databind.cfg.MapperBuilder;
|
||||||
import tools.jackson.databind.json.JsonMapper;
|
import tools.jackson.databind.json.JsonMapper;
|
||||||
|
@ -63,7 +62,7 @@ public class JacksonJsonMessageConverter implements SmartMessageConverter, BeanC
|
||||||
public static final String DEFAULT_ENCODING = "UTF-8";
|
public static final String DEFAULT_ENCODING = "UTF-8";
|
||||||
|
|
||||||
|
|
||||||
private final ObjectMapper objectMapper;
|
private final JsonMapper jsonMapper;
|
||||||
|
|
||||||
private MessageType targetType = MessageType.BYTES;
|
private MessageType targetType = MessageType.BYTES;
|
||||||
|
|
||||||
|
@ -86,17 +85,17 @@ public class JacksonJsonMessageConverter implements SmartMessageConverter, BeanC
|
||||||
* {@link MapperBuilder#findModules(ClassLoader)}.
|
* {@link MapperBuilder#findModules(ClassLoader)}.
|
||||||
*/
|
*/
|
||||||
public JacksonJsonMessageConverter() {
|
public JacksonJsonMessageConverter() {
|
||||||
this.objectMapper = JsonMapper.builder().findAndAddModules(JacksonJsonMessageConverter.class.getClassLoader()).build();
|
this.jsonMapper = JsonMapper.builder().findAndAddModules(JacksonJsonMessageConverter.class.getClassLoader()).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a new instance with the provided {@link ObjectMapper}.
|
* Construct a new instance with the provided {@link JsonMapper}.
|
||||||
* @see JsonMapper#builder()
|
* @see JsonMapper#builder()
|
||||||
* @see MapperBuilder#findModules(ClassLoader)
|
* @see MapperBuilder#findModules(ClassLoader)
|
||||||
*/
|
*/
|
||||||
public JacksonJsonMessageConverter(ObjectMapper objectMapper) {
|
public JacksonJsonMessageConverter(JsonMapper jsonMapper) {
|
||||||
Assert.notNull(objectMapper, "ObjectMapper must not be null");
|
Assert.notNull(jsonMapper, "JsonMapper must not be null");
|
||||||
this.objectMapper = objectMapper;
|
this.jsonMapper = jsonMapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -173,9 +172,9 @@ public class JacksonJsonMessageConverter implements SmartMessageConverter, BeanC
|
||||||
Message message;
|
Message message;
|
||||||
try {
|
try {
|
||||||
message = switch (this.targetType) {
|
message = switch (this.targetType) {
|
||||||
case TEXT -> mapToTextMessage(object, session, this.objectMapper.writer());
|
case TEXT -> mapToTextMessage(object, session, this.jsonMapper.writer());
|
||||||
case BYTES -> mapToBytesMessage(object, session, this.objectMapper.writer());
|
case BYTES -> mapToBytesMessage(object, session, this.jsonMapper.writer());
|
||||||
default -> mapToMessage(object, session, this.objectMapper.writer(), this.targetType);
|
default -> mapToMessage(object, session, this.jsonMapper.writer(), this.targetType);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
catch (IOException ex) {
|
catch (IOException ex) {
|
||||||
|
@ -206,10 +205,10 @@ public class JacksonJsonMessageConverter implements SmartMessageConverter, BeanC
|
||||||
throws JMSException, MessageConversionException {
|
throws JMSException, MessageConversionException {
|
||||||
|
|
||||||
if (jsonView != null) {
|
if (jsonView != null) {
|
||||||
return toMessage(object, session, this.objectMapper.writerWithView(jsonView));
|
return toMessage(object, session, this.jsonMapper.writerWithView(jsonView));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return toMessage(object, session, this.objectMapper.writer());
|
return toMessage(object, session, this.jsonMapper.writer());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -363,7 +362,7 @@ public class JacksonJsonMessageConverter implements SmartMessageConverter, BeanC
|
||||||
throws JMSException, IOException {
|
throws JMSException, IOException {
|
||||||
|
|
||||||
String body = message.getText();
|
String body = message.getText();
|
||||||
return this.objectMapper.readValue(body, targetJavaType);
|
return this.jsonMapper.readValue(body, targetJavaType);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -386,7 +385,7 @@ public class JacksonJsonMessageConverter implements SmartMessageConverter, BeanC
|
||||||
if (encoding != null) {
|
if (encoding != null) {
|
||||||
try {
|
try {
|
||||||
String body = new String(bytes, encoding);
|
String body = new String(bytes, encoding);
|
||||||
return this.objectMapper.readValue(body, targetJavaType);
|
return this.jsonMapper.readValue(body, targetJavaType);
|
||||||
}
|
}
|
||||||
catch (UnsupportedEncodingException ex) {
|
catch (UnsupportedEncodingException ex) {
|
||||||
throw new MessageConversionException("Cannot convert bytes to String", ex);
|
throw new MessageConversionException("Cannot convert bytes to String", ex);
|
||||||
|
@ -394,7 +393,7 @@ public class JacksonJsonMessageConverter implements SmartMessageConverter, BeanC
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Jackson internally performs encoding detection, falling back to UTF-8.
|
// Jackson internally performs encoding detection, falling back to UTF-8.
|
||||||
return this.objectMapper.readValue(bytes, targetJavaType);
|
return this.jsonMapper.readValue(bytes, targetJavaType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -437,11 +436,11 @@ public class JacksonJsonMessageConverter implements SmartMessageConverter, BeanC
|
||||||
}
|
}
|
||||||
Class<?> mappedClass = this.idClassMappings.get(typeId);
|
Class<?> mappedClass = this.idClassMappings.get(typeId);
|
||||||
if (mappedClass != null) {
|
if (mappedClass != null) {
|
||||||
return this.objectMapper.constructType(mappedClass);
|
return this.jsonMapper.constructType(mappedClass);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
Class<?> typeClass = ClassUtils.forName(typeId, this.beanClassLoader);
|
Class<?> typeClass = ClassUtils.forName(typeId, this.beanClassLoader);
|
||||||
return this.objectMapper.constructType(typeClass);
|
return this.jsonMapper.constructType(typeClass);
|
||||||
}
|
}
|
||||||
catch (Throwable ex) {
|
catch (Throwable ex) {
|
||||||
throw new MessageConversionException("Failed to resolve type id [" + typeId + "]", ex);
|
throw new MessageConversionException("Failed to resolve type id [" + typeId + "]", ex);
|
||||||
|
|
|
@ -27,7 +27,6 @@ import tools.jackson.core.JacksonException;
|
||||||
import tools.jackson.core.JsonEncoding;
|
import tools.jackson.core.JsonEncoding;
|
||||||
import tools.jackson.core.JsonGenerator;
|
import tools.jackson.core.JsonGenerator;
|
||||||
import tools.jackson.databind.JavaType;
|
import tools.jackson.databind.JavaType;
|
||||||
import tools.jackson.databind.ObjectMapper;
|
|
||||||
import tools.jackson.databind.cfg.MapperBuilder;
|
import tools.jackson.databind.cfg.MapperBuilder;
|
||||||
import tools.jackson.databind.json.JsonMapper;
|
import tools.jackson.databind.json.JsonMapper;
|
||||||
|
|
||||||
|
@ -52,7 +51,7 @@ public class JacksonJsonMessageConverter extends AbstractMessageConverter {
|
||||||
private static final MimeType[] DEFAULT_MIME_TYPES = new MimeType[] {
|
private static final MimeType[] DEFAULT_MIME_TYPES = new MimeType[] {
|
||||||
new MimeType("application", "json"), new MimeType("application", "*+json")};
|
new MimeType("application", "json"), new MimeType("application", "*+json")};
|
||||||
|
|
||||||
private final ObjectMapper objectMapper;
|
private final JsonMapper jsonMapper;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -73,35 +72,35 @@ public class JacksonJsonMessageConverter extends AbstractMessageConverter {
|
||||||
*/
|
*/
|
||||||
public JacksonJsonMessageConverter(MimeType... supportedMimeTypes) {
|
public JacksonJsonMessageConverter(MimeType... supportedMimeTypes) {
|
||||||
super(supportedMimeTypes);
|
super(supportedMimeTypes);
|
||||||
this.objectMapper = JsonMapper.builder().findAndAddModules(JacksonJsonMessageConverter.class.getClassLoader()).build();
|
this.jsonMapper = JsonMapper.builder().findAndAddModules(JacksonJsonMessageConverter.class.getClassLoader()).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a new instance with the provided {@link ObjectMapper}.
|
* Construct a new instance with the provided {@link JsonMapper}.
|
||||||
* @see JsonMapper#builder()
|
* @see JsonMapper#builder()
|
||||||
* @see MapperBuilder#findModules(ClassLoader)
|
* @see MapperBuilder#findModules(ClassLoader)
|
||||||
*/
|
*/
|
||||||
public JacksonJsonMessageConverter(ObjectMapper objectMapper) {
|
public JacksonJsonMessageConverter(JsonMapper jsonMapper) {
|
||||||
this(objectMapper, DEFAULT_MIME_TYPES);
|
this(jsonMapper, DEFAULT_MIME_TYPES);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a new instance with the provided {@link ObjectMapper} and the
|
* Construct a new instance with the provided {@link JsonMapper} and the
|
||||||
* provided {@link MimeType}s.
|
* provided {@link MimeType}s.
|
||||||
* @see JsonMapper#builder()
|
* @see JsonMapper#builder()
|
||||||
* @see MapperBuilder#findModules(ClassLoader)
|
* @see MapperBuilder#findModules(ClassLoader)
|
||||||
*/
|
*/
|
||||||
public JacksonJsonMessageConverter(ObjectMapper objectMapper, MimeType... supportedMimeTypes) {
|
public JacksonJsonMessageConverter(JsonMapper jsonMapper, MimeType... supportedMimeTypes) {
|
||||||
super(supportedMimeTypes);
|
super(supportedMimeTypes);
|
||||||
Assert.notNull(objectMapper, "ObjectMapper must not be null");
|
Assert.notNull(jsonMapper, "JsonMapper must not be null");
|
||||||
this.objectMapper = objectMapper;
|
this.jsonMapper = jsonMapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the underlying {@code ObjectMapper} for this converter.
|
* Return the underlying {@code JsonMapper} for this converter.
|
||||||
*/
|
*/
|
||||||
protected ObjectMapper getObjectMapper() {
|
protected JsonMapper getJsonMapper() {
|
||||||
return this.objectMapper;
|
return this.jsonMapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -122,7 +121,7 @@ public class JacksonJsonMessageConverter extends AbstractMessageConverter {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected @Nullable Object convertFromInternal(Message<?> message, Class<?> targetClass, @Nullable Object conversionHint) {
|
protected @Nullable Object convertFromInternal(Message<?> message, Class<?> targetClass, @Nullable Object conversionHint) {
|
||||||
JavaType javaType = this.objectMapper.constructType(getResolvedType(targetClass, conversionHint));
|
JavaType javaType = this.jsonMapper.constructType(getResolvedType(targetClass, conversionHint));
|
||||||
Object payload = message.getPayload();
|
Object payload = message.getPayload();
|
||||||
Class<?> view = getSerializationView(conversionHint);
|
Class<?> view = getSerializationView(conversionHint);
|
||||||
try {
|
try {
|
||||||
|
@ -131,19 +130,19 @@ public class JacksonJsonMessageConverter extends AbstractMessageConverter {
|
||||||
}
|
}
|
||||||
else if (payload instanceof byte[] bytes) {
|
else if (payload instanceof byte[] bytes) {
|
||||||
if (view != null) {
|
if (view != null) {
|
||||||
return this.objectMapper.readerWithView(view).forType(javaType).readValue(bytes);
|
return this.jsonMapper.readerWithView(view).forType(javaType).readValue(bytes);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return this.objectMapper.readValue(bytes, javaType);
|
return this.jsonMapper.readValue(bytes, javaType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Assuming a text-based source payload
|
// Assuming a text-based source payload
|
||||||
if (view != null) {
|
if (view != null) {
|
||||||
return this.objectMapper.readerWithView(view).forType(javaType).readValue(payload.toString());
|
return this.jsonMapper.readerWithView(view).forType(javaType).readValue(payload.toString());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return this.objectMapper.readValue(payload.toString(), javaType);
|
return this.jsonMapper.readValue(payload.toString(), javaType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -161,12 +160,12 @@ public class JacksonJsonMessageConverter extends AbstractMessageConverter {
|
||||||
if (byte[].class == getSerializedPayloadClass()) {
|
if (byte[].class == getSerializedPayloadClass()) {
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream(1024);
|
ByteArrayOutputStream out = new ByteArrayOutputStream(1024);
|
||||||
JsonEncoding encoding = getJsonEncoding(getMimeType(headers));
|
JsonEncoding encoding = getJsonEncoding(getMimeType(headers));
|
||||||
try (JsonGenerator generator = this.objectMapper.createGenerator(out, encoding)) {
|
try (JsonGenerator generator = this.jsonMapper.createGenerator(out, encoding)) {
|
||||||
if (view != null) {
|
if (view != null) {
|
||||||
this.objectMapper.writerWithView(view).writeValue(generator, payload);
|
this.jsonMapper.writerWithView(view).writeValue(generator, payload);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this.objectMapper.writeValue(generator, payload);
|
this.jsonMapper.writeValue(generator, payload);
|
||||||
}
|
}
|
||||||
payload = out.toByteArray();
|
payload = out.toByteArray();
|
||||||
}
|
}
|
||||||
|
@ -175,10 +174,10 @@ public class JacksonJsonMessageConverter extends AbstractMessageConverter {
|
||||||
// Assuming a text-based target payload
|
// Assuming a text-based target payload
|
||||||
Writer writer = new StringWriter(1024);
|
Writer writer = new StringWriter(1024);
|
||||||
if (view != null) {
|
if (view != null) {
|
||||||
this.objectMapper.writerWithView(view).writeValue(writer, payload);
|
this.jsonMapper.writerWithView(view).writeValue(writer, payload);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this.objectMapper.writeValue(writer, payload);
|
this.jsonMapper.writeValue(writer, payload);
|
||||||
}
|
}
|
||||||
payload = writer.toString();
|
payload = writer.toString();
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,7 +45,7 @@ import org.junit.jupiter.params.provider.ValueSource;
|
||||||
import org.skyscreamer.jsonassert.JSONCompareMode;
|
import org.skyscreamer.jsonassert.JSONCompareMode;
|
||||||
import org.skyscreamer.jsonassert.JSONCompareResult;
|
import org.skyscreamer.jsonassert.JSONCompareResult;
|
||||||
import org.skyscreamer.jsonassert.comparator.JSONComparator;
|
import org.skyscreamer.jsonassert.comparator.JSONComparator;
|
||||||
import tools.jackson.databind.ObjectMapper;
|
import tools.jackson.databind.json.JsonMapper;
|
||||||
|
|
||||||
import org.springframework.core.io.ByteArrayResource;
|
import org.springframework.core.io.ByteArrayResource;
|
||||||
import org.springframework.core.io.ClassPathResource;
|
import org.springframework.core.io.ClassPathResource;
|
||||||
|
@ -86,7 +86,7 @@ class AbstractJsonContentAssertTests {
|
||||||
private static final String DIFFERENT = loadJson("different.json");
|
private static final String DIFFERENT = loadJson("different.json");
|
||||||
|
|
||||||
private static final HttpMessageContentConverter jsonContentConverter = HttpMessageContentConverter.of(
|
private static final HttpMessageContentConverter jsonContentConverter = HttpMessageContentConverter.of(
|
||||||
new JacksonJsonHttpMessageConverter(new ObjectMapper()));
|
new JacksonJsonHttpMessageConverter(new JsonMapper()));
|
||||||
|
|
||||||
private static final JsonComparator comparator = JsonAssert.comparator(JsonCompareMode.LENIENT);
|
private static final JsonComparator comparator = JsonAssert.comparator(JsonCompareMode.LENIENT);
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ import org.assertj.core.data.Offset;
|
||||||
import org.jspecify.annotations.Nullable;
|
import org.jspecify.annotations.Nullable;
|
||||||
import org.junit.jupiter.api.Nested;
|
import org.junit.jupiter.api.Nested;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import tools.jackson.databind.ObjectMapper;
|
import tools.jackson.databind.json.JsonMapper;
|
||||||
|
|
||||||
import org.springframework.http.converter.json.JacksonJsonHttpMessageConverter;
|
import org.springframework.http.converter.json.JacksonJsonHttpMessageConverter;
|
||||||
import org.springframework.test.http.HttpMessageContentConverter;
|
import org.springframework.test.http.HttpMessageContentConverter;
|
||||||
|
@ -206,7 +206,7 @@ class JsonPathValueAssertTests {
|
||||||
class ConvertToTests {
|
class ConvertToTests {
|
||||||
|
|
||||||
private static final HttpMessageContentConverter jsonContentConverter = HttpMessageContentConverter.of(
|
private static final HttpMessageContentConverter jsonContentConverter = HttpMessageContentConverter.of(
|
||||||
new JacksonJsonHttpMessageConverter(new ObjectMapper()));
|
new JacksonJsonHttpMessageConverter(new JsonMapper()));
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void convertToWithoutHttpMessageConverter() {
|
void convertToWithoutHttpMessageConverter() {
|
||||||
|
|
|
@ -27,7 +27,7 @@ import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.params.ParameterizedTest;
|
import org.junit.jupiter.params.ParameterizedTest;
|
||||||
import org.junit.jupiter.params.provider.ValueSource;
|
import org.junit.jupiter.params.provider.ValueSource;
|
||||||
import tools.jackson.databind.JavaType;
|
import tools.jackson.databind.JavaType;
|
||||||
import tools.jackson.databind.ObjectMapper;
|
import tools.jackson.databind.json.JsonMapper;
|
||||||
|
|
||||||
import org.springframework.core.ParameterizedTypeReference;
|
import org.springframework.core.ParameterizedTypeReference;
|
||||||
|
|
||||||
|
@ -385,14 +385,14 @@ class JsonPathExpectationsHelperTests {
|
||||||
*/
|
*/
|
||||||
private static class JacksonMappingProvider implements MappingProvider {
|
private static class JacksonMappingProvider implements MappingProvider {
|
||||||
|
|
||||||
private final ObjectMapper objectMapper;
|
private final JsonMapper jsonMapper;
|
||||||
|
|
||||||
public JacksonMappingProvider() {
|
public JacksonMappingProvider() {
|
||||||
this(new ObjectMapper());
|
this(new JsonMapper());
|
||||||
}
|
}
|
||||||
|
|
||||||
public JacksonMappingProvider(ObjectMapper objectMapper) {
|
public JacksonMappingProvider(JsonMapper jsonMapper) {
|
||||||
this.objectMapper = objectMapper;
|
this.jsonMapper = jsonMapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -402,7 +402,7 @@ class JsonPathExpectationsHelperTests {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
return objectMapper.convertValue(source, targetType);
|
return jsonMapper.convertValue(source, targetType);
|
||||||
}
|
}
|
||||||
catch (Exception ex) {
|
catch (Exception ex) {
|
||||||
throw new MappingException(ex);
|
throw new MappingException(ex);
|
||||||
|
@ -416,10 +416,10 @@ class JsonPathExpectationsHelperTests {
|
||||||
if (source == null){
|
if (source == null){
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
JavaType type = objectMapper.getTypeFactory().constructType(targetType.getType());
|
JavaType type = jsonMapper.getTypeFactory().constructType(targetType.getType());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return (T) objectMapper.convertValue(source, type);
|
return (T) jsonMapper.convertValue(source, type);
|
||||||
}
|
}
|
||||||
catch (Exception ex) {
|
catch (Exception ex) {
|
||||||
throw new MappingException(ex);
|
throw new MappingException(ex);
|
||||||
|
|
|
@ -22,7 +22,7 @@ import java.util.Map;
|
||||||
import com.jayway.jsonpath.Configuration;
|
import com.jayway.jsonpath.Configuration;
|
||||||
import com.jayway.jsonpath.TypeRef;
|
import com.jayway.jsonpath.TypeRef;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import tools.jackson.databind.ObjectMapper;
|
import tools.jackson.databind.json.JsonMapper;
|
||||||
|
|
||||||
import org.springframework.http.codec.json.JacksonJsonDecoder;
|
import org.springframework.http.codec.json.JacksonJsonDecoder;
|
||||||
import org.springframework.http.codec.json.JacksonJsonEncoder;
|
import org.springframework.http.codec.json.JacksonJsonEncoder;
|
||||||
|
@ -36,10 +36,10 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||||
*/
|
*/
|
||||||
class EncoderDecoderMappingProviderTests {
|
class EncoderDecoderMappingProviderTests {
|
||||||
|
|
||||||
private static final ObjectMapper objectMapper = new ObjectMapper();
|
private static final JsonMapper jsonMapper = new JsonMapper();
|
||||||
|
|
||||||
private final EncoderDecoderMappingProvider mappingProvider = new EncoderDecoderMappingProvider(
|
private final EncoderDecoderMappingProvider mappingProvider = new EncoderDecoderMappingProvider(
|
||||||
new JacksonJsonEncoder(objectMapper), new JacksonJsonDecoder(objectMapper));
|
new JacksonJsonEncoder(jsonMapper), new JacksonJsonDecoder(jsonMapper));
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -19,7 +19,7 @@ package org.springframework.test.web.reactive.server;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import tools.jackson.databind.ObjectMapper;
|
import tools.jackson.databind.json.JsonMapper;
|
||||||
|
|
||||||
import org.springframework.http.codec.DecoderHttpMessageReader;
|
import org.springframework.http.codec.DecoderHttpMessageReader;
|
||||||
import org.springframework.http.codec.EncoderHttpMessageWriter;
|
import org.springframework.http.codec.EncoderHttpMessageWriter;
|
||||||
|
@ -39,13 +39,13 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||||
*/
|
*/
|
||||||
class JsonEncoderDecoderTests {
|
class JsonEncoderDecoderTests {
|
||||||
|
|
||||||
private static final ObjectMapper objectMapper = new ObjectMapper();
|
private static final JsonMapper jsonMapper = new JsonMapper();
|
||||||
|
|
||||||
private static final HttpMessageWriter<?> jacksonMessageWriter = new EncoderHttpMessageWriter<>(
|
private static final HttpMessageWriter<?> jacksonMessageWriter = new EncoderHttpMessageWriter<>(
|
||||||
new JacksonJsonEncoder(objectMapper));
|
new JacksonJsonEncoder(jsonMapper));
|
||||||
|
|
||||||
private static final HttpMessageReader<?> jacksonMessageReader = new DecoderHttpMessageReader<>(
|
private static final HttpMessageReader<?> jacksonMessageReader = new DecoderHttpMessageReader<>(
|
||||||
new JacksonJsonDecoder(objectMapper));
|
new JacksonJsonDecoder(jsonMapper));
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void fromWithEmptyWriters() {
|
void fromWithEmptyWriters() {
|
||||||
|
|
|
@ -57,8 +57,9 @@ import org.springframework.util.MimeType;
|
||||||
*
|
*
|
||||||
* @author Sebastien Deleuze
|
* @author Sebastien Deleuze
|
||||||
* @since 7.0
|
* @since 7.0
|
||||||
|
* @param <T> the type of {@link ObjectMapper}
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractJacksonDecoder extends JacksonCodecSupport implements HttpMessageDecoder<Object> {
|
public abstract class AbstractJacksonDecoder<T extends ObjectMapper> extends JacksonCodecSupport<T> implements HttpMessageDecoder<Object> {
|
||||||
|
|
||||||
private int maxInMemorySize = 256 * 1024;
|
private int maxInMemorySize = 256 * 1024;
|
||||||
|
|
||||||
|
@ -68,14 +69,14 @@ public abstract class AbstractJacksonDecoder extends JacksonCodecSupport impleme
|
||||||
* customized with the {@link tools.jackson.databind.JacksonModule}s found
|
* customized with the {@link tools.jackson.databind.JacksonModule}s found
|
||||||
* by {@link MapperBuilder#findModules(ClassLoader)} and {@link MimeType}s.
|
* by {@link MapperBuilder#findModules(ClassLoader)} and {@link MimeType}s.
|
||||||
*/
|
*/
|
||||||
protected AbstractJacksonDecoder(MapperBuilder<?, ?> builder, MimeType... mimeTypes) {
|
protected AbstractJacksonDecoder(MapperBuilder<T, ?> builder, MimeType... mimeTypes) {
|
||||||
super(builder, mimeTypes);
|
super(builder, mimeTypes);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a new instance with the provided {@link ObjectMapper} and {@link MimeType}s.
|
* Construct a new instance with the provided {@link ObjectMapper} and {@link MimeType}s.
|
||||||
*/
|
*/
|
||||||
protected AbstractJacksonDecoder(ObjectMapper mapper, MimeType... mimeTypes) {
|
protected AbstractJacksonDecoder(T mapper, MimeType... mimeTypes) {
|
||||||
super(mapper, mimeTypes);
|
super(mapper, mimeTypes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,7 +105,7 @@ public abstract class AbstractJacksonDecoder extends JacksonCodecSupport impleme
|
||||||
if (!supportsMimeType(mimeType)) {
|
if (!supportsMimeType(mimeType)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
ObjectMapper mapper = selectObjectMapper(elementType, mimeType);
|
T mapper = selectMapper(elementType, mimeType);
|
||||||
if (mapper == null) {
|
if (mapper == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -115,7 +116,7 @@ public abstract class AbstractJacksonDecoder extends JacksonCodecSupport impleme
|
||||||
public Flux<Object> decode(Publisher<DataBuffer> input, ResolvableType elementType,
|
public Flux<Object> decode(Publisher<DataBuffer> input, ResolvableType elementType,
|
||||||
@Nullable MimeType mimeType, @Nullable Map<String, Object> hints) {
|
@Nullable MimeType mimeType, @Nullable Map<String, Object> hints) {
|
||||||
|
|
||||||
ObjectMapper mapper = selectObjectMapper(elementType, mimeType);
|
T mapper = selectMapper(elementType, mimeType);
|
||||||
if (mapper == null) {
|
if (mapper == null) {
|
||||||
return Flux.error(new IllegalStateException("No ObjectMapper for " + elementType));
|
return Flux.error(new IllegalStateException("No ObjectMapper for " + elementType));
|
||||||
}
|
}
|
||||||
|
@ -141,7 +142,7 @@ public abstract class AbstractJacksonDecoder extends JacksonCodecSupport impleme
|
||||||
|
|
||||||
return tokens.handle((tokenBuffer, sink) -> {
|
return tokens.handle((tokenBuffer, sink) -> {
|
||||||
try {
|
try {
|
||||||
Object value = reader.readValue(tokenBuffer.asParser(getObjectMapper()._deserializationContext()));
|
Object value = reader.readValue(tokenBuffer.asParser(getMapper()._deserializationContext()));
|
||||||
logValue(value, hints);
|
logValue(value, hints);
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
sink.next(value);
|
sink.next(value);
|
||||||
|
@ -189,7 +190,7 @@ public abstract class AbstractJacksonDecoder extends JacksonCodecSupport impleme
|
||||||
public Object decode(DataBuffer dataBuffer, ResolvableType targetType,
|
public Object decode(DataBuffer dataBuffer, ResolvableType targetType,
|
||||||
@Nullable MimeType mimeType, @Nullable Map<String, Object> hints) throws DecodingException {
|
@Nullable MimeType mimeType, @Nullable Map<String, Object> hints) throws DecodingException {
|
||||||
|
|
||||||
ObjectMapper mapper = selectObjectMapper(targetType, mimeType);
|
T mapper = selectMapper(targetType, mimeType);
|
||||||
if (mapper == null) {
|
if (mapper == null) {
|
||||||
throw new IllegalStateException("No ObjectMapper for " + targetType);
|
throw new IllegalStateException("No ObjectMapper for " + targetType);
|
||||||
}
|
}
|
||||||
|
@ -208,8 +209,7 @@ public abstract class AbstractJacksonDecoder extends JacksonCodecSupport impleme
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private ObjectReader createObjectReader(
|
private ObjectReader createObjectReader(T mapper, ResolvableType elementType, @Nullable Map<String, Object> hints) {
|
||||||
ObjectMapper mapper, ResolvableType elementType, @Nullable Map<String, Object> hints) {
|
|
||||||
|
|
||||||
Assert.notNull(elementType, "'elementType' must not be null");
|
Assert.notNull(elementType, "'elementType' must not be null");
|
||||||
Class<?> contextClass = getContextClass(elementType);
|
Class<?> contextClass = getContextClass(elementType);
|
||||||
|
|
|
@ -64,8 +64,9 @@ import org.springframework.util.MimeType;
|
||||||
*
|
*
|
||||||
* @author Sebastien Deleuze
|
* @author Sebastien Deleuze
|
||||||
* @since 7.0
|
* @since 7.0
|
||||||
|
* @param <T> the type of {@link ObjectMapper}
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractJacksonEncoder extends JacksonCodecSupport implements HttpMessageEncoder<Object> {
|
public abstract class AbstractJacksonEncoder<T extends ObjectMapper> extends JacksonCodecSupport<T> implements HttpMessageEncoder<Object> {
|
||||||
|
|
||||||
private static final byte[] NEWLINE_SEPARATOR = {'\n'};
|
private static final byte[] NEWLINE_SEPARATOR = {'\n'};
|
||||||
|
|
||||||
|
@ -90,14 +91,14 @@ public abstract class AbstractJacksonEncoder extends JacksonCodecSupport impleme
|
||||||
* customized with the {@link tools.jackson.databind.JacksonModule}s found
|
* customized with the {@link tools.jackson.databind.JacksonModule}s found
|
||||||
* by {@link MapperBuilder#findModules(ClassLoader)} and {@link MimeType}s.
|
* by {@link MapperBuilder#findModules(ClassLoader)} and {@link MimeType}s.
|
||||||
*/
|
*/
|
||||||
protected AbstractJacksonEncoder(MapperBuilder<?, ?> builder, MimeType... mimeTypes) {
|
protected AbstractJacksonEncoder(MapperBuilder<T, ?> builder, MimeType... mimeTypes) {
|
||||||
super(builder, mimeTypes);
|
super(builder, mimeTypes);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a new instance with the provided {@link ObjectMapper} and {@link MimeType}s.
|
* Construct a new instance with the provided {@link ObjectMapper} and {@link MimeType}s.
|
||||||
*/
|
*/
|
||||||
protected AbstractJacksonEncoder(ObjectMapper mapper, MimeType... mimeTypes) {
|
protected AbstractJacksonEncoder(T mapper, MimeType... mimeTypes) {
|
||||||
super(mapper, mimeTypes);
|
super(mapper, mimeTypes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,7 +123,7 @@ public abstract class AbstractJacksonEncoder extends JacksonCodecSupport impleme
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (this.objectMapperRegistrations != null && selectObjectMapper(elementType, mimeType) == null) {
|
if (this.mapperRegistrations != null && selectMapper(elementType, mimeType) == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
Class<?> clazz = elementType.resolve();
|
Class<?> clazz = elementType.resolve();
|
||||||
|
@ -155,7 +156,7 @@ public abstract class AbstractJacksonEncoder extends JacksonCodecSupport impleme
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
ObjectMapper mapper = selectObjectMapper(elementType, mimeType);
|
T mapper = selectMapper(elementType, mimeType);
|
||||||
if (mapper == null) {
|
if (mapper == null) {
|
||||||
throw new IllegalStateException("No ObjectMapper for " + elementType);
|
throw new IllegalStateException("No ObjectMapper for " + elementType);
|
||||||
}
|
}
|
||||||
|
@ -225,7 +226,7 @@ public abstract class AbstractJacksonEncoder extends JacksonCodecSupport impleme
|
||||||
filters = (FilterProvider) hints.get(FILTER_PROVIDER_HINT);
|
filters = (FilterProvider) hints.get(FILTER_PROVIDER_HINT);
|
||||||
}
|
}
|
||||||
|
|
||||||
ObjectMapper mapper = selectObjectMapper(valueType, mimeType);
|
T mapper = selectMapper(valueType, mimeType);
|
||||||
if (mapper == null) {
|
if (mapper == null) {
|
||||||
throw new IllegalStateException("No ObjectMapper for " + valueType);
|
throw new IllegalStateException("No ObjectMapper for " + valueType);
|
||||||
}
|
}
|
||||||
|
@ -319,7 +320,7 @@ public abstract class AbstractJacksonEncoder extends JacksonCodecSupport impleme
|
||||||
}
|
}
|
||||||
|
|
||||||
private ObjectWriter createObjectWriter(
|
private ObjectWriter createObjectWriter(
|
||||||
ObjectMapper mapper, ResolvableType valueType, @Nullable MimeType mimeType,
|
T mapper, ResolvableType valueType, @Nullable MimeType mimeType,
|
||||||
@Nullable Class<?> jsonView, @Nullable Map<String, Object> hints) {
|
@Nullable Class<?> jsonView, @Nullable Map<String, Object> hints) {
|
||||||
|
|
||||||
JavaType javaType = getJavaType(valueType.getType(), null);
|
JavaType javaType = getJavaType(valueType.getType(), null);
|
||||||
|
|
|
@ -50,12 +50,13 @@ import org.springframework.util.CollectionUtils;
|
||||||
import org.springframework.util.MimeType;
|
import org.springframework.util.MimeType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base class providing support methods for Jackson 2.x encoding and decoding.
|
* Base class providing support methods for Jackson 3.x encoding and decoding.
|
||||||
*
|
*
|
||||||
* @author Sebastien Deleuze
|
* @author Sebastien Deleuze
|
||||||
* @since 7.0
|
* @since 7.0
|
||||||
|
* @param <T> the type of {@link ObjectMapper}
|
||||||
*/
|
*/
|
||||||
public abstract class JacksonCodecSupport {
|
public abstract class JacksonCodecSupport<T extends ObjectMapper> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The key for the hint to specify a "JSON View" for encoding or decoding
|
* The key for the hint to specify a "JSON View" for encoding or decoding
|
||||||
|
@ -83,9 +84,9 @@ public abstract class JacksonCodecSupport {
|
||||||
|
|
||||||
protected final Log logger = HttpLogging.forLogName(getClass());
|
protected final Log logger = HttpLogging.forLogName(getClass());
|
||||||
|
|
||||||
private final ObjectMapper defaultObjectMapper;
|
private final T defaultMapper;
|
||||||
|
|
||||||
protected @Nullable Map<Class<?>, Map<MimeType, ObjectMapper>> objectMapperRegistrations;
|
protected @Nullable Map<Class<?>, Map<MimeType, T>> mapperRegistrations;
|
||||||
|
|
||||||
private final List<MimeType> mimeTypes;
|
private final List<MimeType> mimeTypes;
|
||||||
|
|
||||||
|
@ -96,10 +97,10 @@ public abstract class JacksonCodecSupport {
|
||||||
* customized with the {@link tools.jackson.databind.JacksonModule}s found
|
* customized with the {@link tools.jackson.databind.JacksonModule}s found
|
||||||
* by {@link MapperBuilder#findModules(ClassLoader)} and {@link MimeType}s.
|
* by {@link MapperBuilder#findModules(ClassLoader)} and {@link MimeType}s.
|
||||||
*/
|
*/
|
||||||
protected JacksonCodecSupport(MapperBuilder<?, ?> builder, MimeType... mimeTypes) {
|
protected JacksonCodecSupport(MapperBuilder<T, ?> builder, MimeType... mimeTypes) {
|
||||||
Assert.notNull(builder, "MapperBuilder must not be null");
|
Assert.notNull(builder, "MapperBuilder must not be null");
|
||||||
Assert.notEmpty(mimeTypes, "MimeTypes must not be empty");
|
Assert.notEmpty(mimeTypes, "MimeTypes must not be empty");
|
||||||
this.defaultObjectMapper = builder.addModules(initModules()).build();
|
this.defaultMapper = builder.addModules(initModules()).build();
|
||||||
this.mimeTypes = List.of(mimeTypes);
|
this.mimeTypes = List.of(mimeTypes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,10 +109,10 @@ public abstract class JacksonCodecSupport {
|
||||||
* customized with the {@link tools.jackson.databind.JacksonModule}s found
|
* customized with the {@link tools.jackson.databind.JacksonModule}s found
|
||||||
* by {@link MapperBuilder#findModules(ClassLoader)} and {@link MimeType}s.
|
* by {@link MapperBuilder#findModules(ClassLoader)} and {@link MimeType}s.
|
||||||
*/
|
*/
|
||||||
protected JacksonCodecSupport(ObjectMapper objectMapper, MimeType... mimeTypes) {
|
protected JacksonCodecSupport(T mapper, MimeType... mimeTypes) {
|
||||||
Assert.notNull(objectMapper, "ObjectMapper must not be null");
|
Assert.notNull(mapper, "ObjectMapper must not be null");
|
||||||
Assert.notEmpty(mimeTypes, "MimeTypes must not be empty");
|
Assert.notEmpty(mimeTypes, "MimeTypes must not be empty");
|
||||||
this.defaultObjectMapper = objectMapper;
|
this.defaultMapper = mapper;
|
||||||
this.mimeTypes = List.of(mimeTypes);
|
this.mimeTypes = List.of(mimeTypes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,19 +125,19 @@ public abstract class JacksonCodecSupport {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the {@link ObjectMapper configured} default ObjectMapper.
|
* Return the {@link ObjectMapper configured} default mapper.
|
||||||
*/
|
*/
|
||||||
public ObjectMapper getObjectMapper() {
|
public T getMapper() {
|
||||||
return this.defaultObjectMapper;
|
return this.defaultMapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configure the {@link ObjectMapper} instances to use for the given
|
* Configure the {@link ObjectMapper} instances to use for the given
|
||||||
* {@link Class}. This is useful when you want to deviate from the
|
* {@link Class}. This is useful when you want to deviate from the
|
||||||
* {@link #getObjectMapper() default} ObjectMapper or have the
|
* {@link #getMapper() default} ObjectMapper or have the
|
||||||
* {@code ObjectMapper} vary by {@code MediaType}.
|
* {@code ObjectMapper} vary by {@code MediaType}.
|
||||||
* <p><strong>Note:</strong> Use of this method effectively turns off use of
|
* <p><strong>Note:</strong> Use of this method effectively turns off use of
|
||||||
* the default {@link #getObjectMapper() ObjectMapper} and supported
|
* the default {@link #getMapper() ObjectMapper} and supported
|
||||||
* {@link #getMimeTypes() MimeTypes} for the given class. Therefore it is
|
* {@link #getMimeTypes() MimeTypes} for the given class. Therefore it is
|
||||||
* important for the mappings configured here to
|
* important for the mappings configured here to
|
||||||
* {@link MediaType#includes(MediaType) include} every MediaType that must
|
* {@link MediaType#includes(MediaType) include} every MediaType that must
|
||||||
|
@ -145,12 +146,12 @@ public abstract class JacksonCodecSupport {
|
||||||
* @param registrar a consumer to populate or otherwise update the
|
* @param registrar a consumer to populate or otherwise update the
|
||||||
* MediaType-to-ObjectMapper associations for the given Class
|
* MediaType-to-ObjectMapper associations for the given Class
|
||||||
*/
|
*/
|
||||||
public void registerObjectMappersForType(Class<?> clazz, Consumer<Map<MimeType, ObjectMapper>> registrar) {
|
public void registerMappersForType(Class<?> clazz, Consumer<Map<MimeType, T>> registrar) {
|
||||||
if (this.objectMapperRegistrations == null) {
|
if (this.mapperRegistrations == null) {
|
||||||
this.objectMapperRegistrations = new LinkedHashMap<>();
|
this.mapperRegistrations = new LinkedHashMap<>();
|
||||||
}
|
}
|
||||||
Map<MimeType, ObjectMapper> registrations =
|
Map<MimeType, T> registrations =
|
||||||
this.objectMapperRegistrations.computeIfAbsent(clazz, c -> new LinkedHashMap<>());
|
this.mapperRegistrations.computeIfAbsent(clazz, c -> new LinkedHashMap<>());
|
||||||
registrar.accept(registrations);
|
registrar.accept(registrations);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,8 +161,8 @@ public abstract class JacksonCodecSupport {
|
||||||
* @return a map with registered MediaType-to-ObjectMapper registrations,
|
* @return a map with registered MediaType-to-ObjectMapper registrations,
|
||||||
* or empty if in case of no registrations for the given class.
|
* or empty if in case of no registrations for the given class.
|
||||||
*/
|
*/
|
||||||
public @Nullable Map<MimeType, ObjectMapper> getObjectMappersForType(Class<?> clazz) {
|
public @Nullable Map<MimeType, T> getMappersForType(Class<?> clazz) {
|
||||||
for (Map.Entry<Class<?>, Map<MimeType, ObjectMapper>> entry : getObjectMapperRegistrations().entrySet()) {
|
for (Map.Entry<Class<?>, Map<MimeType, T>> entry : getMapperRegistrations().entrySet()) {
|
||||||
if (entry.getKey().isAssignableFrom(clazz)) {
|
if (entry.getKey().isAssignableFrom(clazz)) {
|
||||||
return entry.getValue();
|
return entry.getValue();
|
||||||
}
|
}
|
||||||
|
@ -169,8 +170,8 @@ public abstract class JacksonCodecSupport {
|
||||||
return Collections.emptyMap();
|
return Collections.emptyMap();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Map<Class<?>, Map<MimeType, ObjectMapper>> getObjectMapperRegistrations() {
|
protected Map<Class<?>, Map<MimeType, T>> getMapperRegistrations() {
|
||||||
return (this.objectMapperRegistrations != null ? this.objectMapperRegistrations : Collections.emptyMap());
|
return (this.mapperRegistrations != null ? this.mapperRegistrations : Collections.emptyMap());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -183,7 +184,7 @@ public abstract class JacksonCodecSupport {
|
||||||
protected List<MimeType> getMimeTypes(ResolvableType elementType) {
|
protected List<MimeType> getMimeTypes(ResolvableType elementType) {
|
||||||
Class<?> elementClass = elementType.toClass();
|
Class<?> elementClass = elementType.toClass();
|
||||||
List<MimeType> result = null;
|
List<MimeType> result = null;
|
||||||
for (Map.Entry<Class<?>, Map<MimeType, ObjectMapper>> entry : getObjectMapperRegistrations().entrySet()) {
|
for (Map.Entry<Class<?>, Map<MimeType, T>> entry : getMapperRegistrations().entrySet()) {
|
||||||
if (entry.getKey().isAssignableFrom(elementClass)) {
|
if (entry.getKey().isAssignableFrom(elementClass)) {
|
||||||
result = (result != null ? result : new ArrayList<>(entry.getValue().size()));
|
result = (result != null ? result : new ArrayList<>(entry.getValue().size()));
|
||||||
result.addAll(entry.getValue().keySet());
|
result.addAll(entry.getValue().keySet());
|
||||||
|
@ -216,7 +217,7 @@ public abstract class JacksonCodecSupport {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected JavaType getJavaType(Type type, @Nullable Class<?> contextClass) {
|
protected JavaType getJavaType(Type type, @Nullable Class<?> contextClass) {
|
||||||
return this.defaultObjectMapper.constructType(GenericTypeResolver.resolveType(type, contextClass));
|
return this.defaultMapper.constructType(GenericTypeResolver.resolveType(type, contextClass));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Map<String, Object> getHints(ResolvableType resolvableType) {
|
protected Map<String, Object> getHints(ResolvableType resolvableType) {
|
||||||
|
@ -250,18 +251,18 @@ public abstract class JacksonCodecSupport {
|
||||||
/**
|
/**
|
||||||
* Select an ObjectMapper to use, either the main ObjectMapper or another
|
* Select an ObjectMapper to use, either the main ObjectMapper or another
|
||||||
* if the handling for the given Class has been customized through
|
* if the handling for the given Class has been customized through
|
||||||
* {@link #registerObjectMappersForType(Class, Consumer)}.
|
* {@link #registerMappersForType(Class, Consumer)}.
|
||||||
*/
|
*/
|
||||||
protected @Nullable ObjectMapper selectObjectMapper(ResolvableType targetType, @Nullable MimeType targetMimeType) {
|
protected @Nullable T selectMapper(ResolvableType targetType, @Nullable MimeType targetMimeType) {
|
||||||
if (targetMimeType == null || CollectionUtils.isEmpty(this.objectMapperRegistrations)) {
|
if (targetMimeType == null || CollectionUtils.isEmpty(this.mapperRegistrations)) {
|
||||||
return this.defaultObjectMapper;
|
return this.defaultMapper;
|
||||||
}
|
}
|
||||||
Class<?> targetClass = targetType.toClass();
|
Class<?> targetClass = targetType.toClass();
|
||||||
for (Map.Entry<Class<?>, Map<MimeType, ObjectMapper>> typeEntry : getObjectMapperRegistrations().entrySet()) {
|
for (Map.Entry<Class<?>, Map<MimeType, T>> typeEntry : getMapperRegistrations().entrySet()) {
|
||||||
if (typeEntry.getKey().isAssignableFrom(targetClass)) {
|
if (typeEntry.getKey().isAssignableFrom(targetClass)) {
|
||||||
for (Map.Entry<MimeType, ObjectMapper> objectMapperEntry : typeEntry.getValue().entrySet()) {
|
for (Map.Entry<MimeType, T> mapperEntry : typeEntry.getValue().entrySet()) {
|
||||||
if (objectMapperEntry.getKey().includes(targetMimeType)) {
|
if (mapperEntry.getKey().includes(targetMimeType)) {
|
||||||
return objectMapperEntry.getValue();
|
return mapperEntry.getValue();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// No matching registrations
|
// No matching registrations
|
||||||
|
@ -269,7 +270,7 @@ public abstract class JacksonCodecSupport {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// No registrations
|
// No registrations
|
||||||
return this.defaultObjectMapper;
|
return this.defaultMapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,7 +40,7 @@ import org.springframework.util.MimeType;
|
||||||
* @see JacksonCborEncoder
|
* @see JacksonCborEncoder
|
||||||
* @see <a href="https://github.com/spring-projects/spring-framework/issues/20513">Add CBOR support to WebFlux</a>
|
* @see <a href="https://github.com/spring-projects/spring-framework/issues/20513">Add CBOR support to WebFlux</a>
|
||||||
*/
|
*/
|
||||||
public class JacksonCborDecoder extends AbstractJacksonDecoder {
|
public class JacksonCborDecoder extends AbstractJacksonDecoder<CBORMapper> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a new instance with a {@link CBORMapper} customized with the
|
* Construct a new instance with a {@link CBORMapper} customized with the
|
||||||
|
|
|
@ -41,7 +41,7 @@ import org.springframework.util.MimeType;
|
||||||
* @see JacksonCborDecoder
|
* @see JacksonCborDecoder
|
||||||
* @see <a href="https://github.com/spring-projects/spring-framework/issues/20513">Add CBOR support to WebFlux</a>
|
* @see <a href="https://github.com/spring-projects/spring-framework/issues/20513">Add CBOR support to WebFlux</a>
|
||||||
*/
|
*/
|
||||||
public class JacksonCborEncoder extends AbstractJacksonEncoder {
|
public class JacksonCborEncoder extends AbstractJacksonEncoder<CBORMapper> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a new instance with a {@link CBORMapper} customized with the
|
* Construct a new instance with a {@link CBORMapper} customized with the
|
||||||
|
|
|
@ -25,7 +25,6 @@ import java.util.Map;
|
||||||
import org.jspecify.annotations.Nullable;
|
import org.jspecify.annotations.Nullable;
|
||||||
import org.reactivestreams.Publisher;
|
import org.reactivestreams.Publisher;
|
||||||
import reactor.core.publisher.Flux;
|
import reactor.core.publisher.Flux;
|
||||||
import tools.jackson.databind.ObjectMapper;
|
|
||||||
import tools.jackson.databind.cfg.MapperBuilder;
|
import tools.jackson.databind.cfg.MapperBuilder;
|
||||||
import tools.jackson.databind.json.JsonMapper;
|
import tools.jackson.databind.json.JsonMapper;
|
||||||
|
|
||||||
|
@ -50,7 +49,7 @@ import org.springframework.util.MimeTypeUtils;
|
||||||
* @since 7.0
|
* @since 7.0
|
||||||
* @see JacksonJsonEncoder
|
* @see JacksonJsonEncoder
|
||||||
*/
|
*/
|
||||||
public class JacksonJsonDecoder extends AbstractJacksonDecoder {
|
public class JacksonJsonDecoder extends AbstractJacksonDecoder<JsonMapper> {
|
||||||
|
|
||||||
private static final CharBufferDecoder CHAR_BUFFER_DECODER = CharBufferDecoder.textPlainOnly(Arrays.asList(",", "\n"), false);
|
private static final CharBufferDecoder CHAR_BUFFER_DECODER = CharBufferDecoder.textPlainOnly(Arrays.asList(",", "\n"), false);
|
||||||
|
|
||||||
|
@ -73,20 +72,20 @@ public class JacksonJsonDecoder extends AbstractJacksonDecoder {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a new instance with the provided {@link ObjectMapper}.
|
* Construct a new instance with the provided {@link JsonMapper}.
|
||||||
* @see JsonMapper#builder()
|
* @see JsonMapper#builder()
|
||||||
* @see MapperBuilder#findModules(ClassLoader)
|
* @see MapperBuilder#findModules(ClassLoader)
|
||||||
*/
|
*/
|
||||||
public JacksonJsonDecoder(ObjectMapper mapper) {
|
public JacksonJsonDecoder(JsonMapper mapper) {
|
||||||
this(mapper, DEFAULT_JSON_MIME_TYPES);
|
this(mapper, DEFAULT_JSON_MIME_TYPES);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a new instance with the provided {@link ObjectMapper} and {@link MimeType}s.
|
* Construct a new instance with the provided {@link JsonMapper} and {@link MimeType}s.
|
||||||
* @see JsonMapper#builder()
|
* @see JsonMapper#builder()
|
||||||
* @see MapperBuilder#findModules(ClassLoader)
|
* @see MapperBuilder#findModules(ClassLoader)
|
||||||
*/
|
*/
|
||||||
public JacksonJsonDecoder(ObjectMapper mapper, MimeType... mimeTypes) {
|
public JacksonJsonDecoder(JsonMapper mapper, MimeType... mimeTypes) {
|
||||||
super(mapper, mimeTypes);
|
super(mapper, mimeTypes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,6 @@ import reactor.core.publisher.Flux;
|
||||||
import tools.jackson.core.PrettyPrinter;
|
import tools.jackson.core.PrettyPrinter;
|
||||||
import tools.jackson.core.util.DefaultIndenter;
|
import tools.jackson.core.util.DefaultIndenter;
|
||||||
import tools.jackson.core.util.DefaultPrettyPrinter;
|
import tools.jackson.core.util.DefaultPrettyPrinter;
|
||||||
import tools.jackson.databind.ObjectMapper;
|
|
||||||
import tools.jackson.databind.ObjectWriter;
|
import tools.jackson.databind.ObjectWriter;
|
||||||
import tools.jackson.databind.SerializationFeature;
|
import tools.jackson.databind.SerializationFeature;
|
||||||
import tools.jackson.databind.cfg.MapperBuilder;
|
import tools.jackson.databind.cfg.MapperBuilder;
|
||||||
|
@ -51,7 +50,7 @@ import org.springframework.util.MimeType;
|
||||||
* @since 7.0
|
* @since 7.0
|
||||||
* @see JacksonJsonDecoder
|
* @see JacksonJsonDecoder
|
||||||
*/
|
*/
|
||||||
public class JacksonJsonEncoder extends AbstractJacksonEncoder {
|
public class JacksonJsonEncoder extends AbstractJacksonEncoder<JsonMapper> {
|
||||||
|
|
||||||
private static final List<MimeType> problemDetailMimeTypes =
|
private static final List<MimeType> problemDetailMimeTypes =
|
||||||
Collections.singletonList(MediaType.APPLICATION_PROBLEM_JSON);
|
Collections.singletonList(MediaType.APPLICATION_PROBLEM_JSON);
|
||||||
|
@ -80,21 +79,21 @@ public class JacksonJsonEncoder extends AbstractJacksonEncoder {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a new instance with the provided {@link ObjectMapper}.
|
* Construct a new instance with the provided {@link JsonMapper}.
|
||||||
* @see JsonMapper#builder()
|
* @see JsonMapper#builder()
|
||||||
* @see MapperBuilder#findModules(ClassLoader)
|
* @see MapperBuilder#findModules(ClassLoader)
|
||||||
*/
|
*/
|
||||||
public JacksonJsonEncoder(ObjectMapper mapper) {
|
public JacksonJsonEncoder(JsonMapper mapper) {
|
||||||
this(mapper, DEFAULT_JSON_MIME_TYPES);
|
this(mapper, DEFAULT_JSON_MIME_TYPES);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a new instance with the provided {@link ObjectMapper} and
|
* Construct a new instance with the provided {@link JsonMapper} and
|
||||||
* {@link MimeType}s.
|
* {@link MimeType}s.
|
||||||
* @see JsonMapper#builder()
|
* @see JsonMapper#builder()
|
||||||
* @see MapperBuilder#findModules(ClassLoader)
|
* @see MapperBuilder#findModules(ClassLoader)
|
||||||
*/
|
*/
|
||||||
public JacksonJsonEncoder(ObjectMapper mapper, MimeType... mimeTypes) {
|
public JacksonJsonEncoder(JsonMapper mapper, MimeType... mimeTypes) {
|
||||||
super(mapper, mimeTypes);
|
super(mapper, mimeTypes);
|
||||||
setStreamingMediaTypes(List.of(MediaType.APPLICATION_NDJSON));
|
setStreamingMediaTypes(List.of(MediaType.APPLICATION_NDJSON));
|
||||||
this.ssePrettyPrinter = initSsePrettyPrinter();
|
this.ssePrettyPrinter = initSsePrettyPrinter();
|
||||||
|
|
|
@ -33,7 +33,7 @@ import org.springframework.util.MimeType;
|
||||||
* @since 7.0
|
* @since 7.0
|
||||||
* @see JacksonSmileEncoder
|
* @see JacksonSmileEncoder
|
||||||
*/
|
*/
|
||||||
public class JacksonSmileDecoder extends AbstractJacksonDecoder {
|
public class JacksonSmileDecoder extends AbstractJacksonDecoder<SmileMapper> {
|
||||||
|
|
||||||
private static final MimeType[] DEFAULT_SMILE_MIME_TYPES = new MimeType[] {
|
private static final MimeType[] DEFAULT_SMILE_MIME_TYPES = new MimeType[] {
|
||||||
new MimeType("application", "x-jackson-smile"),
|
new MimeType("application", "x-jackson-smile"),
|
||||||
|
|
|
@ -41,7 +41,7 @@ import org.springframework.util.MimeType;
|
||||||
* @since 7.0
|
* @since 7.0
|
||||||
* @see JacksonSmileDecoder
|
* @see JacksonSmileDecoder
|
||||||
*/
|
*/
|
||||||
public class JacksonSmileEncoder extends AbstractJacksonEncoder {
|
public class JacksonSmileEncoder extends AbstractJacksonEncoder<SmileMapper> {
|
||||||
|
|
||||||
private static final MimeType[] DEFAULT_SMILE_MIME_TYPES = new MimeType[] {
|
private static final MimeType[] DEFAULT_SMILE_MIME_TYPES = new MimeType[] {
|
||||||
new MimeType("application", "x-jackson-smile"),
|
new MimeType("application", "x-jackson-smile"),
|
||||||
|
|
|
@ -527,7 +527,7 @@ class BaseDefaultCodecs implements CodecConfigurer.DefaultCodecs, CodecConfigure
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (jacksonPresent) {
|
if (jacksonPresent) {
|
||||||
if (codec instanceof AbstractJacksonDecoder abstractJacksonDecoder) {
|
if (codec instanceof AbstractJacksonDecoder<?> abstractJacksonDecoder) {
|
||||||
abstractJacksonDecoder.setMaxInMemorySize(size);
|
abstractJacksonDecoder.setMaxInMemorySize(size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,9 +82,10 @@ import org.springframework.util.TypeUtils;
|
||||||
*
|
*
|
||||||
* @author Sebastien Deleuze
|
* @author Sebastien Deleuze
|
||||||
* @since 7.0
|
* @since 7.0
|
||||||
|
* @param <T> the type of {@link ObjectMapper}
|
||||||
* @see JacksonJsonHttpMessageConverter
|
* @see JacksonJsonHttpMessageConverter
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractJacksonHttpMessageConverter extends AbstractSmartHttpMessageConverter<Object> {
|
public abstract class AbstractJacksonHttpMessageConverter<T extends ObjectMapper> extends AbstractSmartHttpMessageConverter<Object> {
|
||||||
|
|
||||||
private static final String JSON_VIEW_HINT = JsonView.class.getName();
|
private static final String JSON_VIEW_HINT = JsonView.class.getName();
|
||||||
|
|
||||||
|
@ -103,9 +104,9 @@ public abstract class AbstractJacksonHttpMessageConverter extends AbstractSmartH
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected final ObjectMapper defaultObjectMapper;
|
protected final T defaultMapper;
|
||||||
|
|
||||||
private @Nullable Map<Class<?>, Map<MediaType, ObjectMapper>> objectMapperRegistrations;
|
private @Nullable Map<Class<?>, Map<MediaType, T>> mapperRegistrations;
|
||||||
|
|
||||||
private final @Nullable PrettyPrinter ssePrettyPrinter;
|
private final @Nullable PrettyPrinter ssePrettyPrinter;
|
||||||
|
|
||||||
|
@ -115,8 +116,8 @@ public abstract class AbstractJacksonHttpMessageConverter extends AbstractSmartH
|
||||||
* customized with the {@link tools.jackson.databind.JacksonModule}s found
|
* customized with the {@link tools.jackson.databind.JacksonModule}s found
|
||||||
* by {@link MapperBuilder#findModules(ClassLoader)}.
|
* by {@link MapperBuilder#findModules(ClassLoader)}.
|
||||||
*/
|
*/
|
||||||
private AbstractJacksonHttpMessageConverter(MapperBuilder<?, ?> builder) {
|
private AbstractJacksonHttpMessageConverter(MapperBuilder<T, ?> builder) {
|
||||||
this.defaultObjectMapper = builder.addModules(initModules()).build();
|
this.defaultMapper = builder.addModules(initModules()).build();
|
||||||
this.ssePrettyPrinter = initSsePrettyPrinter();
|
this.ssePrettyPrinter = initSsePrettyPrinter();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,7 +126,7 @@ public abstract class AbstractJacksonHttpMessageConverter extends AbstractSmartH
|
||||||
* customized with the {@link tools.jackson.databind.JacksonModule}s found
|
* customized with the {@link tools.jackson.databind.JacksonModule}s found
|
||||||
* by {@link MapperBuilder#findModules(ClassLoader)} and {@link MediaType}.
|
* by {@link MapperBuilder#findModules(ClassLoader)} and {@link MediaType}.
|
||||||
*/
|
*/
|
||||||
protected AbstractJacksonHttpMessageConverter(MapperBuilder<?, ?> builder, MediaType supportedMediaType) {
|
protected AbstractJacksonHttpMessageConverter(MapperBuilder<T, ?> builder, MediaType supportedMediaType) {
|
||||||
this(builder);
|
this(builder);
|
||||||
setSupportedMediaTypes(Collections.singletonList(supportedMediaType));
|
setSupportedMediaTypes(Collections.singletonList(supportedMediaType));
|
||||||
}
|
}
|
||||||
|
@ -135,7 +136,7 @@ public abstract class AbstractJacksonHttpMessageConverter extends AbstractSmartH
|
||||||
* customized with the {@link tools.jackson.databind.JacksonModule}s found
|
* customized with the {@link tools.jackson.databind.JacksonModule}s found
|
||||||
* by {@link MapperBuilder#findModules(ClassLoader)} and {@link MediaType}s.
|
* by {@link MapperBuilder#findModules(ClassLoader)} and {@link MediaType}s.
|
||||||
*/
|
*/
|
||||||
protected AbstractJacksonHttpMessageConverter(MapperBuilder<?, ?> builder, MediaType... supportedMediaTypes) {
|
protected AbstractJacksonHttpMessageConverter(MapperBuilder<T, ?> builder, MediaType... supportedMediaTypes) {
|
||||||
this(builder);
|
this(builder);
|
||||||
setSupportedMediaTypes(Arrays.asList(supportedMediaTypes));
|
setSupportedMediaTypes(Arrays.asList(supportedMediaTypes));
|
||||||
}
|
}
|
||||||
|
@ -143,24 +144,24 @@ public abstract class AbstractJacksonHttpMessageConverter extends AbstractSmartH
|
||||||
/**
|
/**
|
||||||
* Construct a new instance with the provided {@link ObjectMapper}.
|
* Construct a new instance with the provided {@link ObjectMapper}.
|
||||||
*/
|
*/
|
||||||
protected AbstractJacksonHttpMessageConverter(ObjectMapper objectMapper) {
|
protected AbstractJacksonHttpMessageConverter(T mapper) {
|
||||||
this.defaultObjectMapper = objectMapper;
|
this.defaultMapper = mapper;
|
||||||
this.ssePrettyPrinter = initSsePrettyPrinter();
|
this.ssePrettyPrinter = initSsePrettyPrinter();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a new instance with the provided {@link ObjectMapper} and {@link MediaType}.
|
* Construct a new instance with the provided {@link ObjectMapper} and {@link MediaType}.
|
||||||
*/
|
*/
|
||||||
protected AbstractJacksonHttpMessageConverter(ObjectMapper objectMapper, MediaType supportedMediaType) {
|
protected AbstractJacksonHttpMessageConverter(T mapper, MediaType supportedMediaType) {
|
||||||
this(objectMapper);
|
this(mapper);
|
||||||
setSupportedMediaTypes(Collections.singletonList(supportedMediaType));
|
setSupportedMediaTypes(Collections.singletonList(supportedMediaType));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a new instance with the provided {@link ObjectMapper} and {@link MediaType}s.
|
* Construct a new instance with the provided {@link ObjectMapper} and {@link MediaType}s.
|
||||||
*/
|
*/
|
||||||
protected AbstractJacksonHttpMessageConverter(ObjectMapper objectMapper, MediaType... supportedMediaTypes) {
|
protected AbstractJacksonHttpMessageConverter(T mapper, MediaType... supportedMediaTypes) {
|
||||||
this(objectMapper);
|
this(mapper);
|
||||||
setSupportedMediaTypes(Arrays.asList(supportedMediaTypes));
|
setSupportedMediaTypes(Arrays.asList(supportedMediaTypes));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,19 +185,19 @@ public abstract class AbstractJacksonHttpMessageConverter extends AbstractSmartH
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the main {@code ObjectMapper} in use.
|
* Return the main {@link ObjectMapper} in use.
|
||||||
*/
|
*/
|
||||||
public ObjectMapper getObjectMapper() {
|
public T getMapper() {
|
||||||
return this.defaultObjectMapper;
|
return this.defaultMapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configure the {@link ObjectMapper} instances to use for the given
|
* Configure the {@link ObjectMapper} instances to use for the given
|
||||||
* {@link Class}. This is useful when you want to deviate from the
|
* {@link Class}. This is useful when you want to deviate from the
|
||||||
* {@link #getObjectMapper() default} ObjectMapper or have the
|
* {@link #getMapper() default} ObjectMapper or have the
|
||||||
* {@code ObjectMapper} vary by {@code MediaType}.
|
* {@code ObjectMapper} vary by {@code MediaType}.
|
||||||
* <p><strong>Note:</strong> Use of this method effectively turns off use of
|
* <p><strong>Note:</strong> Use of this method effectively turns off use of
|
||||||
* the default {@link #getObjectMapper() ObjectMapper} and
|
* the default {@link #getMapper() ObjectMapper} and
|
||||||
* {@link #setSupportedMediaTypes(List) supportedMediaTypes} for the given
|
* {@link #setSupportedMediaTypes(List) supportedMediaTypes} for the given
|
||||||
* class. Therefore it is important for the mappings configured here to
|
* class. Therefore it is important for the mappings configured here to
|
||||||
* {@link MediaType#includes(MediaType) include} every MediaType that must
|
* {@link MediaType#includes(MediaType) include} every MediaType that must
|
||||||
|
@ -205,12 +206,12 @@ public abstract class AbstractJacksonHttpMessageConverter extends AbstractSmartH
|
||||||
* @param registrar a consumer to populate or otherwise update the
|
* @param registrar a consumer to populate or otherwise update the
|
||||||
* MediaType-to-ObjectMapper associations for the given Class
|
* MediaType-to-ObjectMapper associations for the given Class
|
||||||
*/
|
*/
|
||||||
public void registerObjectMappersForType(Class<?> clazz, Consumer<Map<MediaType, ObjectMapper>> registrar) {
|
public void registerMappersForType(Class<?> clazz, Consumer<Map<MediaType, T>> registrar) {
|
||||||
if (this.objectMapperRegistrations == null) {
|
if (this.mapperRegistrations == null) {
|
||||||
this.objectMapperRegistrations = new LinkedHashMap<>();
|
this.mapperRegistrations = new LinkedHashMap<>();
|
||||||
}
|
}
|
||||||
Map<MediaType, ObjectMapper> registrations =
|
Map<MediaType, T> registrations =
|
||||||
this.objectMapperRegistrations.computeIfAbsent(clazz, c -> new LinkedHashMap<>());
|
this.mapperRegistrations.computeIfAbsent(clazz, c -> new LinkedHashMap<>());
|
||||||
registrar.accept(registrations);
|
registrar.accept(registrations);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -220,8 +221,8 @@ public abstract class AbstractJacksonHttpMessageConverter extends AbstractSmartH
|
||||||
* @return a map with registered MediaType-to-ObjectMapper registrations,
|
* @return a map with registered MediaType-to-ObjectMapper registrations,
|
||||||
* or empty if in case of no registrations for the given class.
|
* or empty if in case of no registrations for the given class.
|
||||||
*/
|
*/
|
||||||
public Map<MediaType, ObjectMapper> getObjectMappersForType(Class<?> clazz) {
|
public Map<MediaType, T> getMappersForType(Class<?> clazz) {
|
||||||
for (Map.Entry<Class<?>, Map<MediaType, ObjectMapper>> entry : getObjectMapperRegistrations().entrySet()) {
|
for (Map.Entry<Class<?>, Map<MediaType, T>> entry : getMapperRegistrations().entrySet()) {
|
||||||
if (entry.getKey().isAssignableFrom(clazz)) {
|
if (entry.getKey().isAssignableFrom(clazz)) {
|
||||||
return entry.getValue();
|
return entry.getValue();
|
||||||
}
|
}
|
||||||
|
@ -232,7 +233,7 @@ public abstract class AbstractJacksonHttpMessageConverter extends AbstractSmartH
|
||||||
@Override
|
@Override
|
||||||
public List<MediaType> getSupportedMediaTypes(Class<?> clazz) {
|
public List<MediaType> getSupportedMediaTypes(Class<?> clazz) {
|
||||||
List<MediaType> result = null;
|
List<MediaType> result = null;
|
||||||
for (Map.Entry<Class<?>, Map<MediaType, ObjectMapper>> entry : getObjectMapperRegistrations().entrySet()) {
|
for (Map.Entry<Class<?>, Map<MediaType, T>> entry : getMapperRegistrations().entrySet()) {
|
||||||
if (entry.getKey().isAssignableFrom(clazz)) {
|
if (entry.getKey().isAssignableFrom(clazz)) {
|
||||||
result = (result != null ? result : new ArrayList<>(entry.getValue().size()));
|
result = (result != null ? result : new ArrayList<>(entry.getValue().size()));
|
||||||
result.addAll(entry.getValue().keySet());
|
result.addAll(entry.getValue().keySet());
|
||||||
|
@ -245,8 +246,8 @@ public abstract class AbstractJacksonHttpMessageConverter extends AbstractSmartH
|
||||||
getMediaTypesForProblemDetail() : getSupportedMediaTypes());
|
getMediaTypesForProblemDetail() : getSupportedMediaTypes());
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<Class<?>, Map<MediaType, ObjectMapper>> getObjectMapperRegistrations() {
|
private Map<Class<?>, Map<MediaType, T>> getMapperRegistrations() {
|
||||||
return (this.objectMapperRegistrations != null ? this.objectMapperRegistrations : Collections.emptyMap());
|
return (this.mapperRegistrations != null ? this.mapperRegistrations : Collections.emptyMap());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -267,7 +268,7 @@ public abstract class AbstractJacksonHttpMessageConverter extends AbstractSmartH
|
||||||
if (clazz == null) {
|
if (clazz == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return this.objectMapperRegistrations == null || selectObjectMapper(clazz, mediaType) != null;
|
return this.mapperRegistrations == null || selectMapper(clazz, mediaType) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -285,23 +286,23 @@ public abstract class AbstractJacksonHttpMessageConverter extends AbstractSmartH
|
||||||
if (MappingJacksonValue.class.isAssignableFrom(clazz)) {
|
if (MappingJacksonValue.class.isAssignableFrom(clazz)) {
|
||||||
throw new UnsupportedOperationException("MappingJacksonValue is not supported, use hints instead");
|
throw new UnsupportedOperationException("MappingJacksonValue is not supported, use hints instead");
|
||||||
}
|
}
|
||||||
return this.objectMapperRegistrations == null || selectObjectMapper(clazz, mediaType) != null;
|
return this.mapperRegistrations == null || selectMapper(clazz, mediaType) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Select an ObjectMapper to use, either the main ObjectMapper or another
|
* Select an ObjectMapper to use, either the main ObjectMapper or another
|
||||||
* if the handling for the given Class has been customized through
|
* if the handling for the given Class has been customized through
|
||||||
* {@link #registerObjectMappersForType(Class, Consumer)}.
|
* {@link #registerMappersForType(Class, Consumer)}.
|
||||||
*/
|
*/
|
||||||
private @Nullable ObjectMapper selectObjectMapper(Class<?> targetType, @Nullable MediaType targetMediaType) {
|
private @Nullable T selectMapper(Class<?> targetType, @Nullable MediaType targetMediaType) {
|
||||||
if (targetMediaType == null || CollectionUtils.isEmpty(this.objectMapperRegistrations)) {
|
if (targetMediaType == null || CollectionUtils.isEmpty(this.mapperRegistrations)) {
|
||||||
return this.defaultObjectMapper;
|
return this.defaultMapper;
|
||||||
}
|
}
|
||||||
for (Map.Entry<Class<?>, Map<MediaType, ObjectMapper>> typeEntry : getObjectMapperRegistrations().entrySet()) {
|
for (Map.Entry<Class<?>, Map<MediaType, T>> typeEntry : getMapperRegistrations().entrySet()) {
|
||||||
if (typeEntry.getKey().isAssignableFrom(targetType)) {
|
if (typeEntry.getKey().isAssignableFrom(targetType)) {
|
||||||
for (Map.Entry<MediaType, ObjectMapper> objectMapperEntry : typeEntry.getValue().entrySet()) {
|
for (Map.Entry<MediaType, T> mapperEntry : typeEntry.getValue().entrySet()) {
|
||||||
if (objectMapperEntry.getKey().includes(targetMediaType)) {
|
if (mapperEntry.getKey().includes(targetMediaType)) {
|
||||||
return objectMapperEntry.getValue();
|
return mapperEntry.getValue();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// No matching registrations
|
// No matching registrations
|
||||||
|
@ -309,7 +310,7 @@ public abstract class AbstractJacksonHttpMessageConverter extends AbstractSmartH
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// No registrations
|
// No registrations
|
||||||
return this.defaultObjectMapper;
|
return this.defaultMapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -334,8 +335,8 @@ public abstract class AbstractJacksonHttpMessageConverter extends AbstractSmartH
|
||||||
MediaType contentType = inputMessage.getHeaders().getContentType();
|
MediaType contentType = inputMessage.getHeaders().getContentType();
|
||||||
Charset charset = getCharset(contentType);
|
Charset charset = getCharset(contentType);
|
||||||
|
|
||||||
ObjectMapper objectMapper = selectObjectMapper(javaType.getRawClass(), contentType);
|
T mapper = selectMapper(javaType.getRawClass(), contentType);
|
||||||
Assert.state(objectMapper != null, () -> "No ObjectMapper for " + javaType);
|
Assert.state(mapper != null, () -> "No ObjectMapper for " + javaType);
|
||||||
|
|
||||||
boolean isUnicode = ENCODINGS.containsKey(charset.name()) ||
|
boolean isUnicode = ENCODINGS.containsKey(charset.name()) ||
|
||||||
"UTF-16".equals(charset.name()) ||
|
"UTF-16".equals(charset.name()) ||
|
||||||
|
@ -345,7 +346,7 @@ public abstract class AbstractJacksonHttpMessageConverter extends AbstractSmartH
|
||||||
if (inputMessage instanceof MappingJacksonInputMessage) {
|
if (inputMessage instanceof MappingJacksonInputMessage) {
|
||||||
throw new UnsupportedOperationException("MappingJacksonInputMessage is not supported, use hints instead");
|
throw new UnsupportedOperationException("MappingJacksonInputMessage is not supported, use hints instead");
|
||||||
}
|
}
|
||||||
ObjectReader objectReader = objectMapper.readerFor(javaType);
|
ObjectReader objectReader = mapper.readerFor(javaType);
|
||||||
if (hints != null && hints.containsKey(JSON_VIEW_HINT)) {
|
if (hints != null && hints.containsKey(JSON_VIEW_HINT)) {
|
||||||
objectReader = objectReader.withView((Class<?>) hints.get(JSON_VIEW_HINT));
|
objectReader = objectReader.withView((Class<?>) hints.get(JSON_VIEW_HINT));
|
||||||
}
|
}
|
||||||
|
@ -401,8 +402,8 @@ public abstract class AbstractJacksonHttpMessageConverter extends AbstractSmartH
|
||||||
JsonEncoding encoding = getJsonEncoding(contentType);
|
JsonEncoding encoding = getJsonEncoding(contentType);
|
||||||
|
|
||||||
Class<?> clazz = object.getClass();
|
Class<?> clazz = object.getClass();
|
||||||
ObjectMapper objectMapper = selectObjectMapper(clazz, contentType);
|
T mapper = selectMapper(clazz, contentType);
|
||||||
Assert.state(objectMapper != null, () -> "No ObjectMapper for " + clazz.getName());
|
Assert.state(mapper != null, () -> "No ObjectMapper for " + clazz.getName());
|
||||||
|
|
||||||
OutputStream outputStream = StreamUtils.nonClosing(outputMessage.getBody());
|
OutputStream outputStream = StreamUtils.nonClosing(outputMessage.getBody());
|
||||||
Class<?> jsonView = null;
|
Class<?> jsonView = null;
|
||||||
|
@ -419,7 +420,7 @@ public abstract class AbstractJacksonHttpMessageConverter extends AbstractSmartH
|
||||||
}
|
}
|
||||||
|
|
||||||
ObjectWriter objectWriter = (jsonView != null ?
|
ObjectWriter objectWriter = (jsonView != null ?
|
||||||
objectMapper.writerWithView(jsonView) : objectMapper.writer());
|
mapper.writerWithView(jsonView) : mapper.writer());
|
||||||
if (filters != null) {
|
if (filters != null) {
|
||||||
objectWriter = objectWriter.with(filters);
|
objectWriter = objectWriter.with(filters);
|
||||||
}
|
}
|
||||||
|
@ -485,7 +486,7 @@ public abstract class AbstractJacksonHttpMessageConverter extends AbstractSmartH
|
||||||
* @return the Jackson JavaType
|
* @return the Jackson JavaType
|
||||||
*/
|
*/
|
||||||
protected JavaType getJavaType(Type type, @Nullable Class<?> contextClass) {
|
protected JavaType getJavaType(Type type, @Nullable Class<?> contextClass) {
|
||||||
return this.defaultObjectMapper.constructType(GenericTypeResolver.resolveType(type, contextClass));
|
return this.defaultMapper.constructType(GenericTypeResolver.resolveType(type, contextClass));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -38,7 +38,7 @@ import org.springframework.http.converter.AbstractJacksonHttpMessageConverter;
|
||||||
* @author Sebastien Deleuze
|
* @author Sebastien Deleuze
|
||||||
* @since 7.0
|
* @since 7.0
|
||||||
*/
|
*/
|
||||||
public class JacksonCborHttpMessageConverter extends AbstractJacksonHttpMessageConverter {
|
public class JacksonCborHttpMessageConverter extends AbstractJacksonHttpMessageConverter<CBORMapper> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a new instance with a {@link CBORMapper} customized with the
|
* Construct a new instance with a {@link CBORMapper} customized with the
|
||||||
|
|
|
@ -21,7 +21,6 @@ import java.util.List;
|
||||||
|
|
||||||
import org.jspecify.annotations.Nullable;
|
import org.jspecify.annotations.Nullable;
|
||||||
import tools.jackson.core.JsonGenerator;
|
import tools.jackson.core.JsonGenerator;
|
||||||
import tools.jackson.databind.ObjectMapper;
|
|
||||||
import tools.jackson.databind.cfg.MapperBuilder;
|
import tools.jackson.databind.cfg.MapperBuilder;
|
||||||
import tools.jackson.databind.json.JsonMapper;
|
import tools.jackson.databind.json.JsonMapper;
|
||||||
|
|
||||||
|
@ -32,7 +31,7 @@ import org.springframework.http.converter.AbstractJacksonHttpMessageConverter;
|
||||||
/**
|
/**
|
||||||
* Implementation of {@link org.springframework.http.converter.HttpMessageConverter}
|
* Implementation of {@link org.springframework.http.converter.HttpMessageConverter}
|
||||||
* that can read and write JSON using <a href="https://github.com/FasterXML/jackson">Jackson 3.x's</a>
|
* that can read and write JSON using <a href="https://github.com/FasterXML/jackson">Jackson 3.x's</a>
|
||||||
* {@link ObjectMapper}.
|
* {@link JsonMapper}.
|
||||||
*
|
*
|
||||||
* <p>This converter can be used to bind to typed beans, or untyped
|
* <p>This converter can be used to bind to typed beans, or untyped
|
||||||
* {@code HashMap} instances.
|
* {@code HashMap} instances.
|
||||||
|
@ -56,7 +55,7 @@ import org.springframework.http.converter.AbstractJacksonHttpMessageConverter;
|
||||||
* @author Sebastien Deleuze
|
* @author Sebastien Deleuze
|
||||||
* @since 7.0
|
* @since 7.0
|
||||||
*/
|
*/
|
||||||
public class JacksonJsonHttpMessageConverter extends AbstractJacksonHttpMessageConverter {
|
public class JacksonJsonHttpMessageConverter extends AbstractJacksonHttpMessageConverter<JsonMapper> {
|
||||||
|
|
||||||
private static final List<MediaType> problemDetailMediaTypes =
|
private static final List<MediaType> problemDetailMediaTypes =
|
||||||
Collections.singletonList(MediaType.APPLICATION_PROBLEM_JSON);
|
Collections.singletonList(MediaType.APPLICATION_PROBLEM_JSON);
|
||||||
|
@ -79,11 +78,11 @@ public class JacksonJsonHttpMessageConverter extends AbstractJacksonHttpMessageC
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a new instance with the provided {@link ObjectMapper}.
|
* Construct a new instance with the provided {@link JsonMapper}.
|
||||||
* @see JsonMapper#builder()
|
* @see JsonMapper#builder()
|
||||||
* @see MapperBuilder#findModules(ClassLoader)
|
* @see MapperBuilder#findModules(ClassLoader)
|
||||||
*/
|
*/
|
||||||
public JacksonJsonHttpMessageConverter(ObjectMapper objectMapper) {
|
public JacksonJsonHttpMessageConverter(JsonMapper objectMapper) {
|
||||||
super(objectMapper, DEFAULT_JSON_MIME_TYPES);
|
super(objectMapper, DEFAULT_JSON_MIME_TYPES);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,7 @@ import org.springframework.http.converter.AbstractJacksonHttpMessageConverter;
|
||||||
* @author Sebastien Deleuze
|
* @author Sebastien Deleuze
|
||||||
* @since 7.0
|
* @since 7.0
|
||||||
*/
|
*/
|
||||||
public class JacksonSmileHttpMessageConverter extends AbstractJacksonHttpMessageConverter {
|
public class JacksonSmileHttpMessageConverter extends AbstractJacksonHttpMessageConverter<SmileMapper> {
|
||||||
|
|
||||||
private static final MediaType DEFAULT_SMILE_MIME_TYPES = new MediaType("application", "x-jackson-smile");
|
private static final MediaType DEFAULT_SMILE_MIME_TYPES = new MediaType("application", "x-jackson-smile");
|
||||||
|
|
||||||
|
|
|
@ -53,7 +53,7 @@ import org.springframework.util.xml.StaxUtils;
|
||||||
* @author Sebastien Deleuze
|
* @author Sebastien Deleuze
|
||||||
* @since 7.0
|
* @since 7.0
|
||||||
*/
|
*/
|
||||||
public class JacksonXmlHttpMessageConverter extends AbstractJacksonHttpMessageConverter {
|
public class JacksonXmlHttpMessageConverter extends AbstractJacksonHttpMessageConverter<XmlMapper> {
|
||||||
|
|
||||||
private static final List<MediaType> problemDetailMediaTypes =
|
private static final List<MediaType> problemDetailMediaTypes =
|
||||||
Collections.singletonList(MediaType.APPLICATION_PROBLEM_XML);
|
Collections.singletonList(MediaType.APPLICATION_PROBLEM_XML);
|
||||||
|
|
|
@ -38,7 +38,7 @@ import org.springframework.http.converter.AbstractJacksonHttpMessageConverter;
|
||||||
* @author Sebastien Deleuze
|
* @author Sebastien Deleuze
|
||||||
* @since 7.0
|
* @since 7.0
|
||||||
*/
|
*/
|
||||||
public class JacksonYamlHttpMessageConverter extends AbstractJacksonHttpMessageConverter {
|
public class JacksonYamlHttpMessageConverter extends AbstractJacksonHttpMessageConverter<YAMLMapper> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a new instance with a {@link YAMLMapper} customized with the
|
* Construct a new instance with a {@link YAMLMapper} customized with the
|
||||||
|
|
|
@ -31,7 +31,6 @@ import reactor.test.StepVerifier;
|
||||||
import tools.jackson.core.JsonParser;
|
import tools.jackson.core.JsonParser;
|
||||||
import tools.jackson.databind.DeserializationContext;
|
import tools.jackson.databind.DeserializationContext;
|
||||||
import tools.jackson.databind.JsonNode;
|
import tools.jackson.databind.JsonNode;
|
||||||
import tools.jackson.databind.ObjectMapper;
|
|
||||||
import tools.jackson.databind.annotation.JsonDeserialize;
|
import tools.jackson.databind.annotation.JsonDeserialize;
|
||||||
import tools.jackson.databind.deser.std.StdDeserializer;
|
import tools.jackson.databind.deser.std.StdDeserializer;
|
||||||
import tools.jackson.databind.json.JsonMapper;
|
import tools.jackson.databind.json.JsonMapper;
|
||||||
|
@ -101,9 +100,9 @@ class JacksonJsonDecoderTests extends AbstractDecoderTests<JacksonJsonDecoder> {
|
||||||
assertThat(decoder.canDecode(ResolvableType.forClass(Pojo.class), halFormsJsonMediaType)).isTrue();
|
assertThat(decoder.canDecode(ResolvableType.forClass(Pojo.class), halFormsJsonMediaType)).isTrue();
|
||||||
assertThat(decoder.canDecode(ResolvableType.forClass(Map.class), MediaType.APPLICATION_JSON)).isTrue();
|
assertThat(decoder.canDecode(ResolvableType.forClass(Map.class), MediaType.APPLICATION_JSON)).isTrue();
|
||||||
|
|
||||||
decoder.registerObjectMappersForType(Pojo.class, map -> {
|
decoder.registerMappersForType(Pojo.class, map -> {
|
||||||
map.put(halJsonMediaType, new ObjectMapper());
|
map.put(halJsonMediaType, new JsonMapper());
|
||||||
map.put(MediaType.APPLICATION_JSON, new ObjectMapper());
|
map.put(MediaType.APPLICATION_JSON, new JsonMapper());
|
||||||
});
|
});
|
||||||
|
|
||||||
assertThat(decoder.canDecode(ResolvableType.forClass(Pojo.class), halJsonMediaType)).isTrue();
|
assertThat(decoder.canDecode(ResolvableType.forClass(Pojo.class), halJsonMediaType)).isTrue();
|
||||||
|
@ -115,7 +114,7 @@ class JacksonJsonDecoderTests extends AbstractDecoderTests<JacksonJsonDecoder> {
|
||||||
@Test // SPR-15866
|
@Test // SPR-15866
|
||||||
void canDecodeWithProvidedMimeType() {
|
void canDecodeWithProvidedMimeType() {
|
||||||
MimeType textJavascript = new MimeType("text", "javascript", StandardCharsets.UTF_8);
|
MimeType textJavascript = new MimeType("text", "javascript", StandardCharsets.UTF_8);
|
||||||
JacksonJsonDecoder decoder = new JacksonJsonDecoder(new ObjectMapper(), textJavascript);
|
JacksonJsonDecoder decoder = new JacksonJsonDecoder(new JsonMapper(), textJavascript);
|
||||||
|
|
||||||
assertThat(decoder.getDecodableMimeTypes()).isEqualTo(Collections.singletonList(textJavascript));
|
assertThat(decoder.getDecodableMimeTypes()).isEqualTo(Collections.singletonList(textJavascript));
|
||||||
}
|
}
|
||||||
|
@ -124,7 +123,7 @@ class JacksonJsonDecoderTests extends AbstractDecoderTests<JacksonJsonDecoder> {
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
void decodableMimeTypesIsImmutable() {
|
void decodableMimeTypesIsImmutable() {
|
||||||
MimeType textJavascript = new MimeType("text", "javascript", StandardCharsets.UTF_8);
|
MimeType textJavascript = new MimeType("text", "javascript", StandardCharsets.UTF_8);
|
||||||
JacksonJsonDecoder decoder = new JacksonJsonDecoder(new ObjectMapper(), textJavascript);
|
JacksonJsonDecoder decoder = new JacksonJsonDecoder(new JsonMapper(), textJavascript);
|
||||||
|
|
||||||
assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(() ->
|
assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(() ->
|
||||||
decoder.getDecodableMimeTypes().add(new MimeType("text", "ecmascript")));
|
decoder.getDecodableMimeTypes().add(new MimeType("text", "ecmascript")));
|
||||||
|
@ -135,8 +134,8 @@ class JacksonJsonDecoderTests extends AbstractDecoderTests<JacksonJsonDecoder> {
|
||||||
MimeType mimeType1 = MediaType.parseMediaType("application/hal+json");
|
MimeType mimeType1 = MediaType.parseMediaType("application/hal+json");
|
||||||
MimeType mimeType2 = new MimeType("text", "javascript", StandardCharsets.UTF_8);
|
MimeType mimeType2 = new MimeType("text", "javascript", StandardCharsets.UTF_8);
|
||||||
|
|
||||||
JacksonJsonDecoder decoder = new JacksonJsonDecoder(new ObjectMapper(), mimeType2);
|
JacksonJsonDecoder decoder = new JacksonJsonDecoder(new JsonMapper(), mimeType2);
|
||||||
decoder.registerObjectMappersForType(Pojo.class, map -> map.put(mimeType1, new ObjectMapper()));
|
decoder.registerMappersForType(Pojo.class, map -> map.put(mimeType1, new JsonMapper()));
|
||||||
|
|
||||||
assertThat(decoder.getDecodableMimeTypes(ResolvableType.forClass(Pojo.class)))
|
assertThat(decoder.getDecodableMimeTypes(ResolvableType.forClass(Pojo.class)))
|
||||||
.containsExactly(mimeType1);
|
.containsExactly(mimeType1);
|
||||||
|
|
|
@ -28,7 +28,6 @@ import org.junit.jupiter.api.Test;
|
||||||
import reactor.core.publisher.Flux;
|
import reactor.core.publisher.Flux;
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
import reactor.test.StepVerifier;
|
import reactor.test.StepVerifier;
|
||||||
import tools.jackson.databind.ObjectMapper;
|
|
||||||
import tools.jackson.databind.SerializationFeature;
|
import tools.jackson.databind.SerializationFeature;
|
||||||
import tools.jackson.databind.json.JsonMapper;
|
import tools.jackson.databind.json.JsonMapper;
|
||||||
|
|
||||||
|
@ -109,7 +108,7 @@ class JacksonJsonEncoderTests extends AbstractEncoderTests<JacksonJsonEncoder> {
|
||||||
@Test // SPR-15866
|
@Test // SPR-15866
|
||||||
public void canEncodeWithCustomMimeType() {
|
public void canEncodeWithCustomMimeType() {
|
||||||
MimeType textJavascript = new MimeType("text", "javascript", StandardCharsets.UTF_8);
|
MimeType textJavascript = new MimeType("text", "javascript", StandardCharsets.UTF_8);
|
||||||
JacksonJsonEncoder encoder = new JacksonJsonEncoder(new ObjectMapper(), textJavascript);
|
JacksonJsonEncoder encoder = new JacksonJsonEncoder(new JsonMapper(), textJavascript);
|
||||||
|
|
||||||
assertThat(encoder.getEncodableMimeTypes()).isEqualTo(Collections.singletonList(textJavascript));
|
assertThat(encoder.getEncodableMimeTypes()).isEqualTo(Collections.singletonList(textJavascript));
|
||||||
}
|
}
|
||||||
|
@ -117,7 +116,7 @@ class JacksonJsonEncoderTests extends AbstractEncoderTests<JacksonJsonEncoder> {
|
||||||
@Test
|
@Test
|
||||||
void encodableMimeTypesIsImmutable() {
|
void encodableMimeTypesIsImmutable() {
|
||||||
MimeType textJavascript = new MimeType("text", "javascript", StandardCharsets.UTF_8);
|
MimeType textJavascript = new MimeType("text", "javascript", StandardCharsets.UTF_8);
|
||||||
JacksonJsonEncoder encoder = new JacksonJsonEncoder(new ObjectMapper(), textJavascript);
|
JacksonJsonEncoder encoder = new JacksonJsonEncoder(new JsonMapper(), textJavascript);
|
||||||
|
|
||||||
assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(() ->
|
assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(() ->
|
||||||
encoder.getEncodableMimeTypes().add(new MimeType("text", "ecmascript")));
|
encoder.getEncodableMimeTypes().add(new MimeType("text", "ecmascript")));
|
||||||
|
@ -231,7 +230,7 @@ class JacksonJsonEncoderTests extends AbstractEncoderTests<JacksonJsonEncoder> {
|
||||||
|
|
||||||
@Test // gh-22771
|
@Test // gh-22771
|
||||||
public void encodeWithFlushAfterWriteOff() {
|
public void encodeWithFlushAfterWriteOff() {
|
||||||
ObjectMapper mapper = JsonMapper.builder().configure(SerializationFeature.FLUSH_AFTER_WRITE_VALUE, false).build();
|
JsonMapper mapper = JsonMapper.builder().configure(SerializationFeature.FLUSH_AFTER_WRITE_VALUE, false).build();
|
||||||
JacksonJsonEncoder encoder = new JacksonJsonEncoder(mapper);
|
JacksonJsonEncoder encoder = new JacksonJsonEncoder(mapper);
|
||||||
|
|
||||||
Flux<DataBuffer> result = encoder.encode(Flux.just(new Pojo("foo", "bar")), this.bufferFactory,
|
Flux<DataBuffer> result = encoder.encode(Flux.just(new Pojo("foo", "bar")), this.bufferFactory,
|
||||||
|
|
|
@ -87,9 +87,9 @@ class JacksonJsonHttpMessageConverterTests {
|
||||||
assertThat(converter.canRead(MyBean.class, halFormsJsonMediaType)).isTrue();
|
assertThat(converter.canRead(MyBean.class, halFormsJsonMediaType)).isTrue();
|
||||||
assertThat(converter.canRead(Map.class, MediaType.APPLICATION_JSON)).isTrue();
|
assertThat(converter.canRead(Map.class, MediaType.APPLICATION_JSON)).isTrue();
|
||||||
|
|
||||||
converter.registerObjectMappersForType(MyBean.class, map -> {
|
converter.registerMappersForType(MyBean.class, map -> {
|
||||||
map.put(halJsonMediaType, new ObjectMapper());
|
map.put(halJsonMediaType, new JsonMapper());
|
||||||
map.put(MediaType.APPLICATION_JSON, new ObjectMapper());
|
map.put(MediaType.APPLICATION_JSON, new JsonMapper());
|
||||||
});
|
});
|
||||||
|
|
||||||
assertThat(converter.canRead(MyBean.class, halJsonMediaType)).isTrue();
|
assertThat(converter.canRead(MyBean.class, halJsonMediaType)).isTrue();
|
||||||
|
@ -121,9 +121,9 @@ class JacksonJsonHttpMessageConverterTests {
|
||||||
assertThat(converter.getSupportedMediaTypes(MyBean.class)).containsExactly(defaultMediaTypes);
|
assertThat(converter.getSupportedMediaTypes(MyBean.class)).containsExactly(defaultMediaTypes);
|
||||||
|
|
||||||
MediaType halJson = MediaType.parseMediaType("application/hal+json");
|
MediaType halJson = MediaType.parseMediaType("application/hal+json");
|
||||||
converter.registerObjectMappersForType(MyBean.class, map -> {
|
converter.registerMappersForType(MyBean.class, map -> {
|
||||||
map.put(halJson, new ObjectMapper());
|
map.put(halJson, new JsonMapper());
|
||||||
map.put(MediaType.APPLICATION_JSON, new ObjectMapper());
|
map.put(MediaType.APPLICATION_JSON, new JsonMapper());
|
||||||
});
|
});
|
||||||
|
|
||||||
assertThat(converter.getSupportedMediaTypes(MyBean.class)).containsExactly(halJson, MediaType.APPLICATION_JSON);
|
assertThat(converter.getSupportedMediaTypes(MyBean.class)).containsExactly(halJson, MediaType.APPLICATION_JSON);
|
||||||
|
@ -365,7 +365,7 @@ class JacksonJsonHttpMessageConverterTests {
|
||||||
PrettyPrintBean bean = new PrettyPrintBean();
|
PrettyPrintBean bean = new PrettyPrintBean();
|
||||||
bean.setName("Jason");
|
bean.setName("Jason");
|
||||||
|
|
||||||
ObjectMapper mapper = JsonMapper.builder().enable(SerializationFeature.INDENT_OUTPUT).build();
|
JsonMapper mapper = JsonMapper.builder().enable(SerializationFeature.INDENT_OUTPUT).build();
|
||||||
this.converter = new JacksonJsonHttpMessageConverter(mapper);
|
this.converter = new JacksonJsonHttpMessageConverter(mapper);
|
||||||
this.converter.write(bean, ResolvableType.forType(PrettyPrintBean.class),
|
this.converter.write(bean, ResolvableType.forType(PrettyPrintBean.class),
|
||||||
MediaType.APPLICATION_JSON, outputMessage, null);
|
MediaType.APPLICATION_JSON, outputMessage, null);
|
||||||
|
@ -384,7 +384,7 @@ class JacksonJsonHttpMessageConverterTests {
|
||||||
PrettyPrintBean bean = new PrettyPrintBean();
|
PrettyPrintBean bean = new PrettyPrintBean();
|
||||||
bean.setName("Jason");
|
bean.setName("Jason");
|
||||||
|
|
||||||
ObjectMapper mapper = JsonMapper.builder().enable(SerializationFeature.INDENT_OUTPUT).build();
|
JsonMapper mapper = JsonMapper.builder().enable(SerializationFeature.INDENT_OUTPUT).build();
|
||||||
this.converter = new JacksonJsonHttpMessageConverter(mapper);
|
this.converter = new JacksonJsonHttpMessageConverter(mapper);
|
||||||
this.converter.write(bean, ResolvableType.forType(PrettyPrintBean.class),
|
this.converter.write(bean, ResolvableType.forType(PrettyPrintBean.class),
|
||||||
MediaType.APPLICATION_JSON, outputMessage, null);
|
MediaType.APPLICATION_JSON, outputMessage, null);
|
||||||
|
|
|
@ -27,11 +27,11 @@ import static org.mockito.Mockito.mock;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unit tests for {@link HttpServiceProxyFactory}.
|
* Unit tests for {@link HttpServiceProxyFactory}.
|
||||||
|
*
|
||||||
* @author Rossen Stoyanchev
|
* @author Rossen Stoyanchev
|
||||||
*/
|
*/
|
||||||
public class HttpServiceProxyFactoryTests {
|
public class HttpServiceProxyFactoryTests {
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void httpExchangeAdapterDecorator() {
|
void httpExchangeAdapterDecorator() {
|
||||||
|
|
||||||
|
@ -44,7 +44,6 @@ public class HttpServiceProxyFactoryTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private interface Service {
|
private interface Service {
|
||||||
|
|
||||||
@GetExchange
|
@GetExchange
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
|
|
||||||
package org.springframework.web.service.registry;
|
package org.springframework.web.service.registry;
|
||||||
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
@ -37,6 +36,7 @@ import static org.mockito.Mockito.mock;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unit tests for {@link AbstractClientHttpServiceRegistrar}.
|
* Unit tests for {@link AbstractClientHttpServiceRegistrar}.
|
||||||
|
*
|
||||||
* @author Rossen Stoyanchev
|
* @author Rossen Stoyanchev
|
||||||
*/
|
*/
|
||||||
public class ClientHttpServiceRegistrarTests {
|
public class ClientHttpServiceRegistrarTests {
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
|
|
||||||
package org.springframework.web.service.registry;
|
package org.springframework.web.service.registry;
|
||||||
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
@ -53,4 +52,5 @@ record TestGroup(
|
||||||
group.packageClasses().addAll(Arrays.asList(packageClasses));
|
group.packageClasses().addAll(Arrays.asList(packageClasses));
|
||||||
return group;
|
return group;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
|
|
||||||
package org.springframework.web.service.registry;
|
package org.springframework.web.service.registry;
|
||||||
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -76,4 +75,5 @@ class TestGroupRegistry implements GroupRegistry {
|
||||||
return this.groupMap.computeIfAbsent(this.groupName, name -> new TestGroup(name, this.clientType));
|
return this.groupMap.computeIfAbsent(this.groupName, name -> new TestGroup(name, this.clientType));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
|
|
||||||
package org.springframework.web.service.registry.basic;
|
package org.springframework.web.service.registry.basic;
|
||||||
|
|
||||||
|
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
import org.springframework.web.service.annotation.GetExchange;
|
import org.springframework.web.service.annotation.GetExchange;
|
||||||
import org.springframework.web.service.registry.HttpServiceClient;
|
import org.springframework.web.service.registry.HttpServiceClient;
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
|
|
||||||
package org.springframework.web.service.registry.echo;
|
package org.springframework.web.service.registry.echo;
|
||||||
|
|
||||||
|
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
import org.springframework.web.service.annotation.GetExchange;
|
import org.springframework.web.service.annotation.GetExchange;
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
|
|
||||||
package org.springframework.web.service.registry.echo;
|
package org.springframework.web.service.registry.echo;
|
||||||
|
|
||||||
|
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
import org.springframework.web.service.annotation.GetExchange;
|
import org.springframework.web.service.annotation.GetExchange;
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
|
|
||||||
package org.springframework.web.service.registry.echo;
|
package org.springframework.web.service.registry.echo;
|
||||||
|
|
||||||
|
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
import org.springframework.web.service.annotation.GetExchange;
|
import org.springframework.web.service.annotation.GetExchange;
|
||||||
import org.springframework.web.service.registry.HttpServiceClient;
|
import org.springframework.web.service.registry.HttpServiceClient;
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
|
|
||||||
package org.springframework.web.service.registry.echo;
|
package org.springframework.web.service.registry.echo;
|
||||||
|
|
||||||
|
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
import org.springframework.web.service.annotation.GetExchange;
|
import org.springframework.web.service.annotation.GetExchange;
|
||||||
import org.springframework.web.service.registry.HttpServiceClient;
|
import org.springframework.web.service.registry.HttpServiceClient;
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
|
|
||||||
package org.springframework.web.service.registry.greeting;
|
package org.springframework.web.service.registry.greeting;
|
||||||
|
|
||||||
|
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
import org.springframework.web.service.annotation.GetExchange;
|
import org.springframework.web.service.annotation.GetExchange;
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
|
|
||||||
package org.springframework.web.service.registry.greeting;
|
package org.springframework.web.service.registry.greeting;
|
||||||
|
|
||||||
|
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
import org.springframework.web.service.annotation.GetExchange;
|
import org.springframework.web.service.annotation.GetExchange;
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,6 @@ import org.junit.jupiter.api.Test;
|
||||||
import reactor.core.publisher.Flux;
|
import reactor.core.publisher.Flux;
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
import reactor.test.StepVerifier;
|
import reactor.test.StepVerifier;
|
||||||
import tools.jackson.databind.ObjectMapper;
|
|
||||||
import tools.jackson.databind.SerializationFeature;
|
import tools.jackson.databind.SerializationFeature;
|
||||||
import tools.jackson.databind.json.JsonMapper;
|
import tools.jackson.databind.json.JsonMapper;
|
||||||
|
|
||||||
|
@ -439,10 +438,10 @@ class ResponseEntityResultHandlerTests {
|
||||||
MediaType halFormsMediaType = MediaType.parseMediaType("application/prs.hal-forms+json");
|
MediaType halFormsMediaType = MediaType.parseMediaType("application/prs.hal-forms+json");
|
||||||
MediaType halMediaType = MediaType.parseMediaType("application/hal+json");
|
MediaType halMediaType = MediaType.parseMediaType("application/hal+json");
|
||||||
|
|
||||||
ObjectMapper objectMapper = JsonMapper.builder().enable(SerializationFeature.INDENT_OUTPUT).build();
|
JsonMapper jsonMapper = JsonMapper.builder().enable(SerializationFeature.INDENT_OUTPUT).build();
|
||||||
|
|
||||||
JacksonJsonEncoder encoder = new JacksonJsonEncoder();
|
JacksonJsonEncoder encoder = new JacksonJsonEncoder();
|
||||||
encoder.registerObjectMappersForType(Person.class, map -> map.put(halMediaType, objectMapper));
|
encoder.registerMappersForType(Person.class, map -> map.put(halMediaType, jsonMapper));
|
||||||
EncoderHttpMessageWriter<?> writer = new EncoderHttpMessageWriter<>(encoder);
|
EncoderHttpMessageWriter<?> writer = new EncoderHttpMessageWriter<>(encoder);
|
||||||
|
|
||||||
ResponseEntityResultHandler handler = new ResponseEntityResultHandler(
|
ResponseEntityResultHandler handler = new ResponseEntityResultHandler(
|
||||||
|
|
|
@ -24,7 +24,6 @@ import java.util.Set;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import org.jspecify.annotations.Nullable;
|
import org.jspecify.annotations.Nullable;
|
||||||
import tools.jackson.core.JsonGenerator;
|
import tools.jackson.core.JsonGenerator;
|
||||||
import tools.jackson.databind.ObjectMapper;
|
|
||||||
import tools.jackson.databind.cfg.MapperBuilder;
|
import tools.jackson.databind.cfg.MapperBuilder;
|
||||||
import tools.jackson.databind.json.JsonMapper;
|
import tools.jackson.databind.json.JsonMapper;
|
||||||
|
|
||||||
|
@ -35,7 +34,7 @@ import org.springframework.web.servlet.view.AbstractJacksonView;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Spring MVC {@link View} that renders JSON content by serializing the model for the current request
|
* Spring MVC {@link View} that renders JSON content by serializing the model for the current request
|
||||||
* using <a href="https://github.com/FasterXML/jackson">Jackson 3's</a> {@link ObjectMapper}.
|
* using <a href="https://github.com/FasterXML/jackson">Jackson 3's</a> {@link JsonMapper}.
|
||||||
*
|
*
|
||||||
* <p>By default, the entire contents of the model map (with the exception of framework-specific classes)
|
* <p>By default, the entire contents of the model map (with the exception of framework-specific classes)
|
||||||
* will be encoded as JSON. If the model contains only one key, you can have it extracted encoded as JSON
|
* will be encoded as JSON. If the model contains only one key, you can have it extracted encoded as JSON
|
||||||
|
@ -79,11 +78,11 @@ public class JacksonJsonView extends AbstractJacksonView {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a new instance using the provided {@link ObjectMapper}
|
* Construct a new instance using the provided {@link JsonMapper}
|
||||||
* and setting the content type to {@value #DEFAULT_CONTENT_TYPE}.
|
* and setting the content type to {@value #DEFAULT_CONTENT_TYPE}.
|
||||||
*/
|
*/
|
||||||
public JacksonJsonView(ObjectMapper objectMapper) {
|
public JacksonJsonView(JsonMapper jsonMapper) {
|
||||||
super(objectMapper, DEFAULT_CONTENT_TYPE);
|
super(jsonMapper, DEFAULT_CONTENT_TYPE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import tools.jackson.databind.DeserializationFeature;
|
import tools.jackson.databind.DeserializationFeature;
|
||||||
import tools.jackson.databind.MapperFeature;
|
import tools.jackson.databind.MapperFeature;
|
||||||
import tools.jackson.databind.ObjectMapper;
|
import tools.jackson.databind.json.JsonMapper;
|
||||||
|
|
||||||
import org.springframework.beans.DirectFieldAccessor;
|
import org.springframework.beans.DirectFieldAccessor;
|
||||||
import org.springframework.beans.testfixture.beans.TestBean;
|
import org.springframework.beans.testfixture.beans.TestBean;
|
||||||
|
@ -214,10 +214,10 @@ class WebMvcConfigurationSupportExtensionTests {
|
||||||
assertThat(converters.get(0).getClass()).isEqualTo(StringHttpMessageConverter.class);
|
assertThat(converters.get(0).getClass()).isEqualTo(StringHttpMessageConverter.class);
|
||||||
assertThat(converters.get(1).getClass()).isEqualTo(AllEncompassingFormHttpMessageConverter.class);
|
assertThat(converters.get(1).getClass()).isEqualTo(AllEncompassingFormHttpMessageConverter.class);
|
||||||
assertThat(converters.get(2).getClass()).isEqualTo(JacksonJsonHttpMessageConverter.class);
|
assertThat(converters.get(2).getClass()).isEqualTo(JacksonJsonHttpMessageConverter.class);
|
||||||
ObjectMapper objectMapper = ((JacksonJsonHttpMessageConverter) converters.get(2)).getObjectMapper();
|
JsonMapper jsonMapper = ((JacksonJsonHttpMessageConverter) converters.get(2)).getMapper();
|
||||||
assertThat(objectMapper.deserializationConfig().isEnabled(MapperFeature.DEFAULT_VIEW_INCLUSION)).isFalse();
|
assertThat(jsonMapper.deserializationConfig().isEnabled(MapperFeature.DEFAULT_VIEW_INCLUSION)).isFalse();
|
||||||
assertThat(objectMapper.deserializationConfig().isEnabled(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)).isFalse();
|
assertThat(jsonMapper.deserializationConfig().isEnabled(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)).isFalse();
|
||||||
assertThat(objectMapper.serializationConfig().isEnabled(MapperFeature.DEFAULT_VIEW_INCLUSION)).isFalse();
|
assertThat(jsonMapper.serializationConfig().isEnabled(MapperFeature.DEFAULT_VIEW_INCLUSION)).isFalse();
|
||||||
|
|
||||||
DirectFieldAccessor fieldAccessor = new DirectFieldAccessor(adapter);
|
DirectFieldAccessor fieldAccessor = new DirectFieldAccessor(adapter);
|
||||||
|
|
||||||
|
|
|
@ -181,7 +181,7 @@ class WebMvcConfigurationSupportTests {
|
||||||
.filter(AbstractJacksonHttpMessageConverter.class::isInstance)
|
.filter(AbstractJacksonHttpMessageConverter.class::isInstance)
|
||||||
.map(AbstractJacksonHttpMessageConverter.class::cast)
|
.map(AbstractJacksonHttpMessageConverter.class::cast)
|
||||||
.forEach(converter -> {
|
.forEach(converter -> {
|
||||||
ObjectMapper mapper = converter.getObjectMapper();
|
ObjectMapper mapper = converter.getMapper();
|
||||||
assertThat(mapper.deserializationConfig().isEnabled(MapperFeature.DEFAULT_VIEW_INCLUSION)).isFalse();
|
assertThat(mapper.deserializationConfig().isEnabled(MapperFeature.DEFAULT_VIEW_INCLUSION)).isFalse();
|
||||||
assertThat(mapper.deserializationConfig().isEnabled(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)).isFalse();
|
assertThat(mapper.deserializationConfig().isEnabled(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)).isFalse();
|
||||||
assertThat(mapper.serializationConfig().isEnabled(MapperFeature.DEFAULT_VIEW_INCLUSION)).isFalse();
|
assertThat(mapper.serializationConfig().isEnabled(MapperFeature.DEFAULT_VIEW_INCLUSION)).isFalse();
|
||||||
|
|
|
@ -24,7 +24,6 @@ import java.util.List;
|
||||||
|
|
||||||
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 tools.jackson.databind.ObjectMapper;
|
|
||||||
import tools.jackson.databind.SerializationFeature;
|
import tools.jackson.databind.SerializationFeature;
|
||||||
import tools.jackson.databind.json.JsonMapper;
|
import tools.jackson.databind.json.JsonMapper;
|
||||||
|
|
||||||
|
@ -109,8 +108,8 @@ class SseServerResponseTests {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
ObjectMapper objectMapper = JsonMapper.builder().enable(SerializationFeature.INDENT_OUTPUT).build();
|
JsonMapper jsonMapper = JsonMapper.builder().enable(SerializationFeature.INDENT_OUTPUT).build();
|
||||||
JacksonJsonHttpMessageConverter converter = new JacksonJsonHttpMessageConverter(objectMapper);
|
JacksonJsonHttpMessageConverter converter = new JacksonJsonHttpMessageConverter(jsonMapper);
|
||||||
ServerResponse.Context context = () -> List.of(converter);
|
ServerResponse.Context context = () -> List.of(converter);
|
||||||
|
|
||||||
ModelAndView mav = response.writeTo(this.mockRequest, this.mockResponse, context);
|
ModelAndView mav = response.writeTo(this.mockRequest, this.mockResponse, context);
|
||||||
|
|
|
@ -338,7 +338,7 @@ class RequestResponseBodyMethodProcessorTests {
|
||||||
simpleBean.setName("Jason");
|
simpleBean.setName("Jason");
|
||||||
|
|
||||||
JacksonJsonHttpMessageConverter converter = new JacksonJsonHttpMessageConverter();
|
JacksonJsonHttpMessageConverter converter = new JacksonJsonHttpMessageConverter();
|
||||||
converter.registerObjectMappersForType(SimpleBean.class, map -> map.put(halMediaType, mapper));
|
converter.registerMappersForType(SimpleBean.class, map -> map.put(halMediaType, mapper));
|
||||||
RequestResponseBodyMethodProcessor processor =
|
RequestResponseBodyMethodProcessor processor =
|
||||||
new RequestResponseBodyMethodProcessor(List.of(converter));
|
new RequestResponseBodyMethodProcessor(List.of(converter));
|
||||||
MethodParameter returnType = new MethodParameter(getClass().getDeclaredMethod("getSimpleBean"), -1);
|
MethodParameter returnType = new MethodParameter(getClass().getDeclaredMethod("getSimpleBean"), -1);
|
||||||
|
|
|
@ -33,7 +33,6 @@ import tools.jackson.core.JacksonException;
|
||||||
import tools.jackson.core.JsonGenerator;
|
import tools.jackson.core.JsonGenerator;
|
||||||
import tools.jackson.databind.BeanDescription;
|
import tools.jackson.databind.BeanDescription;
|
||||||
import tools.jackson.databind.JavaType;
|
import tools.jackson.databind.JavaType;
|
||||||
import tools.jackson.databind.ObjectMapper;
|
|
||||||
import tools.jackson.databind.SerializationContext;
|
import tools.jackson.databind.SerializationContext;
|
||||||
import tools.jackson.databind.SerializationFeature;
|
import tools.jackson.databind.SerializationFeature;
|
||||||
import tools.jackson.databind.ValueSerializer;
|
import tools.jackson.databind.ValueSerializer;
|
||||||
|
@ -181,7 +180,7 @@ class JacksonJsonViewTests {
|
||||||
@Test
|
@Test
|
||||||
void renderWithCustomSerializerLocatedByFactory() throws Exception {
|
void renderWithCustomSerializerLocatedByFactory() throws Exception {
|
||||||
SerializerFactory factory = new DelegatingSerializerFactory(null);
|
SerializerFactory factory = new DelegatingSerializerFactory(null);
|
||||||
ObjectMapper mapper = JsonMapper.builder().serializerFactory(factory).build();
|
JsonMapper mapper = JsonMapper.builder().serializerFactory(factory).build();
|
||||||
view = new JacksonJsonView(mapper);
|
view = new JacksonJsonView(mapper);
|
||||||
|
|
||||||
Object bean = new TestBeanSimple();
|
Object bean = new TestBeanSimple();
|
||||||
|
|
|
@ -20,7 +20,6 @@ import java.io.InputStream;
|
||||||
|
|
||||||
import org.jspecify.annotations.Nullable;
|
import org.jspecify.annotations.Nullable;
|
||||||
import tools.jackson.core.io.JsonStringEncoder;
|
import tools.jackson.core.io.JsonStringEncoder;
|
||||||
import tools.jackson.databind.ObjectMapper;
|
|
||||||
import tools.jackson.databind.cfg.MapperBuilder;
|
import tools.jackson.databind.cfg.MapperBuilder;
|
||||||
import tools.jackson.databind.json.JsonMapper;
|
import tools.jackson.databind.json.JsonMapper;
|
||||||
|
|
||||||
|
@ -37,7 +36,7 @@ import org.springframework.util.Assert;
|
||||||
*/
|
*/
|
||||||
public class JacksonJsonSockJsMessageCodec extends AbstractSockJsMessageCodec {
|
public class JacksonJsonSockJsMessageCodec extends AbstractSockJsMessageCodec {
|
||||||
|
|
||||||
private final ObjectMapper objectMapper;
|
private final JsonMapper jsonMapper;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -46,28 +45,28 @@ public class JacksonJsonSockJsMessageCodec extends AbstractSockJsMessageCodec {
|
||||||
* {@link MapperBuilder#findModules(ClassLoader)}.
|
* {@link MapperBuilder#findModules(ClassLoader)}.
|
||||||
*/
|
*/
|
||||||
public JacksonJsonSockJsMessageCodec() {
|
public JacksonJsonSockJsMessageCodec() {
|
||||||
this.objectMapper = JsonMapper.builder().findAndAddModules(JacksonJsonSockJsMessageCodec.class.getClassLoader()).build();
|
this.jsonMapper = JsonMapper.builder().findAndAddModules(JacksonJsonSockJsMessageCodec.class.getClassLoader()).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a new instance with the provided {@link ObjectMapper}.
|
* Construct a new instance with the provided {@link JsonMapper}.
|
||||||
* @see JsonMapper#builder()
|
* @see JsonMapper#builder()
|
||||||
* @see MapperBuilder#findAndAddModules(ClassLoader)
|
* @see MapperBuilder#findAndAddModules(ClassLoader)
|
||||||
*/
|
*/
|
||||||
public JacksonJsonSockJsMessageCodec(ObjectMapper objectMapper) {
|
public JacksonJsonSockJsMessageCodec(JsonMapper jsonMapper) {
|
||||||
Assert.notNull(objectMapper, "ObjectMapper must not be null");
|
Assert.notNull(jsonMapper, "JsonMapper must not be null");
|
||||||
this.objectMapper = objectMapper;
|
this.jsonMapper = jsonMapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String @Nullable [] decode(String content) {
|
public String @Nullable [] decode(String content) {
|
||||||
return this.objectMapper.readValue(content, String[].class);
|
return this.jsonMapper.readValue(content, String[].class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String @Nullable [] decodeInputStream(InputStream content) {
|
public String @Nullable [] decodeInputStream(InputStream content) {
|
||||||
return this.objectMapper.readValue(content, String[].class);
|
return this.jsonMapper.readValue(content, String[].class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
Loading…
Reference in New Issue