Skip to content

Commit 2b33104

Browse files
committed
adding back JSON related manual hacks
Signed-off-by: Min Jin <[email protected]>
1 parent 5eccf41 commit 2b33104

File tree

3 files changed

+75
-54
lines changed

3 files changed

+75
-54
lines changed

kubernetes/.openapi-generator-ignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,5 @@ git_push.sh
66
README.md
77
pom.xml
88

9+
# Remove when changes in kubernetes-client/java#366,#240 make into upstream openapi-generator
10+
src/main/java/io/kubernetes/client/openapi/JSON.java

kubernetes/src/main/java/io/kubernetes/client/openapi/JSON.java

Lines changed: 73 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
Copyright 2023 The Kubernetes Authors.
2+
Copyright 2021 The Kubernetes Authors.
33
Licensed under the Apache License, Version 2.0 (the "License");
44
you may not use this file except in compliance with the License.
55
You may obtain a copy of the License at
@@ -14,79 +14,102 @@
1414

1515
import com.google.gson.Gson;
1616
import com.google.gson.GsonBuilder;
17+
import com.google.gson.JsonElement;
1718
import com.google.gson.JsonParseException;
1819
import com.google.gson.TypeAdapter;
19-
import com.google.gson.internal.bind.util.ISO8601Utils;
2020
import com.google.gson.stream.JsonReader;
2121
import com.google.gson.stream.JsonWriter;
22-
import com.google.gson.JsonElement;
2322
import io.gsonfire.GsonFireBuilder;
24-
import io.gsonfire.TypeSelector;
25-
26-
import io.kubernetes.client.openapi.models.*;
27-
import okio.ByteString;
28-
23+
import io.kubernetes.client.gson.V1StatusPreProcessor;
24+
import io.kubernetes.client.openapi.models.V1Status;
2925
import java.io.IOException;
3026
import java.io.StringReader;
3127
import java.lang.reflect.Type;
3228
import java.text.DateFormat;
3329
import java.text.ParseException;
34-
import java.text.ParsePosition;
30+
import java.time.Instant;
3531
import java.time.LocalDate;
3632
import java.time.OffsetDateTime;
3733
import java.time.format.DateTimeFormatter;
34+
import java.time.format.DateTimeFormatterBuilder;
35+
import java.time.format.DateTimeParseException;
36+
import java.time.temporal.ChronoField;
3837
import java.util.Date;
39-
import java.util.Locale;
4038
import java.util.Map;
41-
import java.util.HashMap;
39+
import okio.ByteString;
4240

4341
public class JSON {
42+
4443
private Gson gson;
44+
4545
private boolean isLenientOnJson = false;
46+
47+
private static final DateTimeFormatter RFC3339MICRO_FORMATTER =
48+
new DateTimeFormatterBuilder()
49+
.parseDefaulting(ChronoField.OFFSET_SECONDS, 0)
50+
.append(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss"))
51+
.optionalStart()
52+
.appendFraction(ChronoField.NANO_OF_SECOND, 6, 6, true)
53+
.optionalEnd()
54+
.appendOffsetId()
55+
.toFormatter();
56+
4657
private DateTypeAdapter dateTypeAdapter = new DateTypeAdapter();
58+
4759
private SqlDateTypeAdapter sqlDateTypeAdapter = new SqlDateTypeAdapter();
48-
private OffsetDateTimeTypeAdapter offsetDateTimeTypeAdapter = new OffsetDateTimeTypeAdapter();
60+
61+
private OffsetDateTimeTypeAdapter offsetDateTimeTypeAdapter =
62+
new OffsetDateTimeTypeAdapter(RFC3339MICRO_FORMATTER);
63+
4964
private LocalDateTypeAdapter localDateTypeAdapter = new LocalDateTypeAdapter();
65+
5066
private ByteArrayAdapter byteArrayAdapter = new ByteArrayAdapter();
5167

5268
public static GsonBuilder createGson() {
53-
GsonFireBuilder fireBuilder = new GsonFireBuilder()
54-
;
55-
GsonBuilder builder = fireBuilder.createGsonBuilder();
69+
GsonFireBuilder fireBuilder = new GsonFireBuilder();
70+
GsonBuilder builder =
71+
fireBuilder
72+
.registerPreProcessor(V1Status.class, new V1StatusPreProcessor())
73+
.createGsonBuilder();
5674
return builder;
5775
}
5876

5977
private static String getDiscriminatorValue(JsonElement readElement, String discriminatorField) {
6078
JsonElement element = readElement.getAsJsonObject().get(discriminatorField);
6179
if (null == element) {
62-
throw new IllegalArgumentException("missing discriminator field: <" + discriminatorField + ">");
80+
throw new IllegalArgumentException(
81+
"missing discriminator field: <" + discriminatorField + ">");
6382
}
6483
return element.getAsString();
6584
}
6685

6786
/**
68-
* Returns the Java class that implements the OpenAPI schema for the specified discriminator value.
87+
* Returns the Java class that implements the OpenAPI schema for the specified discriminator
88+
* value.
6989
*
7090
* @param classByDiscriminatorValue The map of discriminator values to Java classes.
7191
* @param discriminatorValue The value of the OpenAPI discriminator in the input data.
7292
* @return The Java class that implements the OpenAPI schema
7393
*/
74-
private static Class getClassByDiscriminator(Map classByDiscriminatorValue, String discriminatorValue) {
94+
private static Class getClassByDiscriminator(
95+
Map classByDiscriminatorValue, String discriminatorValue) {
7596
Class clazz = (Class) classByDiscriminatorValue.get(discriminatorValue);
7697
if (null == clazz) {
77-
throw new IllegalArgumentException("cannot determine model class of name: <" + discriminatorValue + ">");
98+
throw new IllegalArgumentException(
99+
"cannot determine model class of name: <" + discriminatorValue + ">");
78100
}
79101
return clazz;
80102
}
81103

82104
public JSON() {
83-
gson = createGson()
84-
.registerTypeAdapter(Date.class, dateTypeAdapter)
85-
.registerTypeAdapter(java.sql.Date.class, sqlDateTypeAdapter)
86-
.registerTypeAdapter(OffsetDateTime.class, offsetDateTimeTypeAdapter)
87-
.registerTypeAdapter(LocalDate.class, localDateTypeAdapter)
88-
.registerTypeAdapter(byte[].class, byteArrayAdapter)
89-
.create();
105+
gson =
106+
createGson()
107+
.registerTypeAdapter(Date.class, dateTypeAdapter)
108+
.registerTypeAdapter(java.sql.Date.class, sqlDateTypeAdapter)
109+
.registerTypeAdapter(OffsetDateTime.class, offsetDateTimeTypeAdapter)
110+
.registerTypeAdapter(LocalDate.class, localDateTypeAdapter)
111+
.registerTypeAdapter(byte[].class, byteArrayAdapter)
112+
.create();
90113
}
91114

92115
/**
@@ -127,8 +150,8 @@ public String serialize(Object obj) {
127150
/**
128151
* Deserialize the given JSON string to Java object.
129152
*
130-
* @param <T> Type
131-
* @param body The JSON string
153+
* @param <T> Type
154+
* @param body The JSON string
132155
* @param returnType The type to deserialize into
133156
* @return The deserialized Java object
134157
*/
@@ -137,7 +160,8 @@ public <T> T deserialize(String body, Type returnType) {
137160
try {
138161
if (isLenientOnJson) {
139162
JsonReader jsonReader = new JsonReader(new StringReader(body));
140-
// see https://google-gson.googlecode.com/svn/trunk/gson/docs/javadocs/com/google/gson/stream/JsonReader.html#setLenient(boolean)
163+
// see
164+
// https://google-gson.googlecode.com/svn/trunk/gson/docs/javadocs/com/google/gson/stream/JsonReader.html#setLenient(boolean)
141165
jsonReader.setLenient(true);
142166
return gson.fromJson(jsonReader, returnType);
143167
} else {
@@ -154,18 +178,19 @@ public <T> T deserialize(String body, Type returnType) {
154178
}
155179
}
156180

157-
/**
158-
* Gson TypeAdapter for Byte Array type
159-
*/
181+
/** Gson TypeAdapter for Byte Array type */
160182
public class ByteArrayAdapter extends TypeAdapter<byte[]> {
161183

162184
@Override
163185
public void write(JsonWriter out, byte[] value) throws IOException {
186+
boolean oldHtmlSafe = out.isHtmlSafe();
187+
out.setHtmlSafe(false);
164188
if (value == null) {
165189
out.nullValue();
166190
} else {
167191
out.value(ByteString.of(value).base64());
168192
}
193+
out.setHtmlSafe(oldHtmlSafe);
169194
}
170195

171196
@Override
@@ -182,9 +207,7 @@ public byte[] read(JsonReader in) throws IOException {
182207
}
183208
}
184209

185-
/**
186-
* Gson TypeAdapter for JSR310 OffsetDateTime type
187-
*/
210+
/** Gson TypeAdapter for JSR310 OffsetDateTime type */
188211
public static class OffsetDateTimeTypeAdapter extends TypeAdapter<OffsetDateTime> {
189212

190213
private DateTimeFormatter formatter;
@@ -219,16 +242,19 @@ public OffsetDateTime read(JsonReader in) throws IOException {
219242
default:
220243
String date = in.nextString();
221244
if (date.endsWith("+0000")) {
222-
date = date.substring(0, date.length()-5) + "Z";
245+
date = date.substring(0, date.length() - 5) + "Z";
246+
}
247+
try {
248+
return OffsetDateTime.parse(date, formatter);
249+
} catch (DateTimeParseException e) {
250+
// backward-compatibility for ISO8601 timestamp format
251+
return OffsetDateTime.parse(date, DateTimeFormatter.ISO_OFFSET_DATE_TIME);
223252
}
224-
return OffsetDateTime.parse(date, formatter);
225253
}
226254
}
227255
}
228256

229-
/**
230-
* Gson TypeAdapter for JSR310 LocalDate type
231-
*/
257+
/** Gson TypeAdapter for JSR310 LocalDate type */
232258
public class LocalDateTypeAdapter extends TypeAdapter<LocalDate> {
233259

234260
private DateTimeFormatter formatter;
@@ -278,9 +304,8 @@ public JSON setLocalDateFormat(DateTimeFormatter dateFormat) {
278304
}
279305

280306
/**
281-
* Gson TypeAdapter for java.sql.Date type
282-
* If the dateFormat is null, a simple "yyyy-MM-dd" format will be used
283-
* (more efficient than SimpleDateFormat).
307+
* Gson TypeAdapter for java.sql.Date type If the dateFormat is null, a simple "yyyy-MM-dd" format
308+
* will be used (more efficient than SimpleDateFormat).
284309
*/
285310
public static class SqlDateTypeAdapter extends TypeAdapter<java.sql.Date> {
286311

@@ -323,7 +348,8 @@ public java.sql.Date read(JsonReader in) throws IOException {
323348
if (dateFormat != null) {
324349
return new java.sql.Date(dateFormat.parse(date).getTime());
325350
}
326-
return new java.sql.Date(ISO8601Utils.parse(date, new ParsePosition(0)).getTime());
351+
return new java.sql.Date(
352+
Instant.from(DateTimeFormatter.ISO_INSTANT.parse(date)).toEpochMilli());
327353
} catch (ParseException e) {
328354
throw new JsonParseException(e);
329355
}
@@ -332,8 +358,7 @@ public java.sql.Date read(JsonReader in) throws IOException {
332358
}
333359

334360
/**
335-
* Gson TypeAdapter for java.util.Date type
336-
* If the dateFormat is null, ISO8601Utils will be used.
361+
* Gson TypeAdapter for java.util.Date type If the dateFormat is null, ISO8601Utils will be used.
337362
*/
338363
public static class DateTypeAdapter extends TypeAdapter<Date> {
339364

@@ -358,7 +383,7 @@ public void write(JsonWriter out, Date date) throws IOException {
358383
if (dateFormat != null) {
359384
value = dateFormat.format(date);
360385
} else {
361-
value = ISO8601Utils.format(date, true);
386+
value = DateTimeFormatter.ISO_INSTANT.format(date.toInstant());
362387
}
363388
out.value(value);
364389
}
@@ -377,7 +402,7 @@ public Date read(JsonReader in) throws IOException {
377402
if (dateFormat != null) {
378403
return dateFormat.parse(date);
379404
}
380-
return ISO8601Utils.parse(date, new ParsePosition(0));
405+
return Date.from(Instant.from(DateTimeFormatter.ISO_INSTANT.parse(date)));
381406
} catch (ParseException e) {
382407
throw new JsonParseException(e);
383408
}
@@ -397,5 +422,4 @@ public JSON setSqlDateFormat(DateFormat dateFormat) {
397422
sqlDateTypeAdapter.setFormat(dateFormat);
398423
return this;
399424
}
400-
401425
}

kubernetes/src/test/java/io/kubernetes/client/openapi/JSONTest.java

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ public class JSONTest {
2525
private final JSON json = new JSON();
2626

2727
@Test
28-
@Ignore // TODO: Re-enable this after adding the manual changes back: https://github.com/kubernetes-client/java/pull/2818
2928
public void testSerializeByteArray() {
3029
final String plainText = "string that contains '=' when encoded";
3130
final String base64String = json.serialize(plainText.getBytes());
@@ -42,7 +41,6 @@ public void testSerializeByteArray() {
4241
}
4342

4443
@Test
45-
@Ignore // TODO: Re-enable this after adding the manual changes back: https://github.com/kubernetes-client/java/pull/2818
4644
public void testOffsetDateTime1e6Parse() {
4745
String timeStr = "\"2018-04-03T11:32:26.123456Z\"";
4846
OffsetDateTime dateTime = json.deserialize(timeStr, OffsetDateTime.class);
@@ -51,7 +49,6 @@ public void testOffsetDateTime1e6Parse() {
5149
}
5250

5351
@Test
54-
@Ignore // TODO: Re-enable this after adding the manual changes back: https://github.com/kubernetes-client/java/pull/2818
5552
public void testOffsetDateTime1e4Parse() {
5653
String timeStr = "\"2018-04-03T11:32:26.1234Z\"";
5754
OffsetDateTime dateTime = json.deserialize(timeStr, OffsetDateTime.class);
@@ -61,7 +58,6 @@ public void testOffsetDateTime1e4Parse() {
6158
}
6259

6360
@Test
64-
@Ignore // TODO: Re-enable this after adding the manual changes back: https://github.com/kubernetes-client/java/pull/2818
6561
public void testOffsetDateTime1e3Parse() {
6662
String timeStr = "\"2018-04-03T11:32:26.123Z\"";
6763
OffsetDateTime dateTime = json.deserialize(timeStr, OffsetDateTime.class);
@@ -71,7 +67,6 @@ public void testOffsetDateTime1e3Parse() {
7167
}
7268

7369
@Test
74-
@Ignore // TODO: Re-enable this after adding the manual changes back: https://github.com/kubernetes-client/java/pull/2818
7570
public void testOffsetDateTimeNoFractionParse() {
7671
String timeStr = "\"2018-04-03T11:32:26Z\"";
7772
OffsetDateTime dateTime = json.deserialize(timeStr, OffsetDateTime.class);

0 commit comments

Comments
 (0)