Add web support for Yaml via Jackson

This commit adds support for application/yaml in MediaType and leverages
jackson-dataformat-yaml in order to support Yaml in RestTemplate,
RestClient and Spring MVC.

See gh-32345
This commit is contained in:
Hyoungjune
2024-02-29 16:26:26 +09:00
committed by Sébastien Deleuze
parent 246e4977a2
commit 6a8f0d6d7d
11 changed files with 177 additions and 2 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -21,6 +21,7 @@ import java.util.Properties;
import com.fasterxml.jackson.dataformat.cbor.CBORFactory;
import com.fasterxml.jackson.dataformat.smile.SmileFactory;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import org.w3c.dom.Element;
import org.springframework.beans.factory.FactoryBean;
@@ -55,6 +56,7 @@ import org.springframework.http.converter.smile.MappingJackson2SmileHttpMessageC
import org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter;
import org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter;
import org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter;
import org.springframework.http.converter.yaml.MappingJackson2YamlHttpMessageConverter;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
@@ -148,6 +150,7 @@ import org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolv
* @author Rossen Stoyanchev
* @author Brian Clozel
* @author Agim Emruli
* @author Hyoungjune Kim
* @since 3.0
*/
class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
@@ -173,6 +176,8 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
private static final boolean jackson2CborPresent;
private static final boolean jackson2YamlPresent;
private static final boolean gsonPresent;
static {
@@ -185,6 +190,7 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
jackson2XmlPresent = ClassUtils.isPresent("com.fasterxml.jackson.dataformat.xml.XmlMapper", classLoader);
jackson2SmilePresent = ClassUtils.isPresent("com.fasterxml.jackson.dataformat.smile.SmileFactory", classLoader);
jackson2CborPresent = ClassUtils.isPresent("com.fasterxml.jackson.dataformat.cbor.CBORFactory", classLoader);
jackson2YamlPresent = ClassUtils.isPresent("com.fasterxml.jackson.dataformat.yaml.YAMLFactory", classLoader);
gsonPresent = ClassUtils.isPresent("com.google.gson.Gson", classLoader);
}
@@ -463,6 +469,9 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
if (jackson2CborPresent) {
defaultMediaTypes.put("cbor", MediaType.APPLICATION_CBOR_VALUE);
}
if (jackson2YamlPresent) {
defaultMediaTypes.put("yaml", MediaType.APPLICATION_YAML_VALE);
}
return defaultMediaTypes;
}
@@ -614,6 +623,14 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
jacksonConverterDef.getConstructorArgumentValues().addIndexedArgumentValue(0, jacksonFactoryDef);
messageConverters.add(jacksonConverterDef);
}
if(jackson2YamlPresent) {
Class<?> type = MappingJackson2YamlHttpMessageConverter.class;
RootBeanDefinition jacksonConverterDef = createConverterDefinition(type, source);
GenericBeanDefinition jacksonFactoryDef = createObjectMapperFactoryDefinition(source);
jacksonFactoryDef.getPropertyValues().add("factory", new RootBeanDefinition(YAMLFactory.class));
jacksonConverterDef.getConstructorArgumentValues().addIndexedArgumentValue(0, jacksonFactoryDef);
messageConverters.add(jacksonConverterDef);
}
}
return messageConverters;
}

View File

@@ -58,6 +58,7 @@ import org.springframework.http.converter.smile.MappingJackson2SmileHttpMessageC
import org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter;
import org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter;
import org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter;
import org.springframework.http.converter.yaml.MappingJackson2YamlHttpMessageConverter;
import org.springframework.lang.Nullable;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.Assert;
@@ -183,6 +184,7 @@ import org.springframework.web.util.pattern.PathPatternParser;
* @author Rossen Stoyanchev
* @author Brian Clozel
* @author Sebastien Deleuze
* @author Hyoungjune Kim
* @since 3.1
* @see EnableWebMvc
* @see WebMvcConfigurer
@@ -201,6 +203,8 @@ public class WebMvcConfigurationSupport implements ApplicationContextAware, Serv
private static final boolean jackson2CborPresent;
private static final boolean jackson2YamlPresent;
private static final boolean gsonPresent;
private static final boolean jsonbPresent;
@@ -220,6 +224,7 @@ public class WebMvcConfigurationSupport implements ApplicationContextAware, Serv
jackson2XmlPresent = ClassUtils.isPresent("com.fasterxml.jackson.dataformat.xml.XmlMapper", classLoader);
jackson2SmilePresent = ClassUtils.isPresent("com.fasterxml.jackson.dataformat.smile.SmileFactory", classLoader);
jackson2CborPresent = ClassUtils.isPresent("com.fasterxml.jackson.dataformat.cbor.CBORFactory", classLoader);
jackson2YamlPresent = ClassUtils.isPresent("com.fasterxml.jackson.dataformat.yaml.YAMLFactory", classLoader);
gsonPresent = ClassUtils.isPresent("com.google.gson.Gson", classLoader);
jsonbPresent = ClassUtils.isPresent("jakarta.json.bind.Jsonb", classLoader);
kotlinSerializationCborPresent = ClassUtils.isPresent("kotlinx.serialization.cbor.Cbor", classLoader);
@@ -467,6 +472,9 @@ public class WebMvcConfigurationSupport implements ApplicationContextAware, Serv
if (jackson2CborPresent || kotlinSerializationCborPresent) {
map.put("cbor", MediaType.APPLICATION_CBOR);
}
if (jackson2YamlPresent) {
map.put("yaml", MediaType.APPLICATION_YAML);
}
return map;
}
@@ -940,6 +948,13 @@ public class WebMvcConfigurationSupport implements ApplicationContextAware, Serv
}
messageConverters.add(new MappingJackson2CborHttpMessageConverter(builder.build()));
}
if (jackson2YamlPresent) {
Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.yaml();
if (this.applicationContext != null) {
builder.applicationContext(this.applicationContext);
}
messageConverters.add(new MappingJackson2YamlHttpMessageConverter(builder.build()));
}
}
/**