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

Java 8 date and time support #685

Merged
merged 5 commits into from
Jul 31, 2018
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* Copyright 2005-2018 Dozer Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.github.dozermapper.core.converters;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAccessor;

import org.apache.commons.beanutils.Converter;

/**
* Base converter to Java 8 date and time types.
* <pre>
* Supported basic conversions:
* Any child of TemporalAccessor &#45;&gt; LocalDateTime
* String &#45;&gt; LocalDateTime
* </pre>
*/
public abstract class AbstractJava8DateTimeConverter implements Converter {

private final DateTimeFormatter formatter;

AbstractJava8DateTimeConverter(DateTimeFormatter formatter) {
this.formatter = formatter;
}

@Override
@SuppressWarnings("unchecked")
public Object convert(Class destClass, Object srcObject) {
Class<?> srcObjectClass = srcObject.getClass();
try {
if (TemporalAccessor.class.isAssignableFrom(srcObjectClass)) {
Method method = destClass.getDeclaredMethod("from", TemporalAccessor.class);
return method.invoke(null, (TemporalAccessor)srcObject);
} else if (String.class.isAssignableFrom(srcObjectClass) && formatter != null) {
Method method = destClass.getDeclaredMethod("parse", CharSequence.class, DateTimeFormatter.class);
return method.invoke(null, srcObject, formatter);
} else {
throw new ConversionException(String.format("Unsupported source object type: %s", srcObjectClass), null);
}
} catch (NoSuchMethodException | IllegalAccessException e) {
throw new ConversionException(
String.format("Failed to create %s from %s", destClass.getSimpleName(), srcObject.getClass().getSimpleName()), e);
} catch (InvocationTargetException e) {
throw new ConversionException(
String.format("Failed to create %s from %s", destClass.getSimpleName(), srcObject.getClass().getSimpleName()), e.getTargetException());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,18 @@

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.time.format.DateTimeFormatter;
import java.util.Locale;

/**
* Internal class used as a container to determine the date format to use for a particular field mapping. Only intended
* for internal use.
*/
public class DateFormatContainer {

private String dfStr;
private DateFormat dateFormat;
private DateTimeFormatter dateTimeFormatter;

public DateFormatContainer(String dfStr) {
this.dfStr = dfStr;
Expand All @@ -38,6 +41,28 @@ public DateFormat getDateFormat() {
return dateFormat;
}

/**
* Date and time formatter for Java 8 Date &amp; Time objects.
*
* @return formatter
*/
public DateTimeFormatter getDateTimeFormatter() {
if (dateTimeFormatter == null) {
if (dfStr != null) {
dateTimeFormatter = DateTimeFormatter.ofPattern(dfStr);
}
}
return dateTimeFormatter;
}

/**
* TODO replace method call with reflection in tests.
*
* @param dateFormat dateFormat
* @deprecated This method will break internal state of the instance by setting formatter which is not using
* format provided using constructor. It will be removed in future releases.
*/
@Deprecated
public void setDateFormat(DateFormat dateFormat) {
this.dateFormat = dateFormat;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*
* Copyright 2005-2018 Dozer Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.github.dozermapper.core.converters;

import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Date;

/**
* Internal converter to {@link LocalDateTime} type. Only intended for internal use.
* <pre>
* Supported conversions:
* Any child of TemporalAccessor &#45;&gt; LocalDateTime ()
* String &#45;&gt; LocalDateTime
* Long &#45;&gt; LocalDateTime
* Date &#45;&gt; LocalDateTime
* </pre>
*/
public final class LocalDateTimeConverter extends AbstractJava8DateTimeConverter {

public LocalDateTimeConverter(DateTimeFormatter formatter) {
super(formatter);
}

@Override
public Object convert(Class destClass, Object srcObject) {
LocalDateTime localDateTime = convertToLocalDateTime(srcObject);
if (localDateTime != null) {
if (LocalTime.class.isAssignableFrom(destClass)) {
return localDateTime.toLocalTime();
} else if (LocalDate.class.isAssignableFrom(destClass)) {
return localDateTime.toLocalDate();
}
return localDateTime;
}
return super.convert(destClass, srcObject);
}

private LocalDateTime convertToLocalDateTime(Object srcObject) {
Class<?> srcObjectClass = srcObject.getClass();

if (Date.class.isAssignableFrom(srcObjectClass)) {
Instant instant = ((Date)srcObject).toInstant();
return LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
} else if (Instant.class.isAssignableFrom(srcObjectClass)) {
return LocalDateTime.ofInstant((Instant)srcObject, ZoneId.systemDefault());
} else if (Long.class.isAssignableFrom(srcObjectClass)) {
Instant instant = Instant.ofEpochMilli((Long)srcObject);
return LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
} else {
return null;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* Copyright 2005-2018 Dozer Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.github.dozermapper.core.converters;

import java.time.Instant;
import java.time.OffsetDateTime;
import java.time.OffsetTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Date;

/**
* Internal class for converting supported types to {@link java.time.OffsetDateTime}.
* Only intended for internal use.
*/
public class OffsetDateTimeConverter
extends AbstractJava8DateTimeConverter {

public OffsetDateTimeConverter(DateTimeFormatter formatter) {
super(formatter);
}

@Override
public Object convert(Class destClass, Object srcObject) {
OffsetDateTime offsetDateTime = convertToOffsetDateTime(srcObject);
if (offsetDateTime != null) {
if (OffsetTime.class.isAssignableFrom(destClass)) {
return offsetDateTime.toOffsetTime();
}
return offsetDateTime;
}
return super.convert(destClass, srcObject);
}

private OffsetDateTime convertToOffsetDateTime(Object srcObject) {
Class<?> srcObjectClass = srcObject.getClass();
if (Date.class.isAssignableFrom(srcObjectClass)) {
Instant instant = ((Date)srcObject).toInstant();
return OffsetDateTime.ofInstant(instant, ZoneId.systemDefault());
} else if (Instant.class.isAssignableFrom(srcObjectClass)) {
return OffsetDateTime.ofInstant((Instant)srcObject, ZoneId.systemDefault());
} else if (Long.class.isAssignableFrom(srcObjectClass)) {
Instant instant = Instant.ofEpochMilli((Long)srcObject);
return OffsetDateTime.ofInstant(instant, ZoneId.systemDefault());
} else {
return null;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@

import java.math.BigDecimal;
import java.math.BigInteger;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.OffsetDateTime;
import java.time.OffsetTime;
import java.time.ZonedDateTime;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;
Expand Down Expand Up @@ -105,6 +111,12 @@ private Converter getPrimitiveOrWrapperConverter(Class destClass, DateFormatCont
result = new EnumConverter();
} else if (JAXBElement.class.isAssignableFrom(destClass) && destFieldName != null) {
result = new JAXBElementConverter(destObj.getClass().getCanonicalName(), destFieldName, dateFormatContainer.getDateFormat(), beanContainer);
} else if (isLocalTime(destClass)) {
result = new LocalDateTimeConverter(dateFormatContainer.getDateTimeFormatter());
} else if (isOffsetTime(destClass)) {
result = new OffsetDateTimeConverter(dateFormatContainer.getDateTimeFormatter());
} else if (ZonedDateTime.class.isAssignableFrom(destClass)) {
result = new ZonedDateTimeConverter(dateFormatContainer.getDateTimeFormatter());
}
}
return result == null ? new StringConstructorConverter(dateFormatContainer) : result;
Expand All @@ -118,7 +130,23 @@ public boolean accepts(Class<?> aClass) {
|| Boolean.class.equals(aClass)
|| java.util.Date.class.isAssignableFrom(aClass)
|| java.util.Calendar.class.isAssignableFrom(aClass)
|| aClass.isEnum();
|| aClass.isEnum()
|| LocalDateTime.class.isAssignableFrom(aClass)
|| LocalDate.class.isAssignableFrom(aClass)
|| LocalTime.class.isAssignableFrom(aClass)
|| OffsetDateTime.class.isAssignableFrom(aClass)
|| OffsetTime.class.isAssignableFrom(aClass)
|| ZonedDateTime.class.isAssignableFrom(aClass);
}

private static boolean isLocalTime(Class clazz) {
return LocalDateTime.class.isAssignableFrom(clazz) ||
LocalDate.class.isAssignableFrom(clazz) ||
LocalTime.class.isAssignableFrom(clazz);
}

private static boolean isOffsetTime(Class clazz) {
return OffsetDateTime.class.isAssignableFrom(clazz) ||
OffsetTime.class.isAssignableFrom(clazz);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,40 +15,48 @@
*/
package com.github.dozermapper.core.converters;

import java.time.temporal.TemporalAccessor;
import java.util.Calendar;
import java.util.Date;

import org.apache.commons.beanutils.Converter;

/**
* Internal class for converting Supported Data Types to String. Uses date formatter for Date and Calendar source
* objects. Calls toString() on the source object for all other types. Only intended for internal use.
*/
public class StringConverter implements Converter {

private DateFormatContainer dateFormatContainer;

public StringConverter(DateFormatContainer dateFormatContainer) {
this.dateFormatContainer = dateFormatContainer;
}

public Object convert(Class destClass, Object srcObj) {
String result;
Class srcClass = srcObj.getClass();
if (dateFormatContainer != null && java.util.Date.class.isAssignableFrom(srcClass)
&& dateFormatContainer.getDateFormat() != null) {
result = dateFormatContainer.getDateFormat().format((java.util.Date)srcObj);
} else if (dateFormatContainer != null && java.util.Calendar.class.isAssignableFrom(srcClass)
&& dateFormatContainer.getDateFormat() != null) {
result = dateFormatContainer.getDateFormat().format(((java.util.Calendar)srcObj).getTime());
if (hasDateFormat()) {
if (Date.class.isAssignableFrom(srcClass)) {
return dateFormatContainer.getDateFormat().format((Date)srcObj);
}
if (Calendar.class.isAssignableFrom(srcClass)) {
return dateFormatContainer.getDateFormat().format(((Calendar)srcObj).getTime());
} else if (TemporalAccessor.class.isAssignableFrom(srcClass)) {
return dateFormatContainer.getDateTimeFormatter().format((TemporalAccessor)srcObj);
} else {
return srcObj.toString();
}
} else {
result = srcObj.toString();
return srcObj.toString();
}

return result;
}

public DateFormatContainer getDateFormatContainer() {
return dateFormatContainer;
}

public void setDateFormatContainer(DateFormatContainer dateFormat) {
this.dateFormatContainer = dateFormat;
/**
* Whether date format is provided or not
*
* @return true - date format provided. Otherwise false.
*/
private boolean hasDateFormat() {
return dateFormatContainer != null && dateFormatContainer.getDateFormat() != null;
}
}
Loading