From 2279cea9ba7b247d01e528d919a6b834a85565cd Mon Sep 17 00:00:00 2001 From: yue9944882 <291271447@qq.com> Date: Wed, 6 Jan 2021 17:37:14 +0800 Subject: [PATCH 1/3] support rfc3339 micro 6 digit timestamp --- .../leaderelection/LeaderElectorTest.java | 17 ----------- .../resourcelock/LeaseLock.java | 28 ++++++++++++------- .../io/kubernetes/client/openapi/JSON.java | 15 +++++++++- .../kubernetes/client/openapi/JSONTest.java | 26 +++++++++++++++++ 4 files changed, 58 insertions(+), 28 deletions(-) diff --git a/e2e/src/test/java/io/kubernetes/client/e2e/extended/leaderelection/LeaderElectorTest.java b/e2e/src/test/java/io/kubernetes/client/e2e/extended/leaderelection/LeaderElectorTest.java index 142ed75755..b73dbfcc61 100644 --- a/e2e/src/test/java/io/kubernetes/client/e2e/extended/leaderelection/LeaderElectorTest.java +++ b/e2e/src/test/java/io/kubernetes/client/e2e/extended/leaderelection/LeaderElectorTest.java @@ -26,8 +26,6 @@ import java.io.IOException; import java.net.HttpURLConnection; import java.time.Duration; -import java.time.format.DateTimeFormatter; -import java.time.format.DateTimeFormatterBuilder; import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -78,21 +76,6 @@ public LeaderElectorTest(LockType lockType) { } catch (IOException ex) { throw new RuntimeException("Couldn't create ApiClient", ex); } - // Lease resource requires special care with DateTime - if (lockType == LockType.Lease) { - // TODO: switch date-time library so that micro-sec timestamp can be serialized - // in RFC3339 - // format w/ correct precision without the hacks - - // This formatter is used for Lease resource spec's acquire/renewTime - DateTimeFormatter formatter = - new DateTimeFormatterBuilder() - .appendOptional(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSSSS'Z'")) - .appendOptional(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss'Z'")) - .toFormatter(); - - apiClient.setOffsetDateTimeFormat(formatter); - } this.lockType = lockType; } diff --git a/extended/src/main/java/io/kubernetes/client/extended/leaderelection/resourcelock/LeaseLock.java b/extended/src/main/java/io/kubernetes/client/extended/leaderelection/resourcelock/LeaseLock.java index 0caa3261cc..90954beb72 100644 --- a/extended/src/main/java/io/kubernetes/client/extended/leaderelection/resourcelock/LeaseLock.java +++ b/extended/src/main/java/io/kubernetes/client/extended/leaderelection/resourcelock/LeaseLock.java @@ -135,15 +135,23 @@ private LeaderElectionRecord getRecordFromLease(V1LeaseSpec lease) { } private V1LeaseSpec getLeaseFromRecord(LeaderElectionRecord record) { - return new V1LeaseSpec() - .acquireTime( - OffsetDateTime.ofInstant( - Instant.ofEpochMilli(record.getAcquireTime().getTime()), ZoneOffset.UTC)) - .renewTime( - OffsetDateTime.ofInstant( - Instant.ofEpochMilli(record.getRenewTime().getTime()), ZoneOffset.UTC)) - .holderIdentity(record.getHolderIdentity()) - .leaseDurationSeconds(record.getLeaseDurationSeconds()) - .leaseTransitions(record.getLeaderTransitions()); + V1LeaseSpec spec = + new V1LeaseSpec() + .holderIdentity(record.getHolderIdentity()) + .leaseDurationSeconds(record.getLeaseDurationSeconds()) + .leaseTransitions(record.getLeaderTransitions()); + if (record.getAcquireTime() != null) { + spec = + spec.acquireTime( + OffsetDateTime.ofInstant( + Instant.ofEpochMilli(record.getAcquireTime().getTime()), ZoneOffset.UTC)); + } + if (record.getRenewTime() != null) { + spec = + spec.renewTime( + OffsetDateTime.ofInstant( + Instant.ofEpochMilli(record.getRenewTime().getTime()), ZoneOffset.UTC)); + } + return spec; } } diff --git a/kubernetes/src/main/java/io/kubernetes/client/openapi/JSON.java b/kubernetes/src/main/java/io/kubernetes/client/openapi/JSON.java index 0176e0a432..3ee3afd11f 100644 --- a/kubernetes/src/main/java/io/kubernetes/client/openapi/JSON.java +++ b/kubernetes/src/main/java/io/kubernetes/client/openapi/JSON.java @@ -32,6 +32,8 @@ import java.time.LocalDate; import java.time.OffsetDateTime; import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeFormatterBuilder; +import java.time.temporal.ChronoField; import java.util.Date; import java.util.Map; import okio.ByteString; @@ -42,11 +44,22 @@ public class JSON { private boolean isLenientOnJson = false; + public static final DateTimeFormatter RFC3339MICRO_FORMATTER = + new DateTimeFormatterBuilder() + .parseDefaulting(ChronoField.OFFSET_SECONDS, 0) + .append(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss")) + .optionalStart() + .appendFraction(ChronoField.NANO_OF_SECOND, 6, 6, true) + .optionalEnd() + .appendLiteral("Z") + .toFormatter(); + private DateTypeAdapter dateTypeAdapter = new DateTypeAdapter(); private SqlDateTypeAdapter sqlDateTypeAdapter = new SqlDateTypeAdapter(); - private OffsetDateTimeTypeAdapter offsetDateTimeTypeAdapter = new OffsetDateTimeTypeAdapter(); + private OffsetDateTimeTypeAdapter offsetDateTimeTypeAdapter = + new OffsetDateTimeTypeAdapter(RFC3339MICRO_FORMATTER); private LocalDateTypeAdapter localDateTypeAdapter = new LocalDateTypeAdapter(); diff --git a/kubernetes/src/test/java/io/kubernetes/client/openapi/JSONTest.java b/kubernetes/src/test/java/io/kubernetes/client/openapi/JSONTest.java index 52041ce9d7..8834fb0fab 100644 --- a/kubernetes/src/test/java/io/kubernetes/client/openapi/JSONTest.java +++ b/kubernetes/src/test/java/io/kubernetes/client/openapi/JSONTest.java @@ -15,6 +15,7 @@ import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.*; +import java.time.OffsetDateTime; import okio.ByteString; import org.junit.Test; @@ -36,4 +37,29 @@ public void testSerializeByteArray() { final String decodedText = new String(byteStr.toByteArray()); assertThat(decodedText, is(plainText)); } + + @Test + public void testOffsetDateTime1e6Parse() { + System.out.println(JSON.RFC3339MICRO_FORMATTER.format(OffsetDateTime.now())); + String timeStr = "2018-04-03T11:32:26.123456Z"; + OffsetDateTime t = OffsetDateTime.parse(timeStr, JSON.RFC3339MICRO_FORMATTER); + String serializedTsStr = JSON.RFC3339MICRO_FORMATTER.format(t); + assertEquals(timeStr, serializedTsStr); + } + + @Test + public void testOffsetDateTime1e4Parse() { + String timeStr = "2018-04-03T11:32:26.123400Z"; + OffsetDateTime t = OffsetDateTime.parse(timeStr, JSON.RFC3339MICRO_FORMATTER); + String serializedTsStr = JSON.RFC3339MICRO_FORMATTER.format(t); + assertEquals(timeStr, serializedTsStr); + } + + @Test + public void testOffsetDateTimeNoFractionParse() { + String timeStr = "2018-04-03T11:32:26Z"; + OffsetDateTime t = OffsetDateTime.parse(timeStr, JSON.RFC3339MICRO_FORMATTER); + String serializedTsStr = JSON.RFC3339MICRO_FORMATTER.format(t); + assertEquals("2018-04-03T11:32:26.000000Z", serializedTsStr); + } } From 36ec40501383bae1e0187b0f2e4de5ab06fb23c3 Mon Sep 17 00:00:00 2001 From: yue9944882 <291271447@qq.com> Date: Wed, 6 Jan 2021 23:26:56 +0800 Subject: [PATCH 2/3] backward-compatibiity for ISO8601 timestamps from older version client --- .../io/kubernetes/client/openapi/JSON.java | 8 +++++- .../kubernetes/client/openapi/JSONTest.java | 28 +++++++++++++------ 2 files changed, 26 insertions(+), 10 deletions(-) diff --git a/kubernetes/src/main/java/io/kubernetes/client/openapi/JSON.java b/kubernetes/src/main/java/io/kubernetes/client/openapi/JSON.java index 3ee3afd11f..6c2c219545 100644 --- a/kubernetes/src/main/java/io/kubernetes/client/openapi/JSON.java +++ b/kubernetes/src/main/java/io/kubernetes/client/openapi/JSON.java @@ -33,6 +33,7 @@ import java.time.OffsetDateTime; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatterBuilder; +import java.time.format.DateTimeParseException; import java.time.temporal.ChronoField; import java.util.Date; import java.util.Map; @@ -244,7 +245,12 @@ public OffsetDateTime read(JsonReader in) throws IOException { if (date.endsWith("+0000")) { date = date.substring(0, date.length() - 5) + "Z"; } - return OffsetDateTime.parse(date, formatter); + try { + return OffsetDateTime.parse(date, formatter); + } catch (DateTimeParseException e) { + // backward-compatibility for ISO8601 timestamp format + return OffsetDateTime.parse(date, DateTimeFormatter.ISO_OFFSET_DATE_TIME); + } } } } diff --git a/kubernetes/src/test/java/io/kubernetes/client/openapi/JSONTest.java b/kubernetes/src/test/java/io/kubernetes/client/openapi/JSONTest.java index 8834fb0fab..f32c6a1169 100644 --- a/kubernetes/src/test/java/io/kubernetes/client/openapi/JSONTest.java +++ b/kubernetes/src/test/java/io/kubernetes/client/openapi/JSONTest.java @@ -21,9 +21,10 @@ public class JSONTest { + private final JSON json = new JSON(); + @Test public void testSerializeByteArray() { - final JSON json = new JSON(); final String plainText = "string that contains '=' when encoded"; final String base64String = json.serialize(plainText.getBytes()); // serialize returns string surrounded by quotes: "\"[base64]\"" @@ -40,19 +41,28 @@ public void testSerializeByteArray() { @Test public void testOffsetDateTime1e6Parse() { - System.out.println(JSON.RFC3339MICRO_FORMATTER.format(OffsetDateTime.now())); - String timeStr = "2018-04-03T11:32:26.123456Z"; - OffsetDateTime t = OffsetDateTime.parse(timeStr, JSON.RFC3339MICRO_FORMATTER); - String serializedTsStr = JSON.RFC3339MICRO_FORMATTER.format(t); + String timeStr = "\"2018-04-03T11:32:26.123456Z\""; + OffsetDateTime dateTime = json.deserialize(timeStr, OffsetDateTime.class); + String serializedTsStr = json.serialize(dateTime); assertEquals(timeStr, serializedTsStr); } @Test public void testOffsetDateTime1e4Parse() { - String timeStr = "2018-04-03T11:32:26.123400Z"; - OffsetDateTime t = OffsetDateTime.parse(timeStr, JSON.RFC3339MICRO_FORMATTER); - String serializedTsStr = JSON.RFC3339MICRO_FORMATTER.format(t); - assertEquals(timeStr, serializedTsStr); + String timeStr = "\"2018-04-03T11:32:26.1234Z\""; + OffsetDateTime dateTime = json.deserialize(timeStr, OffsetDateTime.class); + String serializedTsStr = json.serialize(dateTime); + String expectedStr = "\"2018-04-03T11:32:26.123400Z\""; + assertEquals(expectedStr, serializedTsStr); + } + + @Test + public void testOffsetDateTime1e3Parse() { + String timeStr = "\"2018-04-03T11:32:26.123Z\""; + OffsetDateTime dateTime = json.deserialize(timeStr, OffsetDateTime.class); + String serializedTsStr = json.serialize(dateTime); + String expectedStr = "\"2018-04-03T11:32:26.123000Z\""; + assertEquals(expectedStr, serializedTsStr); } @Test From 61cf85c573ab6dff553851df76232d51f6acdf71 Mon Sep 17 00:00:00 2001 From: yue9944882 <291271447@qq.com> Date: Thu, 7 Jan 2021 19:39:08 +0800 Subject: [PATCH 3/3] privatize datetimeformatter --- .../src/main/java/io/kubernetes/client/openapi/JSON.java | 2 +- .../test/java/io/kubernetes/client/openapi/JSONTest.java | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/kubernetes/src/main/java/io/kubernetes/client/openapi/JSON.java b/kubernetes/src/main/java/io/kubernetes/client/openapi/JSON.java index 6c2c219545..717f70a79d 100644 --- a/kubernetes/src/main/java/io/kubernetes/client/openapi/JSON.java +++ b/kubernetes/src/main/java/io/kubernetes/client/openapi/JSON.java @@ -45,7 +45,7 @@ public class JSON { private boolean isLenientOnJson = false; - public static final DateTimeFormatter RFC3339MICRO_FORMATTER = + private static final DateTimeFormatter RFC3339MICRO_FORMATTER = new DateTimeFormatterBuilder() .parseDefaulting(ChronoField.OFFSET_SECONDS, 0) .append(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss")) diff --git a/kubernetes/src/test/java/io/kubernetes/client/openapi/JSONTest.java b/kubernetes/src/test/java/io/kubernetes/client/openapi/JSONTest.java index f32c6a1169..1609a8a067 100644 --- a/kubernetes/src/test/java/io/kubernetes/client/openapi/JSONTest.java +++ b/kubernetes/src/test/java/io/kubernetes/client/openapi/JSONTest.java @@ -67,9 +67,10 @@ public void testOffsetDateTime1e3Parse() { @Test public void testOffsetDateTimeNoFractionParse() { - String timeStr = "2018-04-03T11:32:26Z"; - OffsetDateTime t = OffsetDateTime.parse(timeStr, JSON.RFC3339MICRO_FORMATTER); - String serializedTsStr = JSON.RFC3339MICRO_FORMATTER.format(t); - assertEquals("2018-04-03T11:32:26.000000Z", serializedTsStr); + String timeStr = "\"2018-04-03T11:32:26Z\""; + OffsetDateTime dateTime = json.deserialize(timeStr, OffsetDateTime.class); + String serializedTsStr = json.serialize(dateTime); + String expectedStr = "\"2018-04-03T11:32:26.000000Z\""; + assertEquals(expectedStr, serializedTsStr); } }