Skip to content

Commit 8d789bb

Browse files
committed
#481 Enhance TemporalType with matching export format along with additional LocalTime/LocalDateTime types
1 parent 0ef619d commit 8d789bb

2 files changed

Lines changed: 81 additions & 9 deletions

File tree

src/main/java/ch/jalu/configme/properties/types/TemporalType.java

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
import org.jetbrains.annotations.Nullable;
66

77
import java.time.LocalDate;
8+
import java.time.LocalDateTime;
9+
import java.time.LocalTime;
810
import java.time.format.DateTimeFormatter;
911
import java.time.format.DateTimeParseException;
1012
import java.time.temporal.Temporal;
@@ -22,15 +24,34 @@ public class TemporalType<T extends Temporal> extends PropertyAndLeafType<T> {
2224
/** Local Date temporal type. */
2325
public static final TemporalType<LocalDate> LOCAL_DATE = new TemporalType<>(
2426
LocalDate.class, Arrays.asList("yyyy-MM-dd", "dd.MM.yyyy", "MM/dd/yyyy"), LocalDate::parse);
27+
/** Local Time temporal type. */
28+
public static final TemporalType<LocalTime> LOCAL_TIME = new TemporalType<>(
29+
LocalTime.class, Arrays.asList("HH:mm:ss", "HH.mm", "HH:mm"), LocalTime::parse);
30+
/** Local Date Time temporal type. */
31+
public static final TemporalType<LocalDateTime> LOCAL_DATE_TIME = new TemporalType<>(
32+
LocalDateTime.class, Arrays.asList("yyyy-MM-dd HH:mm:ss", "dd.MM.yyyy HH:mm:ss", "MM/dd/yyyy HH:mm:ss"),
33+
LocalDateTime::parse);
2534

2635
private final List<String> supportedFormats;
2736
private final BiFunction<String, DateTimeFormatter, T> temporalParser;
37+
private String defaultExportFormat;
2838

29-
protected TemporalType(Class<T> clazz, List<String> supportedFormats,
30-
BiFunction<String, DateTimeFormatter, T> defaultParser) {
39+
/**
40+
* Constructor.
41+
*
42+
* @param clazz the temporal type this type should convert to
43+
* @param supportedFormats list of conversion formats supported for this type
44+
* @param defaultParser function which can parse a value to this type in one of the given supportedFormats
45+
*/
46+
public TemporalType(@NotNull Class<T> clazz, @NotNull List<String> supportedFormats,
47+
@NotNull BiFunction<String, DateTimeFormatter, T> defaultParser) {
3148
super(clazz);
49+
if (supportedFormats.isEmpty()) {
50+
throw new IllegalArgumentException("At least one supported format must be provided.");
51+
}
3252
this.supportedFormats = supportedFormats;
3353
this.temporalParser = defaultParser;
54+
this.defaultExportFormat = supportedFormats.get(0);
3455
}
3556

3657
@Override
@@ -43,16 +64,15 @@ protected TemporalType(Class<T> clazz, List<String> supportedFormats,
4364

4465
@Override
4566
public @Nullable Object toExportValue(@NotNull T value) {
46-
if (value instanceof LocalDate) {
47-
return LocalDate.from(value).toString();
48-
}
49-
return value.toString();
67+
return DateTimeFormatter.ofPattern(this.defaultExportFormat).format(value);
5068
}
5169

5270
private T convertToTemporalType(String temporalText) {
5371
for (String format: this.supportedFormats) {
5472
try {
55-
return this.temporalParser.apply(temporalText, DateTimeFormatter.ofPattern(format));
73+
T parsedValue = this.temporalParser.apply(temporalText, DateTimeFormatter.ofPattern(format));
74+
this.defaultExportFormat = format;
75+
return parsedValue;
5676
} catch (DateTimeParseException e) {
5777
// try next format
5878
}

src/test/java/ch/jalu/configme/properties/types/TemporalTypeTest.java

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,27 +4,49 @@
44
import org.junit.jupiter.api.Test;
55

66
import java.time.LocalDate;
7+
import java.time.LocalDateTime;
8+
import java.time.LocalTime;
9+
import java.util.Collections;
710

811
import static ch.jalu.typeresolver.TypeInfo.of;
912
import static org.hamcrest.MatcherAssert.assertThat;
10-
import static org.hamcrest.Matchers.equalTo;
11-
import static org.hamcrest.Matchers.nullValue;
13+
import static org.hamcrest.Matchers.*;
14+
import static org.junit.jupiter.api.Assertions.assertThrows;
1215

1316
/**
1417
* Test for {@link TemporalType}.
1518
*/
1619
public class TemporalTypeTest {
1720

21+
@Test
22+
void shouldNotAllowToInstantiateTemporalTypeWithInvalidArguments() {
23+
// when
24+
IllegalArgumentException noSupportedFormats = assertThrows(IllegalArgumentException.class,
25+
() -> new TemporalType<>(LocalDate.class, Collections.emptyList(), LocalDate::parse));
26+
27+
// then
28+
assertThat(noSupportedFormats.getMessage(), matchesPattern("At least one supported format must be provided."));
29+
}
30+
1831
@Test
1932
void shouldConvertToGivenTemporalTypeForSupportedFormat() {
2033
// given
2134
ConvertErrorRecorder errorRecorder = new ConvertErrorRecorder();
2235
LocalDate localDate = LocalDate.of(1970, 1, 31);
36+
LocalTime localTimeFull = LocalTime.of(15, 35, 40);
37+
LocalTime localTimeShort = LocalTime.of(15, 35);
38+
LocalDateTime localDateTime = LocalDateTime.of(1970, 1, 31, 15, 35, 40);
2339

2440
// when / then
2541
assertThat(TemporalType.LOCAL_DATE.convert("1970-01-31", of(LocalDate.class), errorRecorder), equalTo(localDate));
2642
assertThat(TemporalType.LOCAL_DATE.convert("31.01.1970", of(LocalDate.class), errorRecorder), equalTo(localDate));
2743
assertThat(TemporalType.LOCAL_DATE.convert("01/31/1970", of(LocalDate.class), errorRecorder), equalTo(localDate));
44+
assertThat(TemporalType.LOCAL_TIME.convert("15:35:40", of(LocalTime.class), errorRecorder), equalTo(localTimeFull));
45+
assertThat(TemporalType.LOCAL_TIME.convert("15.35", of(LocalTime.class), errorRecorder), equalTo(localTimeShort));
46+
assertThat(TemporalType.LOCAL_TIME.convert("15:35", of(LocalTime.class), errorRecorder), equalTo(localTimeShort));
47+
assertThat(TemporalType.LOCAL_DATE_TIME.convert("1970-01-31 15:35:40", of(LocalDateTime.class), errorRecorder), equalTo(localDateTime));
48+
assertThat(TemporalType.LOCAL_DATE_TIME.convert("31.01.1970 15:35:40", of(LocalDateTime.class), errorRecorder), equalTo(localDateTime));
49+
assertThat(TemporalType.LOCAL_DATE_TIME.convert("01/31/1970 15:35:40", of(LocalDateTime.class), errorRecorder), equalTo(localDateTime));
2850
}
2951

3052
@Test
@@ -36,6 +58,13 @@ void shouldReturnNullForUnsupportedFormat() {
3658
assertThat(TemporalType.LOCAL_DATE.convert("31-01-1970", of(LocalDate.class), errorRecorder), nullValue());
3759
assertThat(TemporalType.LOCAL_DATE.convert("1970.01.31", of(LocalDate.class), errorRecorder), nullValue());
3860
assertThat(TemporalType.LOCAL_DATE.convert("1970/01/31", of(LocalDate.class), errorRecorder), nullValue());
61+
assertThat(TemporalType.LOCAL_TIME.convert("25:35:40", of(LocalTime.class), errorRecorder), nullValue());
62+
assertThat(TemporalType.LOCAL_TIME.convert("15.35.40", of(LocalTime.class), errorRecorder), nullValue());
63+
assertThat(TemporalType.LOCAL_TIME.convert("15:35.40", of(LocalTime.class), errorRecorder), nullValue());
64+
assertThat(TemporalType.LOCAL_TIME.convert("15.35:40", of(LocalTime.class), errorRecorder), nullValue());
65+
assertThat(TemporalType.LOCAL_DATE_TIME.convert("31-01-1970 25:35:40", of(LocalDateTime.class), errorRecorder), nullValue());
66+
assertThat(TemporalType.LOCAL_DATE_TIME.convert("1970.01.31 15.35.40", of(LocalDateTime.class), errorRecorder), nullValue());
67+
assertThat(TemporalType.LOCAL_DATE_TIME.convert("1970/01/31 15.35:40", of(LocalDateTime.class), errorRecorder), nullValue());
3968
}
4069

4170
@Test
@@ -45,6 +74,8 @@ void shouldReturnNullForInvalidValue() {
4574

4675
// when / then
4776
assertThat(TemporalType.LOCAL_DATE.convert("test", of(LocalDate.class), errorRecorder), nullValue());
77+
assertThat(TemporalType.LOCAL_TIME.convert("test", of(LocalTime.class), errorRecorder), nullValue());
78+
assertThat(TemporalType.LOCAL_DATE_TIME.convert("test", of(LocalDateTime.class), errorRecorder), nullValue());
4879
}
4980

5081
@Test
@@ -54,11 +85,32 @@ void shouldReturnNullForNull() {
5485

5586
// when / then
5687
assertThat(TemporalType.LOCAL_DATE.convert(null, of(LocalDate.class), errorRecorder), nullValue());
88+
assertThat(TemporalType.LOCAL_TIME.convert(null, of(LocalTime.class), errorRecorder), nullValue());
89+
assertThat(TemporalType.LOCAL_DATE_TIME.convert(null, of(LocalDateTime.class), errorRecorder), nullValue());
5790
}
5891

5992
@Test
6093
void shouldExportValueAsString() {
6194
// given / when / then
6295
assertThat(TemporalType.LOCAL_DATE.toExportValue(LocalDate.of(1970, 1, 31)), equalTo("1970-01-31"));
96+
assertThat(TemporalType.LOCAL_TIME.toExportValue(LocalTime.of(13, 55, 13)), equalTo("13:55:13"));
97+
assertThat(TemporalType.LOCAL_DATE_TIME.toExportValue(LocalDateTime.of(1970, 1, 31, 12, 30, 47)), equalTo("1970-01-31 12:30:47"));
98+
}
99+
100+
@Test
101+
void shouldExportValueInMatchingFormatAsString() {
102+
// given
103+
ConvertErrorRecorder errorRecorder = new ConvertErrorRecorder();
104+
LocalDate localDate = TemporalType.LOCAL_DATE.convert("01/31/1970", errorRecorder);
105+
LocalTime localTime = TemporalType.LOCAL_TIME.convert("11:11", errorRecorder);
106+
LocalDateTime localDateTime = TemporalType.LOCAL_DATE_TIME.convert("31.01.1970 13:55:13", errorRecorder);
107+
108+
// when / then
109+
assertThat(localDate, notNullValue());
110+
assertThat(localTime, notNullValue());
111+
assertThat(localDateTime, notNullValue());
112+
assertThat(TemporalType.LOCAL_DATE.toExportValue(localDate), equalTo("01/31/1970"));
113+
assertThat(TemporalType.LOCAL_TIME.toExportValue(localTime), equalTo("11:11"));
114+
assertThat(TemporalType.LOCAL_DATE_TIME.toExportValue(localDateTime), equalTo("31.01.1970 13:55:13"));
63115
}
64116
}

0 commit comments

Comments
 (0)