Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Validate GsonBuilder.setDateFormat style arguments & extend tests #2545

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 16 additions & 4 deletions gson/src/main/java/com/google/gson/GsonBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -593,8 +593,10 @@ public GsonBuilder disableHtmlEscaping() {
* 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
Expand All @@ -611,6 +613,14 @@ public GsonBuilder setDateFormat(String pattern) {
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
Expand All @@ -623,11 +633,12 @@ public GsonBuilder setDateFormat(String pattern) {
* @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;
}
Expand All @@ -645,12 +656,13 @@ public GsonBuilder setDateFormat(int style) {
* 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;
}
Expand Down
86 changes: 86 additions & 0 deletions gson/src/test/java/com/google/gson/GsonBuilderTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
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;

/**
Expand Down Expand Up @@ -305,4 +307,88 @@ public void testRegisterTypeHierarchyAdapterJsonElements() {
// 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");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -493,6 +492,19 @@ public void testDefaultGregorianCalendarDeserialization() {
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";
Expand Down Expand Up @@ -738,24 +750,6 @@ public void testStringBufferDeserialization() {
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 {
Expand Down