1
15
16 package software.amazon.awssdk.protocols.core;
17
18 import java.time.Instant;
19 import java.util.Map;
20 import java.util.function.Function;
21 import software.amazon.awssdk.annotations.SdkProtectedApi;
22 import software.amazon.awssdk.core.SdkField;
23 import software.amazon.awssdk.core.exception.SdkClientException;
24 import software.amazon.awssdk.core.protocol.MarshallLocation;
25 import software.amazon.awssdk.core.traits.TimestampFormatTrait;
26 import software.amazon.awssdk.utils.DateUtils;
27
28
32 @SdkProtectedApi
33 public final class StringToInstant implements StringToValueConverter.StringToValue<Instant> {
34
35
38 private final Map<MarshallLocation, TimestampFormatTrait.Format> defaultFormats;
39
40 private StringToInstant(Map<MarshallLocation, TimestampFormatTrait.Format> defaultFormats) {
41 this.defaultFormats = defaultFormats;
42 }
43
44 @Override
45 public Instant convert(String value, SdkField<Instant> field) {
46 if (value == null) {
47 return null;
48 }
49 TimestampFormatTrait.Format format = resolveTimestampFormat(field);
50 switch (format) {
51 case ISO_8601:
52 return DateUtils.parseIso8601Date(value);
53 case UNIX_TIMESTAMP:
54 return safeParseDate(DateUtils::parseUnixTimestampInstant).apply(value);
55 case UNIX_TIMESTAMP_MILLIS:
56 return safeParseDate(DateUtils::parseUnixTimestampMillisInstant).apply(value);
57 case RFC_822:
58 return DateUtils.parseRfc1123Date(value);
59 default:
60 throw SdkClientException.create("Unrecognized timestamp format - " + format);
61 }
62 }
63
64
69 private Function<String, Instant> safeParseDate(Function<String, Instant> dateUnmarshaller) {
70 return value -> {
71 try {
72 return dateUnmarshaller.apply(value);
73 } catch (NumberFormatException e) {
74 throw SdkClientException.builder()
75 .message("Unable to parse date : " + value)
76 .cause(e)
77 .build();
78 }
79 };
80 }
81
82 private TimestampFormatTrait.Format resolveTimestampFormat(SdkField<Instant> field) {
83 TimestampFormatTrait trait = field.getTrait(TimestampFormatTrait.class);
84 if (trait == null) {
85 TimestampFormatTrait.Format format = defaultFormats.get(field.location());
86 if (format == null) {
87 throw SdkClientException.create(
88 String.format("Timestamps are not supported for this location (%s)", field.location()));
89 }
90 return format;
91 } else {
92 return trait.format();
93 }
94 }
95
96
100 public static StringToInstant create(Map<MarshallLocation, TimestampFormatTrait.Format> defaultFormats) {
101 return new StringToInstant(defaultFormats);
102 }
103 }
104