Skip to content

Commit

Permalink
Merge pull request #8 from GoodforGod/dev
Browse files Browse the repository at this point in the history
[1.4.0]
  • Loading branch information
GoodforGod authored Mar 9, 2022
2 parents 518f2dd + d91e867 commit 1f57d63
Show file tree
Hide file tree
Showing 7 changed files with 152 additions and 5 deletions.
11 changes: 9 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@ Gson configuration and serializers/deserializers for Date/Time in [java.time.*](
## Dependency :rocket:
**Gradle**
```groovy
implementation "io.goodforgod:gson-configuration:1.3.0"
implementation "io.goodforgod:gson-configuration:1.4.0"
```

**Maven**
```xml
<dependency>
<groupId>io.goodforgod</groupId>
<artifactId>gson-configuration</artifactId>
<version>1.3.0</version>
<version>1.4.0</version>
</dependency>
```

Expand Down Expand Up @@ -83,6 +83,8 @@ GsonBuilder builder = new GsonConfiguration()
.setGenerateNonExecutableJson(true)
.setSerializeNulls(true)
.setSerializeSpecialFloatingPointValues(true)
.setExcludeFieldsWithoutExposeAnnotation(true)
.setExcludeFieldsWithModifiers(GsonConfiguration.FieldModifiers.TRANSIENT)
.builder();
```

Expand All @@ -95,6 +97,9 @@ GsonBuilder builder = new GsonConfiguration()

### Properties file

**By default** Gson or GsonBuilder that is build via GsonConfiguration or GsonFactory **doesn't serialize/deserialize** transient, static, volatile, synchronized fields.
You need to use configuration setters to configure it otherwise.

GsonConfiguration also can be filled from *properties* file.

How to build GsonConfiguration from Properties:
Expand Down Expand Up @@ -130,6 +135,8 @@ gson.escapeHtmlChars=false
gson.generateNonExecutableJson=true
gson.serializeComplexMapKey=true
gson.serializeSpecialFloatingPointValues=true
gson.excludeFieldsWithoutExposeAnnotation=false
gson.excludeFieldsWithModifiers=TRANSIENT,STATIC,SYNCHRONIZED,VOLATILE

gson.policy.fieldNaming=UPPER_CAMEL_CASE
gson.policy.longSerialization=STRING
Expand Down
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
plugins {
id "jacoco"
id "maven-publish"
id "java-library"
id "maven-publish"

id "org.sonarqube" version "3.3"
id "com.diffplug.spotless" version "6.1.0"
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
groupId=io.goodforgod
artifactId=gson-configuration
artifactVersion=1.3.0
artifactVersion=1.4.0-SNAPSHOT


##### GRADLE #####
Expand Down
129 changes: 128 additions & 1 deletion src/main/java/io/goodforgod/gson/configuration/GsonConfiguration.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,56 @@
import com.google.gson.FieldNamingPolicy;
import com.google.gson.GsonBuilder;
import com.google.gson.LongSerializationPolicy;
import java.lang.reflect.Modifier;
import java.text.SimpleDateFormat;
import java.time.chrono.IsoChronology;
import java.time.format.DateTimeFormatter;
import java.time.format.ResolverStyle;
import java.util.Properties;
import java.util.*;
import java.util.stream.Collectors;

/**
* @author Anton Kurako (GoodforGod)
* @since 25.04.2021
*/
public class GsonConfiguration {

private static final Set<FieldModifiers> DEFAULT_EXCLUDED_MODIFIERS;

static {
final Set<FieldModifiers> modifiers = new HashSet<>(8);
modifiers.add(FieldModifiers.TRANSIENT);
modifiers.add(FieldModifiers.SYNCHRONIZED);
modifiers.add(FieldModifiers.VOLATILE);
modifiers.add(FieldModifiers.STATIC);
DEFAULT_EXCLUDED_MODIFIERS = Collections.unmodifiableSet(modifiers);
}

/**
* @see GsonBuilder#excludeFieldsWithModifiers(int...)
*/
public enum FieldModifiers {

PUBLIC(Modifier.PUBLIC),
PROTECTED(Modifier.PROTECTED),
PRIVATE(Modifier.PRIVATE),
STATIC(Modifier.STATIC),
FINAL(Modifier.FINAL),
SYNCHRONIZED(Modifier.SYNCHRONIZED),
VOLATILE(Modifier.VOLATILE),
TRANSIENT(Modifier.TRANSIENT);

private final int modifier;

FieldModifiers(int modifier) {
this.modifier = modifier;
}

public int modifier() {
return modifier;
}
}

private DateTimeFormatter instantFormat = DateTimeFormatters.ISO_INSTANT;
private DateTimeFormatter localDateFormat = DateTimeFormatters.ISO_LOCAL_DATE;
private DateTimeFormatter localTimeFormat = DateTimeFormatters.ISO_LOCAL_TIME;
Expand Down Expand Up @@ -61,6 +99,23 @@ public class GsonConfiguration {
*/
private boolean serializeNulls = false;

/**
* Configures Gson to exclude all fields from consideration for serialization or deserialization
* that do not have the {@link com.google.gson.annotations.Expose} annotation.
*
* @see GsonBuilder#excludeFieldsWithoutExposeAnnotation()
*/
private boolean excludeFieldsWithoutExposeAnnotation = false;

/**
* Configures Gson to excludes all class fields that have the specified modifiers. By default,
* Gson will exclude all fields marked transient or static. This method will override that
* behavior.
*
* @see GsonBuilder#excludeFieldsWithModifiers(int...)
*/
private Set<FieldModifiers> excludeFieldsWithModifiers = DEFAULT_EXCLUDED_MODIFIERS;

/**
* Enabling this feature will only change the serialized form if the map key is a complex type (i.e.
* non-primitive) in its <strong>serialized</strong> JSON form.
Expand Down Expand Up @@ -167,6 +222,10 @@ private static GsonConfiguration ofProperties(GsonConfiguration configuration, P
final String complexMapKeySerialization = properties.getProperty(GsonProperties.COMPLEX_MAP_KEY_SERIALIZATION);
final String serializeSpecialFloatingPointValues = properties
.getProperty(GsonProperties.SERIALIZE_SPECIAL_FLOATING_POINT_VALUES);
final String excludeFieldsWithoutExposeAnnotation = properties
.getProperty(GsonProperties.EXCLUDE_FIELDS_WITHOUT_EXPOSE_ANNOTATION);
final String excludeFieldsWithModifiers = properties
.getProperty(GsonProperties.EXCLUDE_FIELDS_WITH_MODIFIERS);

if (formatInstant != null)
configuration.setInstantFormat(formatInstant);
Expand Down Expand Up @@ -215,6 +274,15 @@ private static GsonConfiguration ofProperties(GsonConfiguration configuration, P
configuration.setComplexMapKeySerialization(Boolean.parseBoolean(complexMapKeySerialization));
if (serializeSpecialFloatingPointValues != null)
configuration.setSerializeSpecialFloatingPointValues(Boolean.parseBoolean(serializeSpecialFloatingPointValues));
if (excludeFieldsWithoutExposeAnnotation != null)
configuration.setExcludeFieldsWithoutExposeAnnotation(Boolean.parseBoolean(excludeFieldsWithoutExposeAnnotation));
if (excludeFieldsWithModifiers != null) {
final Set<FieldModifiers> modifiers = Arrays.stream(excludeFieldsWithModifiers.split(","))
.map(FieldModifiers::valueOf)
.collect(Collectors.toSet());

configuration.setExcludeFieldsWithModifiers(modifiers);
}

return configuration;
}
Expand All @@ -225,6 +293,14 @@ public GsonBuilder builder() {
.setLongSerializationPolicy(getLongSerializationPolicy())
.setFieldNamingPolicy(getFieldNamingPolicy());

final int[] modifiers = getExcludeFieldsWithModifiers().stream()
.mapToInt(m -> m.modifier)
.toArray();

builder.excludeFieldsWithModifiers(modifiers);

if (isExcludeFieldsWithoutExposeAnnotation())
builder.excludeFieldsWithoutExposeAnnotation();
if (isComplexMapKeySerialization())
builder.enableComplexMapKeySerialization();
if (isGenerateNonExecutableJson())
Expand Down Expand Up @@ -423,6 +499,57 @@ public GsonConfiguration setSerializeSpecialFloatingPointValues(boolean serializ
return this;
}

public boolean isExcludeFieldsWithoutExposeAnnotation() {
return excludeFieldsWithoutExposeAnnotation;
}

/**
* Configures Gson to exclude all fields from consideration for serialization or deserialization
* that do not have the {@link com.google.gson.annotations.Expose} annotation.
*
* @see GsonBuilder#excludeFieldsWithoutExposeAnnotation()
* @param excludeFieldsWithoutExposeAnnotation set true to exclude
* @return self
*/
public GsonConfiguration setExcludeFieldsWithoutExposeAnnotation(boolean excludeFieldsWithoutExposeAnnotation) {
this.excludeFieldsWithoutExposeAnnotation = excludeFieldsWithoutExposeAnnotation;
return this;
}

public Set<FieldModifiers> getExcludeFieldsWithModifiers() {
return excludeFieldsWithModifiers;
}

/**
* Configures Gson to excludes all class fields that have the specified modifiers. By default,
* Gson will exclude all fields marked transient or static. This method will override that
* behavior.
*
* @see GsonBuilder#excludeFieldsWithModifiers(int...)
* @param excludeFieldsWithModifiers fields modifiers to exclude
* @return self
*/
public GsonConfiguration setExcludeFieldsWithModifiers(Set<FieldModifiers> excludeFieldsWithModifiers) {
this.excludeFieldsWithModifiers = Collections.unmodifiableSet(excludeFieldsWithModifiers);
return this;
}

/**
* Configures Gson to excludes all class fields that have the specified modifiers. By default,
* Gson will exclude all fields marked transient or static. This method will override that
* behavior.
*
* @see GsonBuilder#excludeFieldsWithModifiers(int...)
* @param excludeFieldsWithModifiers fields modifiers to exclude
* @return self
*/
public GsonConfiguration setExcludeFieldsWithModifiers(FieldModifiers... excludeFieldsWithModifiers) {
this.excludeFieldsWithModifiers = Collections.unmodifiableSet(Arrays.stream(excludeFieldsWithModifiers)
.collect(Collectors.toSet()));

return this;
}

public DateTimeFormatter getInstantFormat() {
return instantFormat;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ private GsonProperties() {}
public static final String GENERATE_NON_EXECUTABLE_JSON = PREFIX + "generateNonExecutableJson";
public static final String COMPLEX_MAP_KEY_SERIALIZATION = PREFIX + "serializeComplexMapKey";
public static final String SERIALIZE_SPECIAL_FLOATING_POINT_VALUES = PREFIX + "serializeSpecialFloatingPointValues";
public static final String EXCLUDE_FIELDS_WITHOUT_EXPOSE_ANNOTATION = PREFIX + "excludeFieldsWithoutExposeAnnotation";
public static final String EXCLUDE_FIELDS_WITH_MODIFIERS = PREFIX + "excludeFieldsWithModifiers";

public static final String POLICY_FIELD_NAMING = PREFIX + "policy.fieldNaming";
public static final String POLICY_LONG_SERIALIZATION = PREFIX + "policy.longSerialization";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ void configurationPropertiesApplied() throws Exception {
assertTrue(configuration.isGenerateNonExecutableJson());
assertTrue(configuration.isSerializeSpecialFloatingPointValues());
assertFalse(configuration.isEscapeHtmlChars());
assertTrue(configuration.isExcludeFieldsWithoutExposeAnnotation());
assertEquals(1, configuration.getExcludeFieldsWithModifiers().size());
assertTrue(configuration.getExcludeFieldsWithModifiers().contains(GsonConfiguration.FieldModifiers.TRANSIENT));

assertEquals(FieldNamingPolicy.UPPER_CAMEL_CASE, configuration.getFieldNamingPolicy());
assertEquals(LongSerializationPolicy.STRING, configuration.getLongSerializationPolicy());
Expand Down Expand Up @@ -70,6 +73,12 @@ void configurationPropertiesAsDefault() {
assertFalse(configuration.isGenerateNonExecutableJson());
assertFalse(configuration.isSerializeSpecialFloatingPointValues());
assertTrue(configuration.isEscapeHtmlChars());
assertFalse(configuration.isExcludeFieldsWithoutExposeAnnotation());
assertEquals(4, configuration.getExcludeFieldsWithModifiers().size());
assertTrue(configuration.getExcludeFieldsWithModifiers().contains(GsonConfiguration.FieldModifiers.TRANSIENT));
assertTrue(configuration.getExcludeFieldsWithModifiers().contains(GsonConfiguration.FieldModifiers.STATIC));
assertTrue(configuration.getExcludeFieldsWithModifiers().contains(GsonConfiguration.FieldModifiers.VOLATILE));
assertTrue(configuration.getExcludeFieldsWithModifiers().contains(GsonConfiguration.FieldModifiers.SYNCHRONIZED));

assertEquals(FieldNamingPolicy.IDENTITY, configuration.getFieldNamingPolicy());
assertEquals(LongSerializationPolicy.DEFAULT, configuration.getLongSerializationPolicy());
Expand Down
2 changes: 2 additions & 0 deletions src/test/resources/gson.properties
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ gson.escapeHtmlChars=false
gson.generateNonExecutableJson=true
gson.serializeComplexMapKey=true
gson.serializeSpecialFloatingPointValues=true
gson.excludeFieldsWithoutExposeAnnotation=true
gson.excludeFieldsWithModifiers=TRANSIENT

gson.policy.fieldNaming=UPPER_CAMEL_CASE
gson.policy.longSerialization=STRING

0 comments on commit 1f57d63

Please sign in to comment.