Validate `GsonBuilder.setDateFormat` style arguments & extend tests (#2545)

`DateFormat` validates these arguments as well, but it is currently not
documented, see https://bugs.openjdk.org/browse/JDK-8319628.

Also moves the other tests for `setDateFormat(String)` from
DefaultTypeAdaptersTest to GsonBuilderTest.
This commit is contained in:
Marcono1234 2023-11-18 23:09:25 +01:00 committed by GitHub
parent b7c3e1d0b8
commit 6684726476
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 115 additions and 23 deletions

View File

@ -593,8 +593,10 @@ public final class GsonBuilder {
* class. See the documentation in {@link java.text.SimpleDateFormat} for more information on
* valid date and time patterns.
*
* @param pattern the pattern that dates will be serialized/deserialized to/from
* @param pattern the pattern that dates will be serialized/deserialized to/from; can be {@code
* null} to reset the pattern
* @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
* @throws IllegalArgumentException if the pattern is invalid
* @since 1.2
*/
@CanIgnoreReturnValue
@ -611,6 +613,14 @@ public final class GsonBuilder {
return this;
}
private static int checkDateFormatStyle(int style) {
// Valid DateFormat styles are: 0, 1, 2, 3 (FULL, LONG, MEDIUM, SHORT)
if (style < 0 || style > 3) {
throw new IllegalArgumentException("Invalid style: " + style);
}
return style;
}
/**
* Configures Gson to serialize {@code Date} objects according to the style value provided. You
* can call this method or {@link #setDateFormat(String)} multiple times, but only the last
@ -623,11 +633,12 @@ public final class GsonBuilder {
* @param style the predefined date style that date objects will be serialized/deserialized
* to/from
* @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
* @throws IllegalArgumentException if the style is invalid
* @since 1.2
*/
@CanIgnoreReturnValue
public GsonBuilder setDateFormat(int style) {
this.dateStyle = style;
this.dateStyle = checkDateFormatStyle(style);
this.datePattern = null;
return this;
}
@ -645,12 +656,13 @@ public final class GsonBuilder {
* to/from
* @param timeStyle the predefined style for the time portion of the date objects
* @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
* @throws IllegalArgumentException if the style values are invalid
* @since 1.2
*/
@CanIgnoreReturnValue
public GsonBuilder setDateFormat(int dateStyle, int timeStyle) {
this.dateStyle = dateStyle;
this.timeStyle = timeStyle;
this.dateStyle = checkDateFormatStyle(dateStyle);
this.timeStyle = checkDateFormatStyle(timeStyle);
this.datePattern = null;
return this;
}

View File

@ -28,6 +28,8 @@ import java.io.StringWriter;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.text.DateFormat;
import java.util.Date;
import org.junit.Test;
/**
@ -305,4 +307,88 @@ public class GsonBuilderTest {
// But registering type hierarchy adapter for Object should be allowed
gsonBuilder.registerTypeHierarchyAdapter(Object.class, NULL_TYPE_ADAPTER);
}
@Test
public void testSetDateFormatWithInvalidPattern() {
GsonBuilder builder = new GsonBuilder();
String invalidPattern = "This is an invalid Pattern";
IllegalArgumentException e =
assertThrows(IllegalArgumentException.class, () -> builder.setDateFormat(invalidPattern));
assertThat(e)
.hasMessageThat()
.isEqualTo("The date pattern '" + invalidPattern + "' is not valid");
}
@Test
public void testSetDateFormatWithValidPattern() {
GsonBuilder builder = new GsonBuilder();
String validPattern = "yyyy-MM-dd";
// Should not throw an exception
builder.setDateFormat(validPattern);
}
@Test
public void testSetDateFormatNullPattern() {
GsonBuilder builder = new GsonBuilder();
@SuppressWarnings("JavaUtilDate")
Date date = new Date(0);
String originalFormatted = builder.create().toJson(date);
String customFormatted = builder.setDateFormat("yyyy-MM-dd").create().toJson(date);
assertThat(customFormatted).isNotEqualTo(originalFormatted);
// `null` should reset the format to the default
String resetFormatted = builder.setDateFormat(null).create().toJson(date);
assertThat(resetFormatted).isEqualTo(originalFormatted);
}
/**
* Tests behavior for an empty date pattern; this behavior is not publicly documented at the
* moment.
*/
@Test
public void testSetDateFormatEmptyPattern() {
GsonBuilder builder = new GsonBuilder();
@SuppressWarnings("JavaUtilDate")
Date date = new Date(0);
String originalFormatted = builder.create().toJson(date);
String emptyFormatted = builder.setDateFormat(" ").create().toJson(date);
// Empty pattern was ignored
assertThat(emptyFormatted).isEqualTo(originalFormatted);
}
@Test
public void testSetDateFormatValidStyle() {
GsonBuilder builder = new GsonBuilder();
int[] validStyles = {DateFormat.FULL, DateFormat.LONG, DateFormat.MEDIUM, DateFormat.SHORT};
for (int style : validStyles) {
// Should not throw an exception
builder.setDateFormat(style);
builder.setDateFormat(style, style);
}
}
@Test
public void testSetDateFormatInvalidStyle() {
GsonBuilder builder = new GsonBuilder();
IllegalArgumentException e =
assertThrows(IllegalArgumentException.class, () -> builder.setDateFormat(-1));
assertThat(e).hasMessageThat().isEqualTo("Invalid style: -1");
e = assertThrows(IllegalArgumentException.class, () -> builder.setDateFormat(4));
assertThat(e).hasMessageThat().isEqualTo("Invalid style: 4");
e =
assertThrows(
IllegalArgumentException.class, () -> builder.setDateFormat(-1, DateFormat.FULL));
assertThat(e).hasMessageThat().isEqualTo("Invalid style: -1");
e =
assertThrows(
IllegalArgumentException.class, () -> builder.setDateFormat(DateFormat.FULL, -1));
assertThat(e).hasMessageThat().isEqualTo("Invalid style: -1");
}
}

View File

@ -16,7 +16,6 @@
package com.google.gson.functional;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.fail;
import com.google.gson.Gson;
@ -493,6 +492,19 @@ public class DefaultTypeAdaptersTest {
assertThat(cal.get(Calendar.SECOND)).isEqualTo(23);
}
@Test
public void testDateSerializationWithStyle() {
int style = DateFormat.SHORT;
Date date = new Date(0);
String expectedFormatted = DateFormat.getDateTimeInstance(style, style, Locale.US).format(date);
Gson gson = new GsonBuilder().setDateFormat(style, style).create();
String json = gson.toJson(date);
assertThat(json).isEqualTo("\"" + expectedFormatted + "\"");
// Verify that custom style is not equal to default style
assertThat(json).isNotEqualTo(new Gson().toJson(date));
}
@Test
public void testDateSerializationWithPattern() {
String pattern = "yyyy-MM-dd";
@ -738,24 +750,6 @@ public class DefaultTypeAdaptersTest {
assertThat(sb.toString()).isEqualTo("abc");
}
@Test
public void testSetDateFormatWithInvalidPattern() {
GsonBuilder builder = new GsonBuilder();
String invalidPattern = "This is a invalid Pattern";
assertThrows(
IllegalArgumentException.class,
() -> {
builder.setDateFormat(invalidPattern);
});
}
@Test
public void testSetDateFormatWithValidPattern() {
GsonBuilder builder = new GsonBuilder();
String validPattern = "yyyy-MM-dd";
builder.setDateFormat(validPattern);
}
private static class MyClassTypeAdapter extends TypeAdapter<Class<?>> {
@Override
public void write(JsonWriter out, Class<?> value) throws IOException {