From 1b284a06193c95353a48197f860b45cd6698a80e Mon Sep 17 00:00:00 2001 From: Dave Syer Date: Mon, 12 May 2014 15:03:12 +0100 Subject: [PATCH] Add RelaxedDataSourceFactory --- .../jdbc/RelaxedDataSourceFactory.java | 78 +++++++++++ .../jdbc/JsonSerializationTests.java | 128 ++++++++++++++++++ 2 files changed, 206 insertions(+) create mode 100644 spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/RelaxedDataSourceFactory.java create mode 100644 spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/JsonSerializationTests.java diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/RelaxedDataSourceFactory.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/RelaxedDataSourceFactory.java new file mode 100644 index 00000000000..81fb1715a4b --- /dev/null +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/RelaxedDataSourceFactory.java @@ -0,0 +1,78 @@ +/* + * Copyright 2012-2013 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.jdbc; + +import javax.sql.DataSource; + +import org.springframework.beans.BeanUtils; +import org.springframework.boot.bind.PropertySourcesPropertyValues; +import org.springframework.boot.bind.RelaxedDataBinder; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.util.ClassUtils; + +/** + * @author Dave Syer + */ +public class RelaxedDataSourceFactory { + + private static final String[] DATA_SOURCE_TYPE_NAMES = new String[] { + "com.zaxxer.hikari.HikariDataSource", + "org.apache.tomcat.jdbc.pool.DataSource", + "org.apache.commons.dbcp.BasicDataSource" }; + + private Class type; + + private ConfigurableEnvironment environment; + + public static RelaxedDataSourceFactory create(ConfigurableEnvironment environment) { + return new RelaxedDataSourceFactory(environment); + } + + public RelaxedDataSourceFactory(ConfigurableEnvironment environment) { + this.environment = environment; + } + + public DataSource build(String prefix) { + Class type = getType(); + DataSource result = BeanUtils.instantiate(type); + RelaxedDataBinder binder = new RelaxedDataBinder(result, prefix); + binder.bind(new PropertySourcesPropertyValues(this.environment + .getPropertySources())); + return result; + } + + public RelaxedDataSourceFactory type(Class type) { + this.type = type; + return this; + } + + private Class getType() { + if (this.type != null) { + return this.type; + } + for (String name : DATA_SOURCE_TYPE_NAMES) { + if (ClassUtils.isPresent(name, null)) { + @SuppressWarnings("unchecked") + Class resolved = (Class) ClassUtils + .resolveClassName(name, null); + return resolved; + } + } + throw new IllegalStateException("No supported DataSource type found"); + } + +} diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/JsonSerializationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/JsonSerializationTests.java new file mode 100644 index 00000000000..0e5607cbad3 --- /dev/null +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/JsonSerializationTests.java @@ -0,0 +1,128 @@ +/* + * Copyright 2012-2013 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.jdbc; + +import java.beans.PropertyDescriptor; +import java.io.IOException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; + +import org.apache.tomcat.jdbc.pool.DataSource; +import org.junit.Test; +import org.springframework.beans.BeanUtils; +import org.springframework.core.convert.ConversionService; +import org.springframework.core.convert.support.DefaultConversionService; +import org.springframework.util.ReflectionUtils; +import org.springframework.util.StringUtils; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.BeanDescription; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationConfig; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.databind.introspect.AnnotatedMethod; +import com.fasterxml.jackson.databind.ser.BeanPropertyWriter; +import com.fasterxml.jackson.databind.ser.BeanSerializerFactory; +import com.fasterxml.jackson.databind.ser.BeanSerializerModifier; +import com.fasterxml.jackson.databind.ser.SerializerFactory; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +/** + * @author Dave Syer + */ +public class JsonSerializationTests { + + @Test + public void serializerFactory() throws Exception { + DataSource dataSource = new DataSource(); + SerializerFactory factory = BeanSerializerFactory.instance + .withSerializerModifier(new GenericSerializerModifier()); + ObjectMapper mapper = new ObjectMapper(); + mapper.setSerializerFactory(factory); + String value = mapper.writeValueAsString(dataSource); + assertTrue(value.contains("\"url\":")); + } + + @Test + public void serializerWithMixin() throws Exception { + DataSource dataSource = new DataSource(); + ObjectMapper mapper = new ObjectMapper(); + mapper.addMixInAnnotations(DataSource.class, DataSourceJson.class); + String value = mapper.writeValueAsString(dataSource); + System.err.println(value); + assertTrue(value.contains("\"url\":")); + assertEquals(1, StringUtils.countOccurrencesOf(value, "\"url\"")); + } + + @JsonSerialize(using = TomcatDataSourceSerializer.class) + protected static interface DataSourceJson { + } + + protected static class TomcatDataSourceSerializer extends JsonSerializer { + + private ConversionService conversionService = new DefaultConversionService(); + + @Override + public void serialize(DataSource value, JsonGenerator jgen, + SerializerProvider provider) throws IOException, JsonProcessingException { + jgen.writeStartObject(); + for (PropertyDescriptor property : BeanUtils + .getPropertyDescriptors(DataSource.class)) { + Method reader = property.getReadMethod(); + if (reader != null + && property.getWriteMethod() != null + && this.conversionService.canConvert(String.class, + property.getPropertyType())) { + jgen.writeObjectField(property.getName(), + ReflectionUtils.invokeMethod(reader, value)); + } + } + jgen.writeEndObject(); + } + + } + + protected static class GenericSerializerModifier extends BeanSerializerModifier { + + private ConversionService conversionService = new DefaultConversionService(); + + @Override + public List changeProperties(SerializationConfig config, + BeanDescription beanDesc, List beanProperties) { + List result = new ArrayList(); + for (BeanPropertyWriter writer : beanProperties) { + AnnotatedMethod setter = beanDesc.findMethod( + "set" + StringUtils.capitalize(writer.getName()), + new Class[] { writer.getPropertyType() }); + if (setter != null + && this.conversionService.canConvert(String.class, + writer.getPropertyType())) { + result.add(writer); + } + } + return result; + } + + } + +}