Skip to content

Commit

Permalink
Merge pull request #122 from prowide/gh/issue-118
Browse files Browse the repository at this point in the history
Issue 118: Fix backward compatibility issue on DateTime fields.
  • Loading branch information
fernando-prowide authored Aug 1, 2024
2 parents 4a031ca + 569bfbc commit cab51fc
Show file tree
Hide file tree
Showing 3 changed files with 662 additions and 40 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

import com.google.gson.*;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZoneId;
Expand All @@ -26,6 +27,9 @@

/**
* This adapter enables accepting OffsetDateTime time Json format.
* <p> The adapter supports two DTO formats: the current one and the
* legacy one based on XMLGregorianCalendar model with Java 1.8.
* </p>
*
* @since 10.0.1
*/
Expand Down Expand Up @@ -58,46 +62,101 @@ public JsonElement serialize(
public OffsetDateTime deserialize(
JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) {
try {
// Parse DTO model
DateTimeOffsetDTO dateTimeOffsetDTO = gson.fromJson(jsonElement, DateTimeOffsetDTO.class);

// Prepare OffsetDateTime
OffsetDateTime offsetDateTime;
int nano = 0;
if (dateTimeOffsetDTO.dateTime.time.nano != null) {
nano = dateTimeOffsetDTO.dateTime.time.nano;
}

if (dateTimeOffsetDTO.offset != null) {
ZoneOffset zoneoffset = ZoneOffset.ofTotalSeconds(dateTimeOffsetDTO.offset.totalSeconds);
offsetDateTime = OffsetDateTime.of(
dateTimeOffsetDTO.dateTime.date.year,
dateTimeOffsetDTO.dateTime.date.month,
dateTimeOffsetDTO.dateTime.date.day,
dateTimeOffsetDTO.dateTime.time.hour,
dateTimeOffsetDTO.dateTime.time.minute,
dateTimeOffsetDTO.dateTime.time.second,
nano,
zoneoffset);
} else {
LocalDateTime localDateTime = LocalDateTime.of(
dateTimeOffsetDTO.dateTime.date.year,
dateTimeOffsetDTO.dateTime.date.month,
dateTimeOffsetDTO.dateTime.date.day,
dateTimeOffsetDTO.dateTime.time.hour,
dateTimeOffsetDTO.dateTime.time.minute,
dateTimeOffsetDTO.dateTime.time.second,
nano);

ZoneId zoneId = ZoneOffset.systemDefault();
offsetDateTime = localDateTime.atZone(zoneId).toOffsetDateTime();
}

return offsetDateTime;
} catch (Exception e) {
log.log(Level.FINEST, "Cannot parse JSON into OffsetDateTime: " + e.getMessage(), e);
return null;
// Parse DTO from current OffsetDateTime model
return deserializeFromOffsetDateTimeDTO(gson.fromJson(jsonElement, DateTimeOffsetDTO.class));
} catch (final Exception e) {
log.log(
Level.FINEST,
"Cannot parse JSON into OffsetDateTime from current DTO format: " + e.getMessage(),
e);
}
log.log(Level.FINEST, "Attempting parsing from legacy DTO format");
try {
// Parse DTO from legacy XMLGregorianCalendar model
return deserializeFromXMLGregorianCalendarDTO(gson.fromJson(jsonElement, XMLGregorianCalendarDTO.class));
} catch (final Exception e) {
log.log(Level.FINEST, "Cannot parse JSON into OffsetDateTime from legacy DTO format: " + e.getMessage(), e);
}
return null;
}

private OffsetDateTime deserializeFromOffsetDateTimeDTO(final DateTimeOffsetDTO dateTimeOffsetDTO) {
// Prepare OffsetDateTime
OffsetDateTime offsetDateTime;
int nano = 0;
if (dateTimeOffsetDTO.dateTime.time.nano != null) {
nano = dateTimeOffsetDTO.dateTime.time.nano;
}

if (dateTimeOffsetDTO.offset != null) {
ZoneOffset zoneoffset = ZoneOffset.ofTotalSeconds(dateTimeOffsetDTO.offset.totalSeconds);
offsetDateTime = OffsetDateTime.of(
dateTimeOffsetDTO.dateTime.date.year,
dateTimeOffsetDTO.dateTime.date.month,
dateTimeOffsetDTO.dateTime.date.day,
dateTimeOffsetDTO.dateTime.time.hour,
dateTimeOffsetDTO.dateTime.time.minute,
dateTimeOffsetDTO.dateTime.time.second,
nano,
zoneoffset);
} else {
LocalDateTime localDateTime = LocalDateTime.of(
dateTimeOffsetDTO.dateTime.date.year,
dateTimeOffsetDTO.dateTime.date.month,
dateTimeOffsetDTO.dateTime.date.day,
dateTimeOffsetDTO.dateTime.time.hour,
dateTimeOffsetDTO.dateTime.time.minute,
dateTimeOffsetDTO.dateTime.time.second,
nano);

ZoneId zoneId = ZoneOffset.systemDefault();
offsetDateTime = localDateTime.atZone(zoneId).toOffsetDateTime();
}

return offsetDateTime;
}

private OffsetDateTime deserializeFromXMLGregorianCalendarDTO(
final XMLGregorianCalendarDTO xmlGregorianCalendarDTO) {
if (Integer.MIN_VALUE == xmlGregorianCalendarDTO.year) {
xmlGregorianCalendarDTO.year = 0;
}
if (Integer.MIN_VALUE == xmlGregorianCalendarDTO.month) {
xmlGregorianCalendarDTO.month = 0;
}
if (Integer.MIN_VALUE == xmlGregorianCalendarDTO.day) {
xmlGregorianCalendarDTO.day = 0;
}
if (Integer.MIN_VALUE == xmlGregorianCalendarDTO.hour) {
xmlGregorianCalendarDTO.hour = 0;
}
if (Integer.MIN_VALUE == xmlGregorianCalendarDTO.minute) {
xmlGregorianCalendarDTO.minute = 0;
}
if (Integer.MIN_VALUE == xmlGregorianCalendarDTO.second) {
xmlGregorianCalendarDTO.second = 0;
}
if (Integer.MIN_VALUE == xmlGregorianCalendarDTO.timezone) {
xmlGregorianCalendarDTO.timezone = null;
}

return LocalDateTime.of(
xmlGregorianCalendarDTO.year,
xmlGregorianCalendarDTO.month,
xmlGregorianCalendarDTO.day,
xmlGregorianCalendarDTO.hour,
xmlGregorianCalendarDTO.minute,
xmlGregorianCalendarDTO.second,
xmlGregorianCalendarDTO
.fractionalSecond
.scaleByPowerOfTen(9)
.toBigInteger()
.intValueExact())
.atZone(
xmlGregorianCalendarDTO.timezone != null
? ZoneOffset.ofHours(xmlGregorianCalendarDTO.timezone)
: ZoneOffset.systemDefault())
.toOffsetDateTime();
}

static class DateTimeOffsetDTO {
Expand Down Expand Up @@ -126,4 +185,15 @@ static class TimeDTO {
static class OffsetDTO {
Integer totalSeconds = 0;
}

static class XMLGregorianCalendarDTO {
Integer year;
Integer month;
Integer day;
Integer hour = 0;
Integer minute = 0;
Integer second = 0;
BigDecimal fractionalSecond = BigDecimal.ZERO;
Integer timezone;
}
}
Loading

0 comments on commit cab51fc

Please sign in to comment.