Skip to content

Commit

Permalink
Merge pull request spring-projects#11498 from ioanngolovko
Browse files Browse the repository at this point in the history
* pr/11498:
  Polish GSON customization support
  Allow GSON customization via properties or beans
  • Loading branch information
philwebb committed Jan 9, 2018
2 parents 9cb5f3d + 286a3bb commit 6ea6adb
Show file tree
Hide file tree
Showing 5 changed files with 524 additions and 23 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2012-2017 the original author or authors.
* Copyright 2012-2018 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.
Expand All @@ -16,28 +16,88 @@

package org.springframework.boot.autoconfigure.gson;

import java.util.List;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.context.properties.PropertyMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;

/**
* {@link EnableAutoConfiguration Auto-configuration} for Gson.
*
* @author David Liu
* @author Ivan Golovko
* @since 1.2.0
*/
@Configuration
@ConditionalOnClass(Gson.class)
@EnableConfigurationProperties(GsonProperties.class)
public class GsonAutoConfiguration {

@Bean
@ConditionalOnMissingBean
public Gson gson() {
return new Gson();
public GsonBuilder gsonBuilder(List<GsonBuilderCustomizer> customizers) {
GsonBuilder builder = new GsonBuilder();
customizers.forEach(c -> c.customize(builder));
return builder;
}

@Bean
@ConditionalOnMissingBean(Gson.class)
public Gson gson(GsonBuilder gsonBuilder) {
return gsonBuilder.create();
}

@Bean
public StandardGsonBuilderCustomizer standardGsonBuilderCustomizer(
GsonProperties gsonProperties) {
return new StandardGsonBuilderCustomizer(gsonProperties);
}

private static final class StandardGsonBuilderCustomizer
implements GsonBuilderCustomizer, Ordered {

private final GsonProperties properties;

StandardGsonBuilderCustomizer(GsonProperties properties) {
this.properties = properties;
}

@Override
public int getOrder() {
return 0;
}

@Override
public void customize(GsonBuilder builder) {
GsonProperties properties = this.properties;
PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull();
map.from(properties::getGenerateNonExecutableJson)
.toCall(builder::generateNonExecutableJson);
map.from(properties::getExcludeFieldsWithoutExposeAnnotation)
.toCall(builder::excludeFieldsWithoutExposeAnnotation);
map.from(properties::getSerializeNulls).toCall(builder::serializeNulls);
map.from(properties::getEnableComplexMapKeySerialization)
.toCall(builder::enableComplexMapKeySerialization);
map.from(properties::getDisableInnerClassSerialization)
.toCall(builder::disableInnerClassSerialization);
map.from(properties::getLongSerializationPolicy)
.to(builder::setLongSerializationPolicy);
map.from(properties::getFieldNamingPolicy).to(builder::setFieldNamingPolicy);
map.from(properties::getPrettyPrinting).toCall(builder::setPrettyPrinting);
map.from(properties::getLenient).toCall(builder::setLenient);
map.from(properties::getDisableHtmlEscaping)
.toCall(builder::disableHtmlEscaping);
map.from(properties::getDateFormat).to(builder::setDateFormat);
}

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* Copyright 2012-2018 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.gson;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

/**
* Callback interface that can be implemented by beans wishing to further customize the
* {@link Gson} via {@link GsonBuilder} retaining its default auto-configuration.
*
* @author Ivan Golovko
* @since 2.0.0
*/
@FunctionalInterface
public interface GsonBuilderCustomizer {

/**
* Customize the GsonBuilder.
* @param gsonBuilder the GsonBuilder to customize
*/
void customize(GsonBuilder gsonBuilder);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
/*
* Copyright 2012-2018 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.gson;

import com.google.gson.FieldNamingPolicy;
import com.google.gson.Gson;
import com.google.gson.LongSerializationPolicy;

import org.springframework.boot.context.properties.ConfigurationProperties;

/**
* Configuration properties to configure {@link Gson}.
*
* @author Ivan Golovko
* @since 2.0.0
*/
@ConfigurationProperties(prefix = "spring.gson")
public class GsonProperties {

/**
* Whether to generate non executable JSON by prefixing the output with some special
* text.
*/
private Boolean generateNonExecutableJson;

/**
* Whether to exclude all fields from consideration for serialization or
* deserialization that do not have the "Expose" annotation.
*/
private Boolean excludeFieldsWithoutExposeAnnotation;

/**
* Whether to to serialize null fields.
*/
private Boolean serializeNulls;

/**
* Whether to enabled serialization of complex map keys (i.e. non-primitives).
*/
private Boolean enableComplexMapKeySerialization;

/**
* Whether to exclude inner classes during serialization.
*/
private Boolean disableInnerClassSerialization;

/**
* Serialization policy for Long and long types.
*/
private LongSerializationPolicy longSerializationPolicy;

/**
* The naming policy that should be applied to an object's field during serialization
* and deserialization.
*/
private FieldNamingPolicy fieldNamingPolicy;

/**
* Whether to output serialized JSON that fits in a page for pretty printing.
*/
private Boolean prettyPrinting;

/**
* Whether to be lenient about parsing JSON that doesn't conform to RFC 4627.
*/
private Boolean lenient;

/**
* Whether to disable the escaping of HTML characters such as '<' '>' etc.
*/
private Boolean disableHtmlEscaping;

/**
* The format to use when serializing Date objects.
*/
private String dateFormat;

public Boolean getGenerateNonExecutableJson() {
return this.generateNonExecutableJson;
}

public void setGenerateNonExecutableJson(Boolean generateNonExecutableJson) {
this.generateNonExecutableJson = generateNonExecutableJson;
}

public Boolean getExcludeFieldsWithoutExposeAnnotation() {
return this.excludeFieldsWithoutExposeAnnotation;
}

public void setExcludeFieldsWithoutExposeAnnotation(
Boolean excludeFieldsWithoutExposeAnnotation) {
this.excludeFieldsWithoutExposeAnnotation = excludeFieldsWithoutExposeAnnotation;
}

public Boolean getSerializeNulls() {
return this.serializeNulls;
}

public void setSerializeNulls(Boolean serializeNulls) {
this.serializeNulls = serializeNulls;
}

public Boolean getEnableComplexMapKeySerialization() {
return this.enableComplexMapKeySerialization;
}

public void setEnableComplexMapKeySerialization(
Boolean enableComplexMapKeySerialization) {
this.enableComplexMapKeySerialization = enableComplexMapKeySerialization;
}

public Boolean getDisableInnerClassSerialization() {
return this.disableInnerClassSerialization;
}

public void setDisableInnerClassSerialization(
Boolean disableInnerClassSerialization) {
this.disableInnerClassSerialization = disableInnerClassSerialization;
}

public LongSerializationPolicy getLongSerializationPolicy() {
return this.longSerializationPolicy;
}

public void setLongSerializationPolicy(
LongSerializationPolicy longSerializationPolicy) {
this.longSerializationPolicy = longSerializationPolicy;
}

public FieldNamingPolicy getFieldNamingPolicy() {
return this.fieldNamingPolicy;
}

public void setFieldNamingPolicy(FieldNamingPolicy fieldNamingPolicy) {
this.fieldNamingPolicy = fieldNamingPolicy;
}

public Boolean getPrettyPrinting() {
return this.prettyPrinting;
}

public void setPrettyPrinting(Boolean prettyPrinting) {
this.prettyPrinting = prettyPrinting;
}

public Boolean getLenient() {
return this.lenient;
}

public void setLenient(Boolean lenient) {
this.lenient = lenient;
}

public Boolean getDisableHtmlEscaping() {
return this.disableHtmlEscaping;
}

public void setDisableHtmlEscaping(Boolean disableHtmlEscaping) {
this.disableHtmlEscaping = disableHtmlEscaping;
}

public String getDateFormat() {
return this.dateFormat;
}

public void setDateFormat(String dateFormat) {
this.dateFormat = dateFormat;
}

}
Loading

0 comments on commit 6ea6adb

Please sign in to comment.