1 /*
2  * Copyright 2013-2020 the original author or authors.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      https://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 package org.springframework.data.convert;
17
18 import static java.time.Instant.*;
19 import static java.time.LocalDateTime.*;
20 import static java.time.ZoneId.*;
21
22 import java.time.Duration;
23 import java.time.Instant;
24 import java.time.LocalDate;
25 import java.time.LocalDateTime;
26 import java.time.LocalTime;
27 import java.time.Period;
28 import java.time.ZoneId;
29 import java.time.format.DateTimeFormatter;
30 import java.util.ArrayList;
31 import java.util.Arrays;
32 import java.util.Collection;
33 import java.util.Collections;
34 import java.util.Date;
35 import java.util.List;
36
37 import javax.annotation.Nonnull;
38
39 import org.springframework.core.convert.converter.Converter;
40 import org.springframework.lang.NonNull;
41 import org.springframework.util.ClassUtils;
42
43 /**
44  * Helper class to register JSR-310 specific {@link Converter} implementations in case the we're running on Java 8.
45  *
46  * @author Oliver Gierke
47  * @author Barak Schoster
48  * @author Christoph Strobl
49  * @author Jens Schauder
50  * @author Mark Paluch
51  */

52 public abstract class Jsr310Converters {
53
54     private static final boolean JAVA_8_IS_PRESENT = ClassUtils.isPresent("java.time.LocalDateTime",
55             Jsr310Converters.class.getClassLoader());
56     private static final List<Class<?>> CLASSES = Arrays.asList(LocalDateTime.class, LocalDate.class, LocalTime.class,
57             Instant.class, ZoneId.class, Duration.class, Period.class);
58
59     /**
60      * Returns the converters to be registered. Will only return converters in case we're running on Java 8.
61      *
62      * @return
63      */

64     public static Collection<Converter<?, ?>> getConvertersToRegister() {
65
66         if (!JAVA_8_IS_PRESENT) {
67             return Collections.emptySet();
68         }
69
70         List<Converter<?, ?>> converters = new ArrayList<>();
71         converters.add(DateToLocalDateTimeConverter.INSTANCE);
72         converters.add(LocalDateTimeToDateConverter.INSTANCE);
73         converters.add(DateToLocalDateConverter.INSTANCE);
74         converters.add(LocalDateToDateConverter.INSTANCE);
75         converters.add(DateToLocalTimeConverter.INSTANCE);
76         converters.add(LocalTimeToDateConverter.INSTANCE);
77         converters.add(DateToInstantConverter.INSTANCE);
78         converters.add(InstantToDateConverter.INSTANCE);
79         converters.add(LocalDateTimeToInstantConverter.INSTANCE);
80         converters.add(InstantToLocalDateTimeConverter.INSTANCE);
81         converters.add(ZoneIdToStringConverter.INSTANCE);
82         converters.add(StringToZoneIdConverter.INSTANCE);
83         converters.add(DurationToStringConverter.INSTANCE);
84         converters.add(StringToDurationConverter.INSTANCE);
85         converters.add(PeriodToStringConverter.INSTANCE);
86         converters.add(StringToPeriodConverter.INSTANCE);
87         converters.add(StringToLocalDateConverter.INSTANCE);
88         converters.add(StringToLocalDateTimeConverter.INSTANCE);
89         converters.add(StringToInstantConverter.INSTANCE);
90
91         return converters;
92     }
93
94     public static boolean supports(Class<?> type) {
95
96         if (!JAVA_8_IS_PRESENT) {
97             return false;
98         }
99
100         return CLASSES.contains(type);
101     }
102
103     @ReadingConverter
104     public static enum DateToLocalDateTimeConverter implements Converter<Date, LocalDateTime> {
105
106         INSTANCE;
107
108         @Nonnull
109         @Override
110         public LocalDateTime convert(Date source) {
111             return ofInstant(source.toInstant(), systemDefault());
112         }
113     }
114
115     @WritingConverter
116     public static enum LocalDateTimeToDateConverter implements Converter<LocalDateTime, Date> {
117
118         INSTANCE;
119
120         @Nonnull
121         @Override
122         public Date convert(LocalDateTime source) {
123             return Date.from(source.atZone(systemDefault()).toInstant());
124         }
125     }
126
127     @ReadingConverter
128     public static enum DateToLocalDateConverter implements Converter<Date, LocalDate> {
129
130         INSTANCE;
131
132         @Nonnull
133         @Override
134         public LocalDate convert(Date source) {
135             return ofInstant(ofEpochMilli(source.getTime()), systemDefault()).toLocalDate();
136         }
137     }
138
139     @WritingConverter
140     public static enum LocalDateToDateConverter implements Converter<LocalDate, Date> {
141
142         INSTANCE;
143
144         @Nonnull
145         @Override
146         public Date convert(LocalDate source) {
147             return Date.from(source.atStartOfDay(systemDefault()).toInstant());
148         }
149     }
150
151     @ReadingConverter
152     public static enum DateToLocalTimeConverter implements Converter<Date, LocalTime> {
153
154         INSTANCE;
155
156         @Nonnull
157         @Override
158         public LocalTime convert(Date source) {
159             return ofInstant(ofEpochMilli(source.getTime()), systemDefault()).toLocalTime();
160         }
161     }
162
163     @WritingConverter
164     public static enum LocalTimeToDateConverter implements Converter<LocalTime, Date> {
165
166         INSTANCE;
167
168         @Nonnull
169         @Override
170         public Date convert(LocalTime source) {
171             return Date.from(source.atDate(LocalDate.now()).atZone(systemDefault()).toInstant());
172         }
173     }
174
175     @ReadingConverter
176     public static enum DateToInstantConverter implements Converter<Date, Instant> {
177
178         INSTANCE;
179
180         @Nonnull
181         @Override
182         public Instant convert(Date source) {
183             return source.toInstant();
184         }
185     }
186
187     @WritingConverter
188     public static enum InstantToDateConverter implements Converter<Instant, Date> {
189
190         INSTANCE;
191
192         @Nonnull
193         @Override
194         public Date convert(Instant source) {
195             return Date.from(source);
196         }
197     }
198
199     @ReadingConverter
200     public static enum LocalDateTimeToInstantConverter implements Converter<LocalDateTime, Instant> {
201
202         INSTANCE;
203
204         @Nonnull
205         @Override
206         public Instant convert(LocalDateTime source) {
207             return source.atZone(systemDefault()).toInstant();
208         }
209     }
210
211     @ReadingConverter
212     public static enum InstantToLocalDateTimeConverter implements Converter<Instant, LocalDateTime> {
213
214         INSTANCE;
215
216         @Nonnull
217         @Override
218         public LocalDateTime convert(Instant source) {
219             return LocalDateTime.ofInstant(source, systemDefault());
220         }
221     }
222
223     @WritingConverter
224     public static enum ZoneIdToStringConverter implements Converter<ZoneId, String> {
225
226         INSTANCE;
227
228         @Nonnull
229         @Override
230         public String convert(ZoneId source) {
231             return source.toString();
232         }
233     }
234
235     @ReadingConverter
236     public static enum StringToZoneIdConverter implements Converter<String, ZoneId> {
237
238         INSTANCE;
239
240         @Nonnull
241         @Override
242         public ZoneId convert(String source) {
243             return ZoneId.of(source);
244         }
245     }
246
247     @WritingConverter
248     public static enum DurationToStringConverter implements Converter<Duration, String> {
249
250         INSTANCE;
251
252         @Nonnull
253         @Override
254         public String convert(Duration duration) {
255             return duration.toString();
256         }
257     }
258
259     @ReadingConverter
260     public static enum StringToDurationConverter implements Converter<String, Duration> {
261
262         INSTANCE;
263
264         @Nonnull
265         @Override
266         public Duration convert(String s) {
267             return Duration.parse(s);
268         }
269     }
270
271     @WritingConverter
272     public static enum PeriodToStringConverter implements Converter<Period, String> {
273
274         INSTANCE;
275
276         @Nonnull
277         @Override
278         public String convert(Period period) {
279             return period.toString();
280         }
281     }
282
283     @ReadingConverter
284     public static enum StringToPeriodConverter implements Converter<String, Period> {
285
286         INSTANCE;
287
288         @Nonnull
289         @Override
290         public Period convert(String s) {
291             return Period.parse(s);
292         }
293     }
294
295     @ReadingConverter
296     public static enum StringToLocalDateConverter implements Converter<String, LocalDate> {
297
298         INSTANCE;
299
300         /*
301          * (non-Javadoc)
302          * @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
303          */

304         @NonNull
305         @Override
306         public LocalDate convert(String source) {
307             return LocalDate.parse(source, DateTimeFormatter.ISO_DATE);
308         }
309     }
310
311     @ReadingConverter
312     public static enum StringToLocalDateTimeConverter implements Converter<String, LocalDateTime> {
313
314         INSTANCE;
315
316         /*
317          * (non-Javadoc)
318          * @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
319          */

320         @NonNull
321         @Override
322         public LocalDateTime convert(String source) {
323             return LocalDateTime.parse(source, DateTimeFormatter.ISO_DATE_TIME);
324         }
325     }
326
327     @ReadingConverter
328     public static enum StringToInstantConverter implements Converter<String, Instant> {
329
330         INSTANCE;
331
332         /*
333          * (non-Javadoc)
334          * @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
335          */

336         @NonNull
337         @Override
338         public Instant convert(String source) {
339             return Instant.parse(source);
340         }
341     }
342 }
343