Add Jsonb support
Spring Framework 5 will support Jsonb as a HttpMessageConverter, this commit adds auto-configuration support. Also, support for Jsonb in the @JsonTest has been added. This implementation is running against Apache Johnzon See gh-9648
This commit is contained in:
committed by
Stephane Nicoll
parent
676dec8cf7
commit
97aeaa4a32
@@ -23,6 +23,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.autoconfigure.condition.NoneNestedConditions;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@@ -33,6 +34,7 @@ import org.springframework.http.converter.json.MappingJackson2HttpMessageConvert
|
||||
* Configuration for HTTP Message converters that use Gson.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @author Eddú Meléndez
|
||||
* @since 1.2.2
|
||||
*/
|
||||
@Configuration
|
||||
@@ -41,7 +43,7 @@ class GsonHttpMessageConvertersConfiguration {
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnBean(Gson.class)
|
||||
@Conditional(PreferGsonOrMissingJacksonCondition.class)
|
||||
@Conditional(PreferGsonOrMissingJacksonAndJsonbCondition.class)
|
||||
protected static class GsonHttpMessageConverterConfiguration {
|
||||
|
||||
@Bean
|
||||
@@ -54,9 +56,9 @@ class GsonHttpMessageConvertersConfiguration {
|
||||
|
||||
}
|
||||
|
||||
private static class PreferGsonOrMissingJacksonCondition extends AnyNestedCondition {
|
||||
private static class PreferGsonOrMissingJacksonAndJsonbCondition extends AnyNestedCondition {
|
||||
|
||||
PreferGsonOrMissingJacksonCondition() {
|
||||
PreferGsonOrMissingJacksonAndJsonbCondition() {
|
||||
super(ConfigurationPhase.REGISTER_BEAN);
|
||||
}
|
||||
|
||||
@@ -65,11 +67,29 @@ class GsonHttpMessageConvertersConfiguration {
|
||||
|
||||
}
|
||||
|
||||
@ConditionalOnMissingBean(MappingJackson2HttpMessageConverter.class)
|
||||
@Conditional(JacksonAndJsonbMissing.class)
|
||||
static class JacksonJsonbMissing {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class JacksonAndJsonbMissing extends NoneNestedConditions {
|
||||
|
||||
JacksonAndJsonbMissing() {
|
||||
super(ConfigurationPhase.REGISTER_BEAN);
|
||||
}
|
||||
|
||||
@ConditionalOnBean(MappingJackson2HttpMessageConverter.class)
|
||||
static class JacksonMissing {
|
||||
|
||||
}
|
||||
|
||||
@ConditionalOnProperty(name = HttpMessageConvertersAutoConfiguration.PREFERRED_MAPPER_PROPERTY, havingValue = "jsonb")
|
||||
static class JsonbMissing {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.jsonb.JsonbAutoConfiguration;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@@ -44,12 +45,15 @@ import org.springframework.http.converter.StringHttpMessageConverter;
|
||||
* @author Andy Wilkinson
|
||||
* @author Sebastien Deleuze
|
||||
* @author Stephane Nicoll
|
||||
* @author Eddú Meléndez
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnClass(HttpMessageConverter.class)
|
||||
@AutoConfigureAfter({ GsonAutoConfiguration.class, JacksonAutoConfiguration.class })
|
||||
@AutoConfigureAfter({ GsonAutoConfiguration.class, JacksonAutoConfiguration.class,
|
||||
JsonbAutoConfiguration.class })
|
||||
@Import({ JacksonHttpMessageConvertersConfiguration.class,
|
||||
GsonHttpMessageConvertersConfiguration.class })
|
||||
GsonHttpMessageConvertersConfiguration.class,
|
||||
JsonbHttpMessageConvertersConfiguration.class })
|
||||
public class HttpMessageConvertersAutoConfiguration {
|
||||
|
||||
static final String PREFERRED_MAPPER_PROPERTY = "spring.http.converters.preferred-json-mapper";
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.autoconfigure.http;
|
||||
|
||||
import javax.json.bind.Jsonb;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.AnyNestedCondition;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.autoconfigure.condition.NoneNestedConditions;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.converter.json.JsonbHttpMessageConverter;
|
||||
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
|
||||
|
||||
/**
|
||||
* Configuration for HTTP Message converters that use JSON-B.
|
||||
*
|
||||
* @author Eddú Meléndez
|
||||
* @author 2.0.0
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnClass(Jsonb.class)
|
||||
class JsonbHttpMessageConvertersConfiguration {
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnBean(Jsonb.class)
|
||||
@Conditional(PreferJsonbOrMissingJacksonAndGsonCondition.class)
|
||||
protected static class JsonbHttpMessageConverterConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public JsonbHttpMessageConverter jsonbHttpMessageConverter(Jsonb jsonb) {
|
||||
JsonbHttpMessageConverter converter = new JsonbHttpMessageConverter();
|
||||
converter.setJsonb(jsonb);
|
||||
return converter;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class PreferJsonbOrMissingJacksonAndGsonCondition extends AnyNestedCondition {
|
||||
|
||||
PreferJsonbOrMissingJacksonAndGsonCondition() {
|
||||
super(ConfigurationPhase.REGISTER_BEAN);
|
||||
}
|
||||
|
||||
@ConditionalOnProperty(name = HttpMessageConvertersAutoConfiguration.PREFERRED_MAPPER_PROPERTY, havingValue = "jsonb", matchIfMissing = false)
|
||||
static class JsonbPreferred {
|
||||
|
||||
}
|
||||
|
||||
@Conditional(JacksonAndGsonMissing.class)
|
||||
static class JacksonGsonMissing {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class JacksonAndGsonMissing extends NoneNestedConditions {
|
||||
|
||||
JacksonAndGsonMissing() {
|
||||
super(ConfigurationPhase.REGISTER_BEAN);
|
||||
}
|
||||
|
||||
@ConditionalOnBean(MappingJackson2HttpMessageConverter.class)
|
||||
static class JacksonMissing {
|
||||
|
||||
}
|
||||
|
||||
@ConditionalOnProperty(name = HttpMessageConvertersAutoConfiguration.PREFERRED_MAPPER_PROPERTY, havingValue = "gson")
|
||||
static class GsonMissing {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.autoconfigure.jsonb;
|
||||
|
||||
import javax.json.bind.Jsonb;
|
||||
import javax.json.bind.JsonbBuilder;
|
||||
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for JSON-B.
|
||||
*
|
||||
* @author Eddú Meléndez
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnClass(Jsonb.class)
|
||||
public class JsonbAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public Jsonb jsonb() {
|
||||
return JsonbBuilder.create();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Auto-configuration for JSON-B.
|
||||
*/
|
||||
package org.springframework.boot.autoconfigure.jsonb;
|
||||
@@ -1362,6 +1362,9 @@
|
||||
},
|
||||
{
|
||||
"value": "jackson"
|
||||
},
|
||||
{
|
||||
"value": "jsonb"
|
||||
}
|
||||
],
|
||||
"providers": [
|
||||
|
||||
@@ -80,6 +80,7 @@ org.springframework.boot.autoconfigure.jms.artemis.ArtemisAutoConfiguration,\
|
||||
org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAutoConfiguration,\
|
||||
org.springframework.boot.autoconfigure.jersey.JerseyAutoConfiguration,\
|
||||
org.springframework.boot.autoconfigure.jooq.JooqAutoConfiguration,\
|
||||
org.springframework.boot.autoconfigure.jsonb.JsonbAutoConfiguration,\
|
||||
org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration,\
|
||||
org.springframework.boot.autoconfigure.ldap.embedded.EmbeddedLdapAutoConfiguration,\
|
||||
org.springframework.boot.autoconfigure.ldap.LdapAutoConfiguration,\
|
||||
|
||||
@@ -19,6 +19,8 @@ package org.springframework.boot.autoconfigure.http;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import javax.json.bind.Jsonb;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.google.gson.Gson;
|
||||
import org.junit.After;
|
||||
@@ -28,6 +30,7 @@ import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.http.JacksonHttpMessageConvertersConfiguration.MappingJackson2HttpMessageConverterConfiguration;
|
||||
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.jsonb.JsonbAutoConfiguration;
|
||||
import org.springframework.boot.test.util.TestPropertyValues;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
@@ -38,6 +41,7 @@ import org.springframework.hateoas.mvc.TypeConstrainedMappingJackson2HttpMessage
|
||||
import org.springframework.http.converter.StringHttpMessageConverter;
|
||||
import org.springframework.http.converter.json.GsonHttpMessageConverter;
|
||||
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
|
||||
import org.springframework.http.converter.json.JsonbHttpMessageConverter;
|
||||
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
|
||||
import org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter;
|
||||
|
||||
@@ -51,6 +55,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
* @author David Liu
|
||||
* @author Andy Wilkinson
|
||||
* @author Sebastien Deleuze
|
||||
* @author Eddú Meléndez
|
||||
*/
|
||||
public class HttpMessageConvertersAutoConfigurationTests {
|
||||
|
||||
@@ -140,19 +145,20 @@ public class HttpMessageConvertersAutoConfigurationTests {
|
||||
@Test
|
||||
public void jacksonIsPreferredByDefaultWhenBothGsonAndJacksonAreAvailable() {
|
||||
this.context.register(GsonAutoConfiguration.class, JacksonAutoConfiguration.class,
|
||||
HttpMessageConvertersAutoConfiguration.class);
|
||||
JsonbAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class);
|
||||
this.context.refresh();
|
||||
assertConverterBeanExists(MappingJackson2HttpMessageConverter.class,
|
||||
"mappingJackson2HttpMessageConverter");
|
||||
assertConverterBeanRegisteredWithHttpMessageConverters(
|
||||
MappingJackson2HttpMessageConverter.class);
|
||||
assertThat(this.context.getBeansOfType(GsonHttpMessageConverter.class)).isEmpty();
|
||||
assertThat(this.context.getBeansOfType(JsonbHttpMessageConverter.class)).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void gsonCanBePreferredWhenBothGsonAndJacksonAreAvailable() {
|
||||
this.context.register(GsonAutoConfiguration.class, JacksonAutoConfiguration.class,
|
||||
HttpMessageConvertersAutoConfiguration.class);
|
||||
JsonbAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class);
|
||||
TestPropertyValues.of("spring.http.converters.preferred-json-mapper:gson")
|
||||
.applyTo(this.context);
|
||||
this.context.refresh();
|
||||
@@ -160,6 +166,8 @@ public class HttpMessageConvertersAutoConfigurationTests {
|
||||
"gsonHttpMessageConverter");
|
||||
assertConverterBeanRegisteredWithHttpMessageConverters(
|
||||
GsonHttpMessageConverter.class);
|
||||
assertThat(this.context.getBeansOfType(JsonbHttpMessageConverter.class))
|
||||
.isEmpty();
|
||||
assertThat(this.context.getBeansOfType(MappingJackson2HttpMessageConverter.class))
|
||||
.isEmpty();
|
||||
}
|
||||
@@ -176,6 +184,55 @@ public class HttpMessageConvertersAutoConfigurationTests {
|
||||
GsonHttpMessageConverter.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noJsonb() throws Exception {
|
||||
this.context.register(HttpMessageConvertersAutoConfiguration.class);
|
||||
this.context.refresh();
|
||||
assertThat(this.context.getBeansOfType(Jsonb.class).isEmpty()).isTrue();
|
||||
assertThat(this.context.getBeansOfType(JsonbHttpMessageConverter.class).isEmpty())
|
||||
.isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void defaultJsonbConverter() throws Exception {
|
||||
this.context.register(JsonbAutoConfiguration.class,
|
||||
HttpMessageConvertersAutoConfiguration.class);
|
||||
this.context.refresh();
|
||||
assertConverterBeanExists(JsonbHttpMessageConverter.class,
|
||||
"jsonbHttpMessageConverter");
|
||||
|
||||
assertConverterBeanRegisteredWithHttpMessageConverters(
|
||||
JsonbHttpMessageConverter.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void jsonbCanBePreferredWhenBothGsonAndJacksonAreAvailable() {
|
||||
this.context.register(GsonAutoConfiguration.class, JacksonAutoConfiguration.class,
|
||||
JsonbAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class);
|
||||
TestPropertyValues.of("spring.http.converters.preferred-json-mapper:jsonb")
|
||||
.applyTo(this.context);
|
||||
this.context.refresh();
|
||||
assertConverterBeanExists(JsonbHttpMessageConverter.class,
|
||||
"jsonbHttpMessageConverter");
|
||||
assertConverterBeanRegisteredWithHttpMessageConverters(
|
||||
JsonbHttpMessageConverter.class);
|
||||
assertThat(this.context.getBeansOfType(GsonHttpMessageConverter.class))
|
||||
.isEmpty();
|
||||
assertThat(this.context.getBeansOfType(MappingJackson2HttpMessageConverter.class))
|
||||
.isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void customJsonbConverter() throws Exception {
|
||||
this.context.register(JsonbAutoConfiguration.class, JsonbConverterConfig.class,
|
||||
HttpMessageConvertersAutoConfiguration.class);
|
||||
this.context.refresh();
|
||||
assertConverterBeanExists(JsonbHttpMessageConverter.class,
|
||||
"customJsonbMessageConverter");
|
||||
assertConverterBeanRegisteredWithHttpMessageConverters(
|
||||
JsonbHttpMessageConverter.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void defaultStringConverter() throws Exception {
|
||||
this.context.register(HttpMessageConvertersAutoConfiguration.class);
|
||||
@@ -288,6 +345,18 @@ public class HttpMessageConvertersAutoConfigurationTests {
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
protected static class JsonbConverterConfig {
|
||||
|
||||
@Bean
|
||||
public JsonbHttpMessageConverter customJsonbMessageConverter(Jsonb jsonb) {
|
||||
JsonbHttpMessageConverter converter = new JsonbHttpMessageConverter();
|
||||
converter.setJsonb(jsonb);
|
||||
return converter;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
protected static class StringConverterConfig {
|
||||
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.autoconfigure.jsonb;
|
||||
|
||||
import javax.json.bind.Jsonb;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link JsonbAutoConfiguration}.
|
||||
*
|
||||
* @author Eddú Meléndez
|
||||
*/
|
||||
public class JsonbAutoConfigurationTests {
|
||||
|
||||
AnnotationConfigApplicationContext context;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
this.context = new AnnotationConfigApplicationContext();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
if (this.context != null) {
|
||||
this.context.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void jsonbRegistration() {
|
||||
this.context.register(JsonbAutoConfiguration.class);
|
||||
this.context.refresh();
|
||||
Jsonb jsonb = this.context.getBean(Jsonb.class);
|
||||
assertThat(jsonb.toJson(new DataObject())).isEqualTo("{\"data\":\"hello\"}");
|
||||
}
|
||||
|
||||
public class DataObject {
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private String data = "hello";
|
||||
|
||||
public String getData() {
|
||||
return this.data;
|
||||
}
|
||||
|
||||
public void setData(String data) {
|
||||
this.data = data;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user