From bd53dd388109225f3423e439dc9b1d29eb300ceb Mon Sep 17 00:00:00 2001 From: Anton Kurako Date: Tue, 11 Jan 2022 00:17:23 +0300 Subject: [PATCH 1/9] [1.1.1-SNAPSHOT] codestyle.xml & format styles updated Dependencies updated --- .editorconfig | 18 +- .gitattributes | 35 +- .gitignore | 9 +- README.md | 4 +- build.gradle | 42 +- config/codestyle.xml | 370 ++++++++++-------- gradle.properties | 9 +- gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 257 +++++++----- .../configuration/GsonAdapterBuilder.java | 3 +- .../LocalDateTimeDeserializer.java | 3 +- .../OffsetDateTimeDeserializer.java | 3 +- .../ZonedDateTimeDeserializer.java | 3 +- .../ZonedDateTimeDeserializerTests.java | 3 +- 14 files changed, 449 insertions(+), 312 deletions(-) diff --git a/.editorconfig b/.editorconfig index 5b9451e..bd43bdc 100644 --- a/.editorconfig +++ b/.editorconfig @@ -8,14 +8,30 @@ root = true end_of_line = lf charset = utf-8 +# Json +[*.json] +indent_size = 2 +indent_style = space +insert_final_newline = false +trim_trailing_whitespace = true + # Yaml [{*.yml, *.yaml}] indent_size = 2 indent_style = space +insert_final_newline = true +trim_trailing_whitespace = true # Property files [*.properties] indent_size = 2 indent_style = space +insert_final_newline = true +trim_trailing_whitespace = true - +# XML files +[*.xml] +indent_size = 4 +indent_style = space +insert_final_newline = true +trim_trailing_whitespace = true diff --git a/.gitattributes b/.gitattributes index ccc6fb5..856d969 100644 --- a/.gitattributes +++ b/.gitattributes @@ -2,9 +2,8 @@ # and leave all files detected as binary untouched. * text=auto -# + # The above will handle all files NOT found below -# # These files are text and should be normalized (Convert crlf => lf) *.bash text eol=lf *.css text diff=css @@ -26,16 +25,36 @@ *.xml text *.yml text eol=lf + # These files are binary and should be left untouched # (binary is a macro for -text -diff) -*.class binary +# Archives +*.7z binary +*.br binary +*.gz binary +*.tar binary +*.zip binary +*.jar binary +*.so binary +*.war binary *.dll binary -*.ear binary -*.gif binary + +# Documents +*.pdf binary + +# Images *.ico binary -*.jar binary +*.gif binary *.jpg binary *.jpeg binary *.png binary -*.so binary -*.war binary \ No newline at end of file +*.psd binary +*.webp binary + +# Fonts +*.woff2 binary + +# Other +*.exe binary +*.class binary +*.ear binary diff --git a/.gitignore b/.gitignore index 569f813..b56b41b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -# Package Files # +### Package Files *.war *.nar *.ear @@ -9,9 +9,10 @@ ### Gradle template .gradle build/ +target/ -# Idea generatted files +### Idea generated files .idea -/out/ -*.iml .settings/ +*.iml +out/ diff --git a/README.md b/README.md index a609173..403895d 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ Gson configuration and serializers/deserializers for Date/Time in [java.time.*]( **Gradle** ```groovy dependencies { - implementation "io.goodforgod:gson-configuration:1.1.0" + implementation "io.goodforgod:gson-configuration:1.1.1" } ``` @@ -21,7 +21,7 @@ dependencies { io.goodforgod gson-configuration - 1.1.0 + 1.1.1 ``` diff --git a/build.gradle b/build.gradle index ac23052..74b1d6c 100644 --- a/build.gradle +++ b/build.gradle @@ -4,7 +4,7 @@ plugins { id "java-library" id "org.sonarqube" version "3.3" - id "com.diffplug.spotless" version "5.14.3" + id "com.diffplug.spotless" version "6.1.0" } repositories { @@ -19,29 +19,12 @@ version = artifactVersion sourceCompatibility = JavaVersion.VERSION_1_8 targetCompatibility = JavaVersion.VERSION_1_8 -spotless { - java { - encoding("UTF-8") - importOrder() - removeUnusedImports() - eclipse().configFile("${projectDir}/config/codestyle.xml") - } -} - -sonarqube { - properties { - property "sonar.host.url", "https://sonarcloud.io" - property "sonar.organization", "goodforgod" - property "sonar.projectKey", "GoodforGod_gson-configuration" - } -} - dependencies { api "com.google.code.gson:gson:2.8.9" - testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:5.8.1" - testImplementation "org.junit.jupiter:junit-jupiter-api:5.8.1" - testImplementation "org.junit.jupiter:junit-jupiter-params:5.8.1" + testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:5.8.2" + testImplementation "org.junit.jupiter:junit-jupiter-api:5.8.2" + testImplementation "org.junit.jupiter:junit-jupiter-params:5.8.2" } test { @@ -57,6 +40,23 @@ test { } } +spotless { + java { + encoding("UTF-8") + importOrder() + removeUnusedImports() + eclipse().configFile("${projectDir}/config/codestyle.xml") + } +} + +sonarqube { + properties { + property "sonar.host.url", "https://sonarcloud.io" + property "sonar.organization", "goodforgod" + property "sonar.projectKey", "GoodforGod_gson-configuration" + } +} + publishing { publications { mavenJava(MavenPublication) { diff --git a/config/codestyle.xml b/config/codestyle.xml index 17f264c..ad0c929 100644 --- a/config/codestyle.xml +++ b/config/codestyle.xml @@ -1,156 +1,95 @@ - - + + - - - - - - - - - - - - - - + + - - - - + + - - - - - - - + + - - - - - - - - - - - - - - - - - + + - - - - + - - - + - - - - - - - - - + - + - - - - - - - - - - - - - + - - - + @@ -158,190 +97,293 @@ - - - - - - + + - - - + - - - - - - - - + - - - - - - - - - - - - - - + - - - - - + - - - - + - + - - - - - - - - + - + - - - - - - - - - + + - - - - - - - - - - - - - + - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - + - - - - + diff --git a/gradle.properties b/gradle.properties index 0794107..968c030 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,6 +1,6 @@ groupId=io.goodforgod artifactId=gson-configuration -artifactVersion=1.1.0 +artifactVersion=1.1.1-SNAPSHOT ##### GRADLE ##### @@ -8,4 +8,9 @@ org.gradle.daemon=true org.gradle.parallel=true org.gradle.configureondemand=true org.gradle.caching=true -org.gradle.jvmargs=-Dfile.encoding=UTF-8 +org.gradle.jvmargs=-Dfile.encoding=UTF-8 \ + --add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED \ + --add-exports jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED \ + --add-exports jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED \ + --add-exports jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED \ + --add-exports jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index e750102..2e6e589 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.3-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 744e882..1b6c787 100755 --- a/gradlew +++ b/gradlew @@ -1,7 +1,7 @@ -#!/usr/bin/env sh +#!/bin/sh # -# Copyright 2015 the original author or authors. +# Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -17,67 +17,101 @@ # ############################################################################## -## -## Gradle start up script for UN*X -## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# ############################################################################## # Attempt to set APP_HOME + # Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` +APP_BASE_NAME=${0##*/} # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MSYS* | MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar @@ -87,9 +121,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -98,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" + JAVACMD=java which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the @@ -106,80 +140,95 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac fi -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java -if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) fi - i=`expr $i + 1` + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg done - case $i in - 0) set -- ;; - 1) set -- "$args0" ;; - 2) set -- "$args0" "$args1" ;; - 3) set -- "$args0" "$args1" "$args2" ;; - 4) set -- "$args0" "$args1" "$args2" "$args3" ;; - 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=`save "$@"` +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' exec "$JAVACMD" "$@" diff --git a/src/main/java/io/goodforgod/gson/configuration/GsonAdapterBuilder.java b/src/main/java/io/goodforgod/gson/configuration/GsonAdapterBuilder.java index c2c1c7d..e375896 100644 --- a/src/main/java/io/goodforgod/gson/configuration/GsonAdapterBuilder.java +++ b/src/main/java/io/goodforgod/gson/configuration/GsonAdapterBuilder.java @@ -70,7 +70,8 @@ public static GsonBuilder builder(GsonConfiguration configuration) { .registerTypeAdapter(LocalDateTime.class, new LocalDateTimeSerializer(configuration.getLocalDateTimeFormat())) .registerTypeAdapter(OffsetTime.class, new OffsetTimeDeserializer(configuration.getOffsetTimeFormat())) .registerTypeAdapter(OffsetTime.class, new OffsetTimeSerializer(configuration.getOffsetTimeFormat())) - .registerTypeAdapter(OffsetDateTime.class, new OffsetDateTimeDeserializer(configuration.getOffsetDateTimeFormat())) + .registerTypeAdapter(OffsetDateTime.class, + new OffsetDateTimeDeserializer(configuration.getOffsetDateTimeFormat())) .registerTypeAdapter(OffsetDateTime.class, new OffsetDateTimeSerializer(configuration.getOffsetDateTimeFormat())) .registerTypeAdapter(ZonedDateTime.class, new ZonedDateTimeDeserializer(configuration.getZonedDateTimeFormat())) .registerTypeAdapter(ZonedDateTime.class, new ZonedDateTimeSerializer(configuration.getZonedDateTimeFormat())); diff --git a/src/main/java/io/goodforgod/gson/configuration/deserializer/LocalDateTimeDeserializer.java b/src/main/java/io/goodforgod/gson/configuration/deserializer/LocalDateTimeDeserializer.java index 1123a53..336c8f3 100644 --- a/src/main/java/io/goodforgod/gson/configuration/deserializer/LocalDateTimeDeserializer.java +++ b/src/main/java/io/goodforgod/gson/configuration/deserializer/LocalDateTimeDeserializer.java @@ -29,7 +29,8 @@ public LocalDateTimeDeserializer(DateTimeFormatter formatter) { } @Override - public LocalDateTime deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { + public LocalDateTime deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) + throws JsonParseException { try { return formatter.parse(json.getAsString()).query(LocalDateTime::from); } catch (Exception e) { diff --git a/src/main/java/io/goodforgod/gson/configuration/deserializer/OffsetDateTimeDeserializer.java b/src/main/java/io/goodforgod/gson/configuration/deserializer/OffsetDateTimeDeserializer.java index dff70fe..b3eb257 100644 --- a/src/main/java/io/goodforgod/gson/configuration/deserializer/OffsetDateTimeDeserializer.java +++ b/src/main/java/io/goodforgod/gson/configuration/deserializer/OffsetDateTimeDeserializer.java @@ -29,7 +29,8 @@ public OffsetDateTimeDeserializer(DateTimeFormatter formatter) { } @Override - public OffsetDateTime deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { + public OffsetDateTime deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) + throws JsonParseException { try { return formatter.parse(json.getAsString()).query(OffsetDateTime::from); } catch (Exception e) { diff --git a/src/main/java/io/goodforgod/gson/configuration/deserializer/ZonedDateTimeDeserializer.java b/src/main/java/io/goodforgod/gson/configuration/deserializer/ZonedDateTimeDeserializer.java index 540ade4..5ebb060 100644 --- a/src/main/java/io/goodforgod/gson/configuration/deserializer/ZonedDateTimeDeserializer.java +++ b/src/main/java/io/goodforgod/gson/configuration/deserializer/ZonedDateTimeDeserializer.java @@ -29,7 +29,8 @@ public ZonedDateTimeDeserializer(DateTimeFormatter formatter) { } @Override - public ZonedDateTime deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { + public ZonedDateTime deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) + throws JsonParseException { try { return formatter.parse(json.getAsString()).query(ZonedDateTime::from); } catch (Exception e) { diff --git a/src/test/java/io/goodforgod/gson/configuration/serializer/ZonedDateTimeDeserializerTests.java b/src/test/java/io/goodforgod/gson/configuration/serializer/ZonedDateTimeDeserializerTests.java index a8236f5..beca413 100644 --- a/src/test/java/io/goodforgod/gson/configuration/serializer/ZonedDateTimeDeserializerTests.java +++ b/src/test/java/io/goodforgod/gson/configuration/serializer/ZonedDateTimeDeserializerTests.java @@ -44,7 +44,8 @@ public void setValue(ZonedDateTime value) { private static final String VALUE_AS_STRING = "1970-01-01T00:00:00.000Z[UTC]"; private static final ZonedDateTime VALUE_AS_TIME_NON_UTC = ZonedDateTime - .ofInstant(LocalDateTime.ofInstant(Instant.EPOCH, ZoneId.of("Europe/Paris")), ZoneOffset.UTC, ZoneId.of("Europe/Paris")); + .ofInstant(LocalDateTime.ofInstant(Instant.EPOCH, ZoneId.of("Europe/Paris")), ZoneOffset.UTC, + ZoneId.of("Europe/Paris")); private static final String VALUE_AS_STRING_NON_UTC = "1970-01-01T02:00:00.000+01:00[Europe/Paris]"; private final Gson adapter = new GsonBuilder() From 32969dd225742a6f8967b9b0b4d57fca26a0a26e Mon Sep 17 00:00:00 2001 From: Anton Kurako Date: Wed, 12 Jan 2022 01:25:29 +0300 Subject: [PATCH 2/9] [1.2.0-SNAPSHOT] DateTimeFormatters#ISO_DATE_JAVA as analog to default java ISO formatter added GsonConfiguration#ofJavaISO and GsonConfiguration#ofPropertiesJavaISO builders added GsonConfiguration#applyRestrictions with new options GsonConfiguration#forceIsoChronology & GsonConfiguration#forceResolverStrict added --- README.md | 4 +- gradle.properties | 2 +- .../configuration/DateTimeFormatters.java | 6 + .../gson/configuration/GsonConfiguration.java | 179 ++++++++++++++++-- 4 files changed, 176 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 403895d..ac89a4a 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ Gson configuration and serializers/deserializers for Date/Time in [java.time.*]( **Gradle** ```groovy dependencies { - implementation "io.goodforgod:gson-configuration:1.1.1" + implementation "io.goodforgod:gson-configuration:1.2.0" } ``` @@ -21,7 +21,7 @@ dependencies { io.goodforgod gson-configuration - 1.1.1 + 1.2.0 ``` diff --git a/gradle.properties b/gradle.properties index 968c030..f0b49bd 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,6 +1,6 @@ groupId=io.goodforgod artifactId=gson-configuration -artifactVersion=1.1.1-SNAPSHOT +artifactVersion=1.2.0-SNAPSHOT ##### GRADLE ##### diff --git a/src/main/java/io/goodforgod/gson/configuration/DateTimeFormatters.java b/src/main/java/io/goodforgod/gson/configuration/DateTimeFormatters.java index 3a210ef..af43248 100644 --- a/src/main/java/io/goodforgod/gson/configuration/DateTimeFormatters.java +++ b/src/main/java/io/goodforgod/gson/configuration/DateTimeFormatters.java @@ -130,4 +130,10 @@ private DateTimeFormatters() {} * ISO8601 for {@link java.util.Date} and {@link java.sql.Timestamp} */ public static final String ISO_DATE = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX"; + + /** + * ISO8601 for {@link java.util.Date} and {@link java.sql.Timestamp} analog to default Java ISO + * {@link DateTimeFormatter} + */ + public static final String ISO_DATE_JAVA = "yyyy-MM-dd'T'HH:mm:ssXXX"; } diff --git a/src/main/java/io/goodforgod/gson/configuration/GsonConfiguration.java b/src/main/java/io/goodforgod/gson/configuration/GsonConfiguration.java index ef27430..119bf2b 100644 --- a/src/main/java/io/goodforgod/gson/configuration/GsonConfiguration.java +++ b/src/main/java/io/goodforgod/gson/configuration/GsonConfiguration.java @@ -4,7 +4,9 @@ import com.google.gson.GsonBuilder; import com.google.gson.LongSerializationPolicy; import java.text.SimpleDateFormat; +import java.time.chrono.IsoChronology; import java.time.format.DateTimeFormatter; +import java.time.format.ResolverStyle; import java.util.Properties; /** @@ -26,51 +28,112 @@ public class GsonConfiguration { private String dateFormat = DateTimeFormatters.ISO_DATE; /** + * Forces {@link java.time.format.ResolverStyle#STRICT} for all formatters setters + */ + private boolean forceResolverStrict = false; + + /** + * Forces {@link IsoChronology#INSTANCE} for all formatters setters + */ + private boolean forceIsoChronology = false; + + /** + * Configures Gson to apply a specific naming policy to an object's field during serialization and + * deserialization. + * * @see GsonBuilder#setFieldNamingPolicy(FieldNamingPolicy) */ private FieldNamingPolicy fieldNamingPolicy = FieldNamingPolicy.IDENTITY; /** + * Configures Gson to apply a specific serialization policy for {@code Long} and {@code long} + * objects. + * * @see GsonBuilder#setLongSerializationPolicy(LongSerializationPolicy) */ private LongSerializationPolicy longSerializationPolicy = LongSerializationPolicy.DEFAULT; /** + * Configure Gson to serialize null fields. By default, Gson omits all fields that are null during + * serialization. + * * @see GsonBuilder#serializeNulls() */ private boolean serializeNulls = false; /** + * Enabling this feature will only change the serialized form if the map key is a complex type (i.e. + * non-primitive) in its serialized JSON form. + * * @see GsonBuilder#enableComplexMapKeySerialization() */ private boolean complexMapKeySerialization = false; /** + * Makes the output JSON non-executable in Javascript by prefixing the generated JSON with some + * special text. + * * @see GsonBuilder#generateNonExecutableJson() */ private boolean generateNonExecutableJson = false; /** + * Use this option to configure Gson to pass-through HTML characters as is. + * * @see GsonBuilder#disableHtmlEscaping() */ private boolean escapeHtmlChars = true; /** + * Configures Gson to output Json that fits in a page for pretty printing. + * * @see GsonBuilder#setPrettyPrinting() */ private boolean prettyPrinting = false; /** + * This option makes the parser liberal in what it accepts. + * * @see GsonBuilder#setLenient() */ private boolean lenient = false; /** + * This method provides a way to not throw exception when you have special floating values like + * {@link Float#NaN}, {@link Float#POSITIVE_INFINITY}, {@link Float#NEGATIVE_INFINITY}, or a double + * value {@link Double#NaN}, {@link Double#POSITIVE_INFINITY}, {@link Double#NEGATIVE_INFINITY}. + * * @see GsonBuilder#serializeSpecialFloatingPointValues() */ private boolean serializeSpecialFloatingPointValues = false; + /** + * @return configuration with Java default formatters {@link DateTimeFormatter} + */ + public static GsonConfiguration ofJavaISO() { + final GsonConfiguration configuration = new GsonConfiguration(); + + configuration.setDateFormat(DateTimeFormatters.ISO_DATE_JAVA); + configuration.setInstantFormat(DateTimeFormatter.ISO_INSTANT); + configuration.setLocalDateFormat(DateTimeFormatter.ISO_LOCAL_DATE); + configuration.setLocalTimeFormat(DateTimeFormatter.ISO_LOCAL_TIME); + configuration.setLocalDateTimeFormat(DateTimeFormatter.ISO_DATE_TIME); + configuration.setOffsetTimeFormat(DateTimeFormatter.ISO_OFFSET_DATE_TIME); + configuration.setOffsetDateTimeFormat(DateTimeFormatter.ISO_OFFSET_DATE_TIME); + configuration.setZonedDateTimeFormat(DateTimeFormatter.ISO_ZONED_DATE_TIME); + + return configuration; + } + + public static GsonConfiguration ofPropertiesJavaISO(Properties properties) { + return ofProperties(ofJavaISO(), properties); + } + public static GsonConfiguration ofProperties(Properties properties) { + return ofProperties(new GsonConfiguration(), properties); + } + + private static GsonConfiguration ofProperties(GsonConfiguration configuration, Properties properties) { final String formatInstant = properties.getProperty(GsonProperties.FORMAT_INSTANT); final String formatLocalDate = properties.getProperty(GsonProperties.FORMAT_LOCAL_DATE); final String formatLocalTime = properties.getProperty(GsonProperties.FORMAT_LOCAL_TIME); @@ -95,8 +158,6 @@ public static GsonConfiguration ofProperties(Properties properties) { final String serializeSpecialFloatingPointValues = properties .getProperty(GsonProperties.SERIALIZE_SPECIAL_FLOATING_POINT_VALUES); - final GsonConfiguration configuration = new GsonConfiguration(); - if (formatInstant != null) configuration.setInstantFormat(formatInstant); if (formatLocalDate != null) @@ -177,10 +238,41 @@ public GsonConfiguration setDateFormat(String dateFormat) { return this; } + public boolean isForceResolverStrict() { + return forceResolverStrict; + } + + /** + * Forces {@link java.time.format.ResolverStyle#STRICT} for all formatters setters + */ + public GsonConfiguration setForceResolverStrict(boolean forceResolverStrict) { + this.forceResolverStrict = forceResolverStrict; + return this; + } + + public boolean isForceIsoChronology() { + return forceIsoChronology; + } + + /** + * Forces {@link IsoChronology#INSTANCE} for all formatters setters + */ + public GsonConfiguration setForceIsoChronology(boolean forceIsoChronology) { + this.forceIsoChronology = forceIsoChronology; + return this; + } + public FieldNamingPolicy getFieldNamingPolicy() { return fieldNamingPolicy; } + /** + * Configures Gson to apply a specific naming policy to an object's field during serialization and + * deserialization. + * + * @param fieldNamingPolicy to set + * @return self + */ public GsonConfiguration setFieldNamingPolicy(FieldNamingPolicy fieldNamingPolicy) { if (fieldNamingPolicy == null) throw new IllegalArgumentException("Policy can not be nullable!"); @@ -192,6 +284,13 @@ public LongSerializationPolicy getLongSerializationPolicy() { return longSerializationPolicy; } + /** + * Configures Gson to apply a specific serialization policy for {@code Long} and {@code long} + * objects. + * + * @param longSerializationPolicy policy to set + * @return self + */ public GsonConfiguration setLongSerializationPolicy(LongSerializationPolicy longSerializationPolicy) { if (longSerializationPolicy == null) throw new IllegalArgumentException("Policy can not be nullable!"); @@ -203,6 +302,13 @@ public boolean isSerializeNulls() { return serializeNulls; } + /** + * Configure Gson to serialize null fields. By default, Gson omits all fields that are null during + * serialization. + * + * @param serializeNulls true if serialize + * @return self + */ public GsonConfiguration setSerializeNulls(boolean serializeNulls) { this.serializeNulls = serializeNulls; return this; @@ -212,6 +318,13 @@ public boolean isComplexMapKeySerialization() { return complexMapKeySerialization; } + /** + * Enabling this feature will only change the serialized form if the map key is a complex type (i.e. + * non-primitive) in its serialized JSON form. + * + * @param complexMapKeySerialization to set + * @return self + */ public GsonConfiguration setComplexMapKeySerialization(boolean complexMapKeySerialization) { this.complexMapKeySerialization = complexMapKeySerialization; return this; @@ -221,6 +334,13 @@ public boolean isGenerateNonExecutableJson() { return generateNonExecutableJson; } + /** + * Makes the output JSON non-executable in Javascript by prefixing the generated JSON with some + * special text. + * + * @param generateNonExecutableJson to set + * @return self + */ public GsonConfiguration setGenerateNonExecutableJson(boolean generateNonExecutableJson) { this.generateNonExecutableJson = generateNonExecutableJson; return this; @@ -230,6 +350,12 @@ public boolean isEscapeHtmlChars() { return escapeHtmlChars; } + /** + * Use this option to configure Gson to pass-through HTML characters as is. + * + * @param escapeHtmlChars to set + * @return self + */ public GsonConfiguration setEscapeHtmlChars(boolean escapeHtmlChars) { this.escapeHtmlChars = escapeHtmlChars; return this; @@ -239,6 +365,12 @@ public boolean isPrettyPrinting() { return prettyPrinting; } + /** + * Configures Gson to output Json that fits in a page for pretty printing. + * + * @param prettyPrinting to set + * @return self + */ public GsonConfiguration setPrettyPrinting(boolean prettyPrinting) { this.prettyPrinting = prettyPrinting; return this; @@ -248,6 +380,12 @@ public boolean isLenient() { return lenient; } + /** + * This option makes the parser liberal in what it accepts. + * + * @param lenient to set + * @return self + */ public GsonConfiguration setLenient(boolean lenient) { this.lenient = lenient; return this; @@ -257,6 +395,14 @@ public boolean isSerializeSpecialFloatingPointValues() { return serializeSpecialFloatingPointValues; } + /** + * This method provides a way to not throw exception when you have special floating values like + * {@link Float#NaN}, {@link Float#POSITIVE_INFINITY}, {@link Float#NEGATIVE_INFINITY}, or a double + * value {@link Double#NaN}, {@link Double#POSITIVE_INFINITY}, {@link Double#NEGATIVE_INFINITY}. + * + * @param serializeSpecialFloatingPointValues to set + * @return self + */ public GsonConfiguration setSerializeSpecialFloatingPointValues(boolean serializeSpecialFloatingPointValues) { this.serializeSpecialFloatingPointValues = serializeSpecialFloatingPointValues; return this; @@ -267,7 +413,7 @@ public DateTimeFormatter getInstantFormat() { } public GsonConfiguration setInstantFormat(DateTimeFormatter instantFormat) { - this.instantFormat = instantFormat; + this.instantFormat = applyRestrictions(instantFormat); return this; } @@ -280,7 +426,7 @@ public DateTimeFormatter getLocalDateFormat() { } public GsonConfiguration setLocalDateFormat(DateTimeFormatter localDateFormat) { - this.localDateFormat = localDateFormat; + this.localDateFormat = applyRestrictions(localDateFormat); return this; } @@ -293,7 +439,7 @@ public DateTimeFormatter getLocalTimeFormat() { } public GsonConfiguration setLocalTimeFormat(DateTimeFormatter localTimeFormat) { - this.localTimeFormat = localTimeFormat; + this.localTimeFormat = applyRestrictions(localTimeFormat); return this; } @@ -306,7 +452,7 @@ public DateTimeFormatter getLocalDateTimeFormat() { } public GsonConfiguration setLocalDateTimeFormat(DateTimeFormatter localDateTimeFormat) { - this.localDateTimeFormat = localDateTimeFormat; + this.localDateTimeFormat = applyRestrictions(localDateTimeFormat); return this; } @@ -319,7 +465,7 @@ public DateTimeFormatter getOffsetTimeFormat() { } public GsonConfiguration setOffsetTimeFormat(DateTimeFormatter offsetTimeFormat) { - this.offsetTimeFormat = offsetTimeFormat; + this.offsetTimeFormat = applyRestrictions(offsetTimeFormat); return this; } @@ -332,7 +478,7 @@ public DateTimeFormatter getOffsetDateTimeFormat() { } public GsonConfiguration setOffsetDateTimeFormat(DateTimeFormatter offsetDateTimeFormat) { - this.offsetDateTimeFormat = offsetDateTimeFormat; + this.offsetDateTimeFormat = applyRestrictions(offsetDateTimeFormat); return this; } @@ -345,7 +491,7 @@ public DateTimeFormatter getZonedDateTimeFormat() { } public GsonConfiguration setZonedDateTimeFormat(DateTimeFormatter zonedDateTimeFormat) { - this.zonedDateTimeFormat = zonedDateTimeFormat; + this.zonedDateTimeFormat = applyRestrictions(zonedDateTimeFormat); return this; } @@ -358,7 +504,7 @@ public DateTimeFormatter getYearFormat() { } public GsonConfiguration setYearFormat(DateTimeFormatter yearFormat) { - this.yearFormat = yearFormat; + this.yearFormat = applyRestrictions(yearFormat); return this; } @@ -371,7 +517,7 @@ public DateTimeFormatter getYearMonthFormat() { } public GsonConfiguration setYearMonthFormat(DateTimeFormatter yearMonthFormat) { - this.yearMonthFormat = yearMonthFormat; + this.yearMonthFormat = applyRestrictions(yearMonthFormat); return this; } @@ -384,11 +530,20 @@ public DateTimeFormatter getMonthDayFormat() { } public GsonConfiguration setMonthDayFormat(DateTimeFormatter monthDayFormat) { - this.monthDayFormat = monthDayFormat; + this.monthDayFormat = applyRestrictions(monthDayFormat); return this; } public GsonConfiguration setMonthDayFormat(String monthDayPattern) { return setMonthDayFormat(DateTimeFormatter.ofPattern(monthDayPattern)); } + + private DateTimeFormatter applyRestrictions(DateTimeFormatter formatter) { + DateTimeFormatter processedFormatter = formatter; + if (forceIsoChronology) + processedFormatter = processedFormatter.withChronology(IsoChronology.INSTANCE); + if (forceResolverStrict) + processedFormatter = processedFormatter.withResolverStyle(ResolverStyle.STRICT); + return processedFormatter; + } } From 8b7f863f8e5c3b4e44335dd6b8cefc558893ee66 Mon Sep 17 00:00:00 2001 From: Anton Kurako Date: Mon, 17 Jan 2022 23:56:28 +0300 Subject: [PATCH 3/9] [1.2.0-SNAPSHOT] DateTimeFormatters javadoc improved for formatters --- .../gson/configuration/DateTimeFormatters.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/io/goodforgod/gson/configuration/DateTimeFormatters.java b/src/main/java/io/goodforgod/gson/configuration/DateTimeFormatters.java index af43248..04f8bbe 100644 --- a/src/main/java/io/goodforgod/gson/configuration/DateTimeFormatters.java +++ b/src/main/java/io/goodforgod/gson/configuration/DateTimeFormatters.java @@ -66,7 +66,7 @@ private DateTimeFormatters() {} .withChronology(IsoChronology.INSTANCE); /** - * HH:mm:ss.SSS + * HH:mm:ss[.SSS] */ public static final DateTimeFormatter ISO_LOCAL_TIME = new DateTimeFormatterBuilder() .appendValue(HOUR_OF_DAY, 2) @@ -82,7 +82,7 @@ private DateTimeFormatters() {} .withResolverStyle(ResolverStyle.STRICT); /** - * uuuu-MM-dd'T'HH:mm:ss.SSS + * uuuu-MM-dd'T'HH:mm:ss[.SSS] */ public static final DateTimeFormatter ISO_LOCAL_DATE_TIME = new DateTimeFormatterBuilder() .append(ISO_LOCAL_DATE) @@ -93,7 +93,7 @@ private DateTimeFormatters() {} .withChronology(IsoChronology.INSTANCE); /** - * HH:mm:ss.SSSXXX + * HH:mm:ss[.SSS]XXX */ public static final DateTimeFormatter ISO_OFFSET_TIME = new DateTimeFormatterBuilder() .append(ISO_LOCAL_TIME) @@ -102,7 +102,7 @@ private DateTimeFormatters() {} .withResolverStyle(ResolverStyle.STRICT); /** - * uuuu-MM-dd'T'HH:mm:ss.SSSXXX + * uuuu-MM-dd'T'HH:mm:ss[.SSS]XXX */ public static final DateTimeFormatter ISO_OFFSET_DATE_TIME = new DateTimeFormatterBuilder() .append(ISO_LOCAL_DATE_TIME) @@ -112,7 +112,7 @@ private DateTimeFormatters() {} .withChronology(IsoChronology.INSTANCE); /** - * uuuu-MM-dd'T'HH:mm:ss.SSSXXX[VV] + * uuuu-MM-dd'T'HH:mm:ss[.SSS]XXX['['VV']'] */ public static final DateTimeFormatter ISO_ZONED_DATE_TIME = new DateTimeFormatterBuilder() .append(ISO_OFFSET_DATE_TIME) From 7414289aafa6ed30f0b780133881ecb17ed0c695 Mon Sep 17 00:00:00 2001 From: Anton Kurako Date: Wed, 19 Jan 2022 01:12:42 +0300 Subject: [PATCH 4/9] [1.2.0-SNAPSHOT] GsonAdapterBuilder#getCommonBuilder ZoneOffset register as registerTypeHierarchyAdapter fixed GsonConfiguration#of added as opposed to GsonConfiguration#ofJavaISO GsonFactory#build updated and GsonFactory#buildJavaISO added --- .../configuration/GsonAdapterBuilder.java | 4 +-- .../gson/configuration/GsonConfiguration.java | 9 ++++- .../gson/configuration/GsonFactory.java | 36 +++++++++++++++---- 3 files changed, 39 insertions(+), 10 deletions(-) diff --git a/src/main/java/io/goodforgod/gson/configuration/GsonAdapterBuilder.java b/src/main/java/io/goodforgod/gson/configuration/GsonAdapterBuilder.java index e375896..65ba527 100644 --- a/src/main/java/io/goodforgod/gson/configuration/GsonAdapterBuilder.java +++ b/src/main/java/io/goodforgod/gson/configuration/GsonAdapterBuilder.java @@ -21,8 +21,8 @@ private static GsonBuilder getCommonBuilder() { .registerTypeAdapter(DayOfWeek.class, DayOfWeekSerializer.INSTANCE) .registerTypeAdapter(Month.class, MonthDeserializer.INSTANCE) .registerTypeAdapter(Month.class, MonthSerializer.INSTANCE) - .registerTypeAdapter(ZoneId.class, ZoneIdDeserializer.INSTANCE) - .registerTypeAdapter(ZoneId.class, ZoneIdSerializer.INSTANCE) + .registerTypeHierarchyAdapter(ZoneId.class, ZoneIdDeserializer.INSTANCE) + .registerTypeHierarchyAdapter(ZoneId.class, ZoneIdSerializer.INSTANCE) .registerTypeAdapter(ZoneOffset.class, ZoneOffsetDeserializer.INSTANCE) .registerTypeAdapter(ZoneOffset.class, ZoneOffsetSerializer.INSTANCE); } diff --git a/src/main/java/io/goodforgod/gson/configuration/GsonConfiguration.java b/src/main/java/io/goodforgod/gson/configuration/GsonConfiguration.java index 119bf2b..21a3feb 100644 --- a/src/main/java/io/goodforgod/gson/configuration/GsonConfiguration.java +++ b/src/main/java/io/goodforgod/gson/configuration/GsonConfiguration.java @@ -107,6 +107,13 @@ public class GsonConfiguration { */ private boolean serializeSpecialFloatingPointValues = false; + /** + * @return configuration with formatters {@link DateTimeFormatters} + */ + public static GsonConfiguration of() { + return new GsonConfiguration(); + } + /** * @return configuration with Java default formatters {@link DateTimeFormatter} */ @@ -130,7 +137,7 @@ public static GsonConfiguration ofPropertiesJavaISO(Properties properties) { } public static GsonConfiguration ofProperties(Properties properties) { - return ofProperties(new GsonConfiguration(), properties); + return ofProperties(of(), properties); } private static GsonConfiguration ofProperties(GsonConfiguration configuration, Properties properties) { diff --git a/src/main/java/io/goodforgod/gson/configuration/GsonFactory.java b/src/main/java/io/goodforgod/gson/configuration/GsonFactory.java index 513e05d..7c92a4c 100644 --- a/src/main/java/io/goodforgod/gson/configuration/GsonFactory.java +++ b/src/main/java/io/goodforgod/gson/configuration/GsonFactory.java @@ -15,25 +15,47 @@ public class GsonFactory { private static final String PROPERTY_FILE = "gson.properties"; + private Properties properties; private GsonConfiguration configuration; + private GsonConfiguration configurationJavaISO; + /** + * @return Gson built with {@link GsonConfiguration#of()} as base + */ public Gson build() { + if (properties == null) + this.properties = getProperties(); + if (configuration == null) - configuration = getGsonConfiguration(); + this.configuration = GsonConfiguration.ofProperties(properties); + return configuration.builder().create(); } - private GsonConfiguration getGsonConfiguration() { + /** + * @return Gson built with {@link GsonConfiguration#ofJavaISO()} as base + */ + public Gson buildJavaISO() { + if (properties == null) + this.properties = getProperties(); + + if (configurationJavaISO == null) + this.configurationJavaISO = GsonConfiguration.ofPropertiesJavaISO(properties); + + return configurationJavaISO.builder().create(); + } + + private Properties getProperties() { try (InputStream resource = getClass().getClassLoader().getResourceAsStream(PROPERTY_FILE)) { if (resource != null) { - final Properties properties = new Properties(); - properties.load(resource); - return GsonConfiguration.ofProperties(properties); + final Properties resourceProperties = new Properties(); + resourceProperties.load(resource); + return resourceProperties; } else { - return new GsonConfiguration(); + return new Properties(); } } catch (Exception e) { - return new GsonConfiguration(); + return new Properties(); } } } From 9b8abd7d0b556e2cd16890c8d20c5a33e7da9375 Mon Sep 17 00:00:00 2001 From: Anton Kurako Date: Wed, 19 Jan 2022 01:13:28 +0300 Subject: [PATCH 5/9] [1.2.0-SNAPSHOT] Tests use GsonAdapterBuilder oppose to manual registration for proper testing GsonFactoryTests added --- .../gson/configuration/GsonFactoryTests.java | 86 +++++++++++++++++++ .../DayOfWeekDeserializerTests.java | 8 +- .../serializer/InstantDeserializerTests.java | 6 +- .../LocalDateDeserializerTests.java | 6 +- .../LocalDateTimeDeserializerTests.java | 6 +- .../LocalTimeDeserializerTests.java | 6 +- .../serializer/MonthDayDeserializerTests.java | 8 +- .../serializer/MonthDeserializerTests.java | 8 +- .../OffsetDateTimeDeserializerTests.java | 6 +- .../OffsetTimeDeserializerTests.java | 6 +- .../serializer/YearDeserializerTests.java | 8 +- .../YearMonthDeserializerTests.java | 8 +- .../serializer/ZoneIdDeserializerTests.java | 8 +- .../ZoneOffsetDeserializerTests.java | 8 +- .../ZonedDateTimeDeserializerTests.java | 6 +- 15 files changed, 114 insertions(+), 70 deletions(-) create mode 100644 src/test/java/io/goodforgod/gson/configuration/GsonFactoryTests.java diff --git a/src/test/java/io/goodforgod/gson/configuration/GsonFactoryTests.java b/src/test/java/io/goodforgod/gson/configuration/GsonFactoryTests.java new file mode 100644 index 0000000..95fa441 --- /dev/null +++ b/src/test/java/io/goodforgod/gson/configuration/GsonFactoryTests.java @@ -0,0 +1,86 @@ +package io.goodforgod.gson.configuration; + +import com.google.gson.Gson; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneOffset; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +/** + * @author Anton Kurako (GoodforGod) + * @since 19.01.2022 + */ +class GsonFactoryTests extends Assertions { + + static class User { + + private String name; + private LocalDateTime value; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public LocalDateTime getValue() { + return value; + } + + public void setValue(LocalDateTime value) { + this.value = value; + } + } + + private static final LocalDateTime VALUE_TIME = LocalDateTime.ofInstant(Instant.EPOCH, ZoneOffset.UTC); + private static final String VALUE = "1970-01-01T00-00-00"; + + private final GsonFactory factory = new GsonFactory(); + + @Test + void serializationIsValid() { + final Gson gson = factory.build(); + + final User user = new User(); + user.setName("Bob"); + user.setValue(VALUE_TIME); + + final String json = gson.toJson(user); + assertNotNull(json); + } + + @Test + void deserializationIsValid() { + final Gson gson = factory.build(); + + final String json = "{\"name\":\"Bob\",\"value\":\"" + VALUE + "\"}"; + + final User user = gson.fromJson(json, User.class); + assertNotNull(user); + } + + @Test + void serializationForJavaISOIsValid() { + final Gson gson = factory.buildJavaISO(); + + final User user = new User(); + user.setName("Bob"); + user.setValue(VALUE_TIME); + + final String json = gson.toJson(user); + assertNotNull(json); + } + + @Test + void deserializationForJavaISOIsValid() { + final Gson gson = factory.buildJavaISO(); + + final String json = "{\"name\":\"Bob\",\"value\":\"" + VALUE + "\"}"; + + final User user = gson.fromJson(json, User.class); + assertNotNull(user); + } +} diff --git a/src/test/java/io/goodforgod/gson/configuration/serializer/DayOfWeekDeserializerTests.java b/src/test/java/io/goodforgod/gson/configuration/serializer/DayOfWeekDeserializerTests.java index d404bef..358fb06 100644 --- a/src/test/java/io/goodforgod/gson/configuration/serializer/DayOfWeekDeserializerTests.java +++ b/src/test/java/io/goodforgod/gson/configuration/serializer/DayOfWeekDeserializerTests.java @@ -1,9 +1,8 @@ package io.goodforgod.gson.configuration.serializer; import com.google.gson.Gson; -import com.google.gson.GsonBuilder; import com.google.gson.JsonParseException; -import io.goodforgod.gson.configuration.deserializer.DayOfWeekDeserializer; +import io.goodforgod.gson.configuration.GsonAdapterBuilder; import java.time.DayOfWeek; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -40,10 +39,7 @@ public void setValue(DayOfWeek value) { private static final String VALUE = "MONDAY"; private static final String VALUE_NUMBER = "1"; - private final Gson adapter = new GsonBuilder() - .registerTypeAdapter(DayOfWeek.class, DayOfWeekSerializer.INSTANCE) - .registerTypeAdapter(DayOfWeek.class, DayOfWeekDeserializer.INSTANCE) - .create(); + private final Gson adapter = GsonAdapterBuilder.builder().create(); @Test void serializationIsValid() { diff --git a/src/test/java/io/goodforgod/gson/configuration/serializer/InstantDeserializerTests.java b/src/test/java/io/goodforgod/gson/configuration/serializer/InstantDeserializerTests.java index 1ef5be3..027721a 100644 --- a/src/test/java/io/goodforgod/gson/configuration/serializer/InstantDeserializerTests.java +++ b/src/test/java/io/goodforgod/gson/configuration/serializer/InstantDeserializerTests.java @@ -3,6 +3,7 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonParseException; +import io.goodforgod.gson.configuration.GsonAdapterBuilder; import io.goodforgod.gson.configuration.deserializer.InstantDeserializer; import java.time.*; import java.time.format.DateTimeFormatter; @@ -44,10 +45,7 @@ public void setValue(Instant value) { private static final Instant VALUE_TIME = OffsetDateTime.ofInstant(Instant.EPOCH, ZoneId.of("UTC")).toInstant(); private static final String VALUE = "1970-01-01T00:00:00Z"; - private final Gson adapter = new GsonBuilder() - .registerTypeAdapter(Instant.class, InstantSerializer.INSTANCE) - .registerTypeAdapter(Instant.class, InstantDeserializer.INSTANCE) - .create(); + private final Gson adapter = GsonAdapterBuilder.builder().create(); private final Gson adapterCustom = new GsonBuilder() .registerTypeAdapter(Instant.class, new InstantSerializer(DateTimeFormatter.ofPattern(CUSTOM_ISO) diff --git a/src/test/java/io/goodforgod/gson/configuration/serializer/LocalDateDeserializerTests.java b/src/test/java/io/goodforgod/gson/configuration/serializer/LocalDateDeserializerTests.java index 77b2155..f11a90d 100644 --- a/src/test/java/io/goodforgod/gson/configuration/serializer/LocalDateDeserializerTests.java +++ b/src/test/java/io/goodforgod/gson/configuration/serializer/LocalDateDeserializerTests.java @@ -3,6 +3,7 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonParseException; +import io.goodforgod.gson.configuration.GsonAdapterBuilder; import io.goodforgod.gson.configuration.deserializer.LocalDateDeserializer; import java.time.DateTimeException; import java.time.LocalDate; @@ -44,10 +45,7 @@ public void setValue(LocalDate value) { private static final LocalDate VALUE_TIME = LocalDate.EPOCH; private static final String VALUE = "1970-01-01"; - private final Gson adapter = new GsonBuilder() - .registerTypeAdapter(LocalDate.class, LocalDateSerializer.INSTANCE) - .registerTypeAdapter(LocalDate.class, LocalDateDeserializer.INSTANCE) - .create(); + private final Gson adapter = GsonAdapterBuilder.builder().create(); private final Gson adapterCustom = new GsonBuilder() .registerTypeAdapter(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern(CUSTOM_ISO))) diff --git a/src/test/java/io/goodforgod/gson/configuration/serializer/LocalDateTimeDeserializerTests.java b/src/test/java/io/goodforgod/gson/configuration/serializer/LocalDateTimeDeserializerTests.java index 729cae6..02b0a2b 100644 --- a/src/test/java/io/goodforgod/gson/configuration/serializer/LocalDateTimeDeserializerTests.java +++ b/src/test/java/io/goodforgod/gson/configuration/serializer/LocalDateTimeDeserializerTests.java @@ -3,6 +3,7 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonParseException; +import io.goodforgod.gson.configuration.GsonAdapterBuilder; import io.goodforgod.gson.configuration.deserializer.LocalDateTimeDeserializer; import java.time.DateTimeException; import java.time.Instant; @@ -46,10 +47,7 @@ public void setValue(LocalDateTime value) { private static final LocalDateTime VALUE_TIME = LocalDateTime.ofInstant(Instant.EPOCH, ZoneOffset.UTC); private static final String VALUE = "1970-01-01T00:00:00.000"; - private final Gson adapter = new GsonBuilder() - .registerTypeAdapter(LocalDateTime.class, LocalDateTimeSerializer.INSTANCE) - .registerTypeAdapter(LocalDateTime.class, LocalDateTimeDeserializer.INSTANCE) - .create(); + private final Gson adapter = GsonAdapterBuilder.builder().create(); private final Gson adapterCustom = new GsonBuilder() .registerTypeAdapter(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(CUSTOM_ISO))) diff --git a/src/test/java/io/goodforgod/gson/configuration/serializer/LocalTimeDeserializerTests.java b/src/test/java/io/goodforgod/gson/configuration/serializer/LocalTimeDeserializerTests.java index 328dc07..dcc58ab 100644 --- a/src/test/java/io/goodforgod/gson/configuration/serializer/LocalTimeDeserializerTests.java +++ b/src/test/java/io/goodforgod/gson/configuration/serializer/LocalTimeDeserializerTests.java @@ -3,6 +3,7 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonParseException; +import io.goodforgod.gson.configuration.GsonAdapterBuilder; import io.goodforgod.gson.configuration.deserializer.LocalTimeDeserializer; import java.time.DateTimeException; import java.time.LocalTime; @@ -46,10 +47,7 @@ public void setValue(LocalTime value) { private static final LocalTime VALUE_TIME = LocalTime.MIN; private static final String VALUE = "00:00:00.000"; - private final Gson adapter = new GsonBuilder() - .registerTypeAdapter(LocalTime.class, LocalTimeSerializer.INSTANCE) - .registerTypeAdapter(LocalTime.class, LocalTimeDeserializer.INSTANCE) - .create(); + private final Gson adapter = GsonAdapterBuilder.builder().create(); private final Gson adapterCustom = new GsonBuilder() .registerTypeAdapter(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern(CUSTOM_ISO))) diff --git a/src/test/java/io/goodforgod/gson/configuration/serializer/MonthDayDeserializerTests.java b/src/test/java/io/goodforgod/gson/configuration/serializer/MonthDayDeserializerTests.java index da24cf1..2fb687d 100644 --- a/src/test/java/io/goodforgod/gson/configuration/serializer/MonthDayDeserializerTests.java +++ b/src/test/java/io/goodforgod/gson/configuration/serializer/MonthDayDeserializerTests.java @@ -1,9 +1,8 @@ package io.goodforgod.gson.configuration.serializer; import com.google.gson.Gson; -import com.google.gson.GsonBuilder; import com.google.gson.JsonParseException; -import io.goodforgod.gson.configuration.deserializer.MonthDayDeserializer; +import io.goodforgod.gson.configuration.GsonAdapterBuilder; import java.time.MonthDay; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -39,10 +38,7 @@ public void setValue(MonthDay value) { private static final MonthDay VALUE = MonthDay.of(1, 1); private static final String VALUE_AS_STRING = "01-01"; - private final Gson adapter = new GsonBuilder() - .registerTypeAdapter(MonthDay.class, MonthDaySerializer.INSTANCE) - .registerTypeAdapter(MonthDay.class, MonthDayDeserializer.INSTANCE) - .create(); + private final Gson adapter = GsonAdapterBuilder.builder().create(); @Test void serializationIsValid() { diff --git a/src/test/java/io/goodforgod/gson/configuration/serializer/MonthDeserializerTests.java b/src/test/java/io/goodforgod/gson/configuration/serializer/MonthDeserializerTests.java index b83df38..833ab3a 100644 --- a/src/test/java/io/goodforgod/gson/configuration/serializer/MonthDeserializerTests.java +++ b/src/test/java/io/goodforgod/gson/configuration/serializer/MonthDeserializerTests.java @@ -1,9 +1,8 @@ package io.goodforgod.gson.configuration.serializer; import com.google.gson.Gson; -import com.google.gson.GsonBuilder; import com.google.gson.JsonParseException; -import io.goodforgod.gson.configuration.deserializer.MonthDeserializer; +import io.goodforgod.gson.configuration.GsonAdapterBuilder; import java.time.Month; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -40,10 +39,7 @@ public void setValue(Month value) { private static final String VALUE = "JANUARY"; private static final String VALUE_NUMBER = "1"; - private final Gson adapter = new GsonBuilder() - .registerTypeAdapter(Month.class, MonthSerializer.INSTANCE) - .registerTypeAdapter(Month.class, MonthDeserializer.INSTANCE) - .create(); + private final Gson adapter = GsonAdapterBuilder.builder().create(); @Test void serializationIsValid() { diff --git a/src/test/java/io/goodforgod/gson/configuration/serializer/OffsetDateTimeDeserializerTests.java b/src/test/java/io/goodforgod/gson/configuration/serializer/OffsetDateTimeDeserializerTests.java index 33eae03..f15f00b 100644 --- a/src/test/java/io/goodforgod/gson/configuration/serializer/OffsetDateTimeDeserializerTests.java +++ b/src/test/java/io/goodforgod/gson/configuration/serializer/OffsetDateTimeDeserializerTests.java @@ -3,6 +3,7 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonParseException; +import io.goodforgod.gson.configuration.GsonAdapterBuilder; import io.goodforgod.gson.configuration.deserializer.OffsetDateTimeDeserializer; import java.time.DateTimeException; import java.time.Instant; @@ -49,10 +50,7 @@ public void setValue(OffsetDateTime value) { private static final OffsetDateTime VALUE_TYPE_MOSCOW = OffsetDateTime.ofInstant(Instant.EPOCH, ZoneId.of("+03:00")); private static final String VALUE_STR_MOSCOW = "1970-01-01T03:00:00.000+03:00"; - private final Gson adapter = new GsonBuilder() - .registerTypeAdapter(OffsetDateTime.class, OffsetDateTimeSerializer.INSTANCE) - .registerTypeAdapter(OffsetDateTime.class, OffsetDateTimeDeserializer.INSTANCE) - .create(); + private final Gson adapter = GsonAdapterBuilder.builder().create(); private final Gson adapterCustom = new GsonBuilder() .registerTypeAdapter(OffsetDateTime.class, new OffsetDateTimeSerializer(DateTimeFormatter.ofPattern(CUSTOM_ISO))) diff --git a/src/test/java/io/goodforgod/gson/configuration/serializer/OffsetTimeDeserializerTests.java b/src/test/java/io/goodforgod/gson/configuration/serializer/OffsetTimeDeserializerTests.java index afcae02..4a19a11 100644 --- a/src/test/java/io/goodforgod/gson/configuration/serializer/OffsetTimeDeserializerTests.java +++ b/src/test/java/io/goodforgod/gson/configuration/serializer/OffsetTimeDeserializerTests.java @@ -3,6 +3,7 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonParseException; +import io.goodforgod.gson.configuration.GsonAdapterBuilder; import io.goodforgod.gson.configuration.deserializer.OffsetTimeDeserializer; import java.time.DateTimeException; import java.time.LocalTime; @@ -46,10 +47,7 @@ public void setValue(OffsetTime value) { private static final OffsetTime VALUE_TIME = OffsetTime.of(LocalTime.MIN, ZoneOffset.UTC); private static final String VALUE = "00:00:00.000Z"; - private final Gson adapter = new GsonBuilder() - .registerTypeAdapter(OffsetTime.class, OffsetTimeSerializer.INSTANCE) - .registerTypeAdapter(OffsetTime.class, OffsetTimeDeserializer.INSTANCE) - .create(); + private final Gson adapter = GsonAdapterBuilder.builder().create(); private final Gson adapterCustom = new GsonBuilder() .registerTypeAdapter(OffsetTime.class, new OffsetTimeSerializer(DateTimeFormatter.ofPattern(CUSTOM_ISO))) diff --git a/src/test/java/io/goodforgod/gson/configuration/serializer/YearDeserializerTests.java b/src/test/java/io/goodforgod/gson/configuration/serializer/YearDeserializerTests.java index eb65aa6..f40607d 100644 --- a/src/test/java/io/goodforgod/gson/configuration/serializer/YearDeserializerTests.java +++ b/src/test/java/io/goodforgod/gson/configuration/serializer/YearDeserializerTests.java @@ -1,9 +1,8 @@ package io.goodforgod.gson.configuration.serializer; import com.google.gson.Gson; -import com.google.gson.GsonBuilder; import com.google.gson.JsonParseException; -import io.goodforgod.gson.configuration.deserializer.YearDeserializer; +import io.goodforgod.gson.configuration.GsonAdapterBuilder; import java.time.Year; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -39,10 +38,7 @@ public void setValue(Year value) { private static final Year VALUE_TIME = Year.of(2000); private static final String VALUE = "2000"; - private final Gson adapter = new GsonBuilder() - .registerTypeAdapter(Year.class, YearSerializer.INSTANCE) - .registerTypeAdapter(Year.class, YearDeserializer.INSTANCE) - .create(); + private final Gson adapter = GsonAdapterBuilder.builder().create(); @Test void serializationIsValid() { diff --git a/src/test/java/io/goodforgod/gson/configuration/serializer/YearMonthDeserializerTests.java b/src/test/java/io/goodforgod/gson/configuration/serializer/YearMonthDeserializerTests.java index 03b69dd..4dab74b 100644 --- a/src/test/java/io/goodforgod/gson/configuration/serializer/YearMonthDeserializerTests.java +++ b/src/test/java/io/goodforgod/gson/configuration/serializer/YearMonthDeserializerTests.java @@ -1,9 +1,8 @@ package io.goodforgod.gson.configuration.serializer; import com.google.gson.Gson; -import com.google.gson.GsonBuilder; import com.google.gson.JsonParseException; -import io.goodforgod.gson.configuration.deserializer.YearMonthDeserializer; +import io.goodforgod.gson.configuration.GsonAdapterBuilder; import java.time.YearMonth; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -39,10 +38,7 @@ public void setValue(YearMonth value) { private static final YearMonth VALUE = YearMonth.of(2000, 1); private static final String VALUE_AS_STRING = "2000-01"; - private final Gson adapter = new GsonBuilder() - .registerTypeAdapter(YearMonth.class, YearMonthSerializer.INSTANCE) - .registerTypeAdapter(YearMonth.class, YearMonthDeserializer.INSTANCE) - .create(); + private final Gson adapter = GsonAdapterBuilder.builder().create(); @Test void serializationIsValid() { diff --git a/src/test/java/io/goodforgod/gson/configuration/serializer/ZoneIdDeserializerTests.java b/src/test/java/io/goodforgod/gson/configuration/serializer/ZoneIdDeserializerTests.java index 26f50b6..106f1c2 100644 --- a/src/test/java/io/goodforgod/gson/configuration/serializer/ZoneIdDeserializerTests.java +++ b/src/test/java/io/goodforgod/gson/configuration/serializer/ZoneIdDeserializerTests.java @@ -1,9 +1,8 @@ package io.goodforgod.gson.configuration.serializer; import com.google.gson.Gson; -import com.google.gson.GsonBuilder; import com.google.gson.JsonParseException; -import io.goodforgod.gson.configuration.deserializer.ZoneIdDeserializer; +import io.goodforgod.gson.configuration.GsonAdapterBuilder; import java.time.ZoneId; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -39,10 +38,7 @@ public void setValue(ZoneId value) { private static final ZoneId VALUE_TIME = ZoneId.of("UTC"); private static final String VALUE = "UTC"; - private final Gson adapter = new GsonBuilder() - .registerTypeAdapter(ZoneId.class, ZoneIdSerializer.INSTANCE) - .registerTypeAdapter(ZoneId.class, ZoneIdDeserializer.INSTANCE) - .create(); + private final Gson adapter = GsonAdapterBuilder.builder().create(); @Test void serializationIsValid() { diff --git a/src/test/java/io/goodforgod/gson/configuration/serializer/ZoneOffsetDeserializerTests.java b/src/test/java/io/goodforgod/gson/configuration/serializer/ZoneOffsetDeserializerTests.java index af14c4b..00e4270 100644 --- a/src/test/java/io/goodforgod/gson/configuration/serializer/ZoneOffsetDeserializerTests.java +++ b/src/test/java/io/goodforgod/gson/configuration/serializer/ZoneOffsetDeserializerTests.java @@ -1,9 +1,8 @@ package io.goodforgod.gson.configuration.serializer; import com.google.gson.Gson; -import com.google.gson.GsonBuilder; import com.google.gson.JsonParseException; -import io.goodforgod.gson.configuration.deserializer.ZoneOffsetDeserializer; +import io.goodforgod.gson.configuration.GsonAdapterBuilder; import java.time.ZoneOffset; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -39,10 +38,7 @@ public void setValue(ZoneOffset value) { private static final ZoneOffset VALUE = ZoneOffset.of("+02:00"); private static final String VALUE_AS_STRING = "+02:00"; - private final Gson adapter = new GsonBuilder() - .registerTypeAdapter(ZoneOffset.class, ZoneOffsetSerializer.INSTANCE) - .registerTypeAdapter(ZoneOffset.class, ZoneOffsetDeserializer.INSTANCE) - .create(); + private final Gson adapter = GsonAdapterBuilder.builder().create(); @Test void serializationIsValid() { diff --git a/src/test/java/io/goodforgod/gson/configuration/serializer/ZonedDateTimeDeserializerTests.java b/src/test/java/io/goodforgod/gson/configuration/serializer/ZonedDateTimeDeserializerTests.java index beca413..d57897b 100644 --- a/src/test/java/io/goodforgod/gson/configuration/serializer/ZonedDateTimeDeserializerTests.java +++ b/src/test/java/io/goodforgod/gson/configuration/serializer/ZonedDateTimeDeserializerTests.java @@ -3,6 +3,7 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonParseException; +import io.goodforgod.gson.configuration.GsonAdapterBuilder; import io.goodforgod.gson.configuration.deserializer.ZonedDateTimeDeserializer; import java.time.*; import java.time.format.DateTimeFormatter; @@ -48,10 +49,7 @@ public void setValue(ZonedDateTime value) { ZoneId.of("Europe/Paris")); private static final String VALUE_AS_STRING_NON_UTC = "1970-01-01T02:00:00.000+01:00[Europe/Paris]"; - private final Gson adapter = new GsonBuilder() - .registerTypeAdapter(ZonedDateTime.class, ZonedDateTimeSerializer.INSTANCE) - .registerTypeAdapter(ZonedDateTime.class, ZonedDateTimeDeserializer.INSTANCE) - .create(); + private final Gson adapter = GsonAdapterBuilder.builder().create(); private final Gson adapterCustom = new GsonBuilder() .registerTypeAdapter(ZonedDateTime.class, new ZonedDateTimeSerializer(DateTimeFormatter.ofPattern(CUSTOM_ISO))) From e1363ea98892634bbbe07eee887de889f107ae41 Mon Sep 17 00:00:00 2001 From: Anton Kurako Date: Wed, 19 Jan 2022 01:16:31 +0300 Subject: [PATCH 6/9] [1.2.0-SNAPSHOT] DateTimeFormatters#JAVA_ISO_DATE renamed --- .../io/goodforgod/gson/configuration/DateTimeFormatters.java | 2 +- .../io/goodforgod/gson/configuration/GsonConfiguration.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/io/goodforgod/gson/configuration/DateTimeFormatters.java b/src/main/java/io/goodforgod/gson/configuration/DateTimeFormatters.java index 04f8bbe..90a92dc 100644 --- a/src/main/java/io/goodforgod/gson/configuration/DateTimeFormatters.java +++ b/src/main/java/io/goodforgod/gson/configuration/DateTimeFormatters.java @@ -135,5 +135,5 @@ private DateTimeFormatters() {} * ISO8601 for {@link java.util.Date} and {@link java.sql.Timestamp} analog to default Java ISO * {@link DateTimeFormatter} */ - public static final String ISO_DATE_JAVA = "yyyy-MM-dd'T'HH:mm:ssXXX"; + public static final String JAVA_ISO_DATE = "yyyy-MM-dd'T'HH:mm:ssXXX"; } diff --git a/src/main/java/io/goodforgod/gson/configuration/GsonConfiguration.java b/src/main/java/io/goodforgod/gson/configuration/GsonConfiguration.java index 21a3feb..c9ded75 100644 --- a/src/main/java/io/goodforgod/gson/configuration/GsonConfiguration.java +++ b/src/main/java/io/goodforgod/gson/configuration/GsonConfiguration.java @@ -120,7 +120,7 @@ public static GsonConfiguration of() { public static GsonConfiguration ofJavaISO() { final GsonConfiguration configuration = new GsonConfiguration(); - configuration.setDateFormat(DateTimeFormatters.ISO_DATE_JAVA); + configuration.setDateFormat(DateTimeFormatters.JAVA_ISO_DATE); configuration.setInstantFormat(DateTimeFormatter.ISO_INSTANT); configuration.setLocalDateFormat(DateTimeFormatter.ISO_LOCAL_DATE); configuration.setLocalTimeFormat(DateTimeFormatter.ISO_LOCAL_TIME); From 207e44bb50fbbcc0f3f9ca838bd0e12d9b9f3eb1 Mon Sep 17 00:00:00 2001 From: Anton Kurako Date: Wed, 19 Jan 2022 01:28:09 +0300 Subject: [PATCH 7/9] [1.2.0-SNAPSHOT] GsonConfiguration#forceResolverStrict and GsonConfiguration#forceIsoChronology properties support and tests added --- .../goodforgod/gson/configuration/GsonConfiguration.java | 8 ++++++++ .../io/goodforgod/gson/configuration/GsonProperties.java | 3 +++ .../GsonConfigurationFromPropertiesTests.java | 3 +++ src/test/resources/gson.properties | 3 +++ 4 files changed, 17 insertions(+) diff --git a/src/main/java/io/goodforgod/gson/configuration/GsonConfiguration.java b/src/main/java/io/goodforgod/gson/configuration/GsonConfiguration.java index c9ded75..824eadd 100644 --- a/src/main/java/io/goodforgod/gson/configuration/GsonConfiguration.java +++ b/src/main/java/io/goodforgod/gson/configuration/GsonConfiguration.java @@ -153,6 +153,9 @@ private static GsonConfiguration ofProperties(GsonConfiguration configuration, P final String formatMonthDay = properties.getProperty(GsonProperties.FORMAT_MONTH_DAY); final String formatDate = properties.getProperty(GsonProperties.FORMAT_DATE); + final String forceIsoChronologyProp = properties.getProperty(GsonProperties.FORCE_ISO_CHRONOLOGY); + final String forceResolverStrictProp = properties.getProperty(GsonProperties.FORCE_RESOLVER_STRICT); + final String fieldNamingPolicy = properties.getProperty(GsonProperties.POLICY_FIELD_NAMING); final String longSerializationPolicy = properties.getProperty(GsonProperties.POLICY_LONG_SERIALIZATION); @@ -188,6 +191,11 @@ private static GsonConfiguration ofProperties(GsonConfiguration configuration, P if (formatDate != null) configuration.setDateFormat(formatDate); + if (forceIsoChronologyProp != null) + configuration.setForceIsoChronology(Boolean.parseBoolean(forceIsoChronologyProp)); + if (forceResolverStrictProp != null) + configuration.setForceResolverStrict(Boolean.parseBoolean(forceResolverStrictProp)); + if (fieldNamingPolicy != null) configuration.setFieldNamingPolicy(FieldNamingPolicy.valueOf(fieldNamingPolicy)); if (longSerializationPolicy != null) diff --git a/src/main/java/io/goodforgod/gson/configuration/GsonProperties.java b/src/main/java/io/goodforgod/gson/configuration/GsonProperties.java index b923234..9016398 100644 --- a/src/main/java/io/goodforgod/gson/configuration/GsonProperties.java +++ b/src/main/java/io/goodforgod/gson/configuration/GsonProperties.java @@ -22,6 +22,9 @@ private GsonProperties() {} public static final String FORMAT_MONTH_DAY = PREFIX + "format.monthDay"; public static final String FORMAT_DATE = PREFIX + "format.date"; + public static final String FORCE_ISO_CHRONOLOGY = PREFIX + "forceIsoChronology"; + public static final String FORCE_RESOLVER_STRICT = PREFIX + "forceResolverStrict"; + public static final String LENIENT = PREFIX + "lenient"; public static final String SERIALIZE_NULLS = PREFIX + "serializeNulls"; public static final String PRETTY_PRINTING = PREFIX + "prettyPrinting"; diff --git a/src/test/java/io/goodforgod/gson/configuration/GsonConfigurationFromPropertiesTests.java b/src/test/java/io/goodforgod/gson/configuration/GsonConfigurationFromPropertiesTests.java index 5559edf..31097d3 100644 --- a/src/test/java/io/goodforgod/gson/configuration/GsonConfigurationFromPropertiesTests.java +++ b/src/test/java/io/goodforgod/gson/configuration/GsonConfigurationFromPropertiesTests.java @@ -31,6 +31,9 @@ void configurationPropertiesApplied() throws Exception { assertNotNull(configuration.getOffsetTimeFormat()); assertNotNull(configuration.getOffsetDateTimeFormat()); + assertTrue(configuration.isForceIsoChronology()); + assertTrue(configuration.isForceResolverStrict()); + assertTrue(configuration.isLenient()); assertTrue(configuration.isComplexMapKeySerialization()); assertTrue(configuration.isPrettyPrinting()); diff --git a/src/test/resources/gson.properties b/src/test/resources/gson.properties index c2beefb..e64022a 100644 --- a/src/test/resources/gson.properties +++ b/src/test/resources/gson.properties @@ -10,6 +10,9 @@ gson.format.yearMonth=uuuu-MM gson.format.monthDay=MM-dd gson.format.date=uuuu-MM-dd'T'HH:mm:ss.SSSXXX +gson.forceIsoChronology=true +gson.forceResolverStrict=true + gson.lenient=true gson.serializeNulls=true gson.prettyPrinting=true From 4831478294434135658e744c13bbb54be11ce849 Mon Sep 17 00:00:00 2001 From: Anton Kurako Date: Wed, 19 Jan 2022 01:34:26 +0300 Subject: [PATCH 8/9] [1.2.0] Release prepared --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index f0b49bd..5228752 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,6 +1,6 @@ groupId=io.goodforgod artifactId=gson-configuration -artifactVersion=1.2.0-SNAPSHOT +artifactVersion=1.2.0 ##### GRADLE ##### From eaf9021a0fe9e3f361979f2462960987ab1e9cbd Mon Sep 17 00:00:00 2001 From: Anton Kurako Date: Wed, 19 Jan 2022 01:45:47 +0300 Subject: [PATCH 9/9] [1.2.0] README.md improved --- README.md | 43 +++++++++++++++++++++++++++++-------------- 1 file changed, 29 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index ac89a4a..39589f4 100644 --- a/README.md +++ b/README.md @@ -44,28 +44,36 @@ datetime objects, supported list: - ZoneId - ZoneOffset -All adapters register with **ISO8601** formatters by defaults, but you can register them manually with your formatter. +## Formatters -## Formats +Gson Configuration by default comes with [ISO8601 with millis precision](https://goodforgod.dev/posts/2/) +(basically default Java ISO8601 formatters but with millis precision) -Gson Configuration by default comes with [ISO8601](https://en.wikipedia.org/wiki/ISO_8601) with millis precision for all APIs: - -Here is list of default formatters for all *java.time.** APIs: +Here is list of such formatters: - LocalDateTime - *uuuu-MM-dd'T'HH:mm:ss[.SSS]* - LocalDate - *uuuu-MM-dd* - LocalTime - *HH:mm:ss[.SSS]* - OffsetDateTime - *uuuu-MM-dd'T'HH:mm:ss[.SSS]XXX* - OffsetTime - *HH:mm:ss[.SSS]XXX* -- ZonedDateTime - *uuuu-MM-dd'T'HH:mm:ss[.SSS]XXX[VV]* +- ZonedDateTime - *uuuu-MM-dd'T'HH:mm:ss[.SSS]XXX['['VV']']* + +If you want to know more about why use such Java Date & Time formats, you can [read more here](https://goodforgod.dev/posts/2/) + +```java +GsonConfiguration configuration = GsonConfiguration.of(); +``` -If you want to know more about Java Date & Time formats, you can [read more here](https://goodforgod.dev/posts/2/) +You can also use default Java ISO8601 formatters by: +```java +GsonConfiguration configuration = GsonConfiguration.ofJavaISO(); +``` ## Gson Configuration Library provides configuration for configuring *GsonBuilder* for most properties: ```java -final GsonBuilder builder = new GsonConfiguration() +GsonBuilder builder = new GsonConfiguration() .setDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX") .setInstantFormat("uuuu-MM-dd HH:mm:ss") .setComplexMapKeySerialization(true) @@ -82,7 +90,7 @@ final GsonBuilder builder = new GsonConfiguration() You can configure DateTimeFormatters for provided adapters: ```java -final GsonBuilder builder = new GsonConfiguration() +GsonBuilder builder = new GsonConfiguration() .setInstantFormat("uuuu-MM-dd HH:mm:ss") .builder(); ``` @@ -93,11 +101,11 @@ GsonConfiguration also can be filled from *properties* file. How to build GsonConfiguration from Properties: ```java -final InputStream resource = getClass().getClassLoader().getResourceAsStream("gson.properties"); -final Properties properties = new Properties(); +InputStream resource = getClass().getClassLoader().getResourceAsStream("gson.properties"); +Properties properties = new Properties(); properties.load(resource); -final GsonConfiguration configuration = GsonConfiguration.ofProperties(properties); +GsonConfiguration configuration = GsonConfiguration.ofProperties(properties); ``` Full list of properties ([check GsonProperties](https://github.com/GoodforGod/gson-configuration/blob/master/src/main/java/io/gson/adapters/config/GsonProperties.java)): @@ -114,6 +122,9 @@ gson.format.yearMonth=uuuu-MM gson.format.monthDay=MM-dd gson.format.date=yyyy-MM-dd'T'HH:mm:ss.SSSXXX +gson.forceIsoChronology=true +gson.forceResolverStrict=true + gson.lenient=true gson.serializeNulls=true gson.prettyPrinting=true @@ -131,11 +142,15 @@ gson.policy.longSerialization=STRING Gson can also be instantiated via properties using *GsonFactory*. *GsonFactory* is looking for property file in root *resource*: **gson.properties** - ```java Gson gson = new GsonFactory().build(); ``` +There is respected method to build Gson with Java ISO8601 formatters as defaults: +```java +Gson gson = new GsonFactory().buildJavaISO(); +``` + ## Gson Builder All adapters already registered via when using *GsonConfiguration#builder*. @@ -149,7 +164,7 @@ GsonBuilder builder = GsonAdapters.builder(); You can register them manually: ```java GsonBuilder builder = new GsonBuilder() - .registerTypeAdapter(LocalDate.class, new LocalDateSerializer()) + .registerTypeAdapter(LocalDate.class, LocalDateSerializer.INSTANCE) ``` You can register with custom formatter also: