1515
1616import com .google .gson .Gson ;
1717import com .google .gson .GsonBuilder ;
18+ import com .google .gson .JsonElement ;
1819import com .google .gson .JsonParseException ;
1920import com .google .gson .TypeAdapter ;
20- import com .google .gson .internal .bind .util .ISO8601Utils ;
2121import com .google .gson .stream .JsonReader ;
2222import com .google .gson .stream .JsonWriter ;
23- import com .google .gson .JsonElement ;
2423import io .gsonfire .GsonFireBuilder ;
25- import io .gsonfire .TypeSelector ;
26-
27- import io .kubernetes .client .openapi .models .*;
28- import okio .ByteString ;
29-
24+ import io .kubernetes .client .gson .V1StatusPreProcessor ;
25+ import io .kubernetes .client .openapi .models .V1Status ;
3026import java .io .IOException ;
3127import java .io .StringReader ;
3228import java .lang .reflect .Type ;
3329import java .text .DateFormat ;
3430import java .text .ParseException ;
35- import java .text . ParsePosition ;
31+ import java .time . Instant ;
3632import java .time .LocalDate ;
3733import java .time .OffsetDateTime ;
3834import java .time .format .DateTimeFormatter ;
35+ import java .time .format .DateTimeFormatterBuilder ;
36+ import java .time .format .DateTimeParseException ;
37+ import java .time .temporal .ChronoField ;
3938import java .util .Date ;
40- import java .util .Locale ;
4139import java .util .Map ;
42- import java . util . HashMap ;
40+ import okio . ByteString ;
4341
4442public class JSON {
43+
4544 private Gson gson ;
45+
4646 private boolean isLenientOnJson = false ;
47+
48+ private static final DateTimeFormatter RFC3339MICRO_FORMATTER =
49+ new DateTimeFormatterBuilder ()
50+ .parseDefaulting (ChronoField .OFFSET_SECONDS , 0 )
51+ .append (DateTimeFormatter .ofPattern ("yyyy-MM-dd'T'HH:mm:ss" ))
52+ .optionalStart ()
53+ .appendFraction (ChronoField .NANO_OF_SECOND , 6 , 6 , true )
54+ .optionalEnd ()
55+ .appendOffsetId ()
56+ .toFormatter ();
57+
4758 private DateTypeAdapter dateTypeAdapter = new DateTypeAdapter ();
59+
4860 private SqlDateTypeAdapter sqlDateTypeAdapter = new SqlDateTypeAdapter ();
49- private OffsetDateTimeTypeAdapter offsetDateTimeTypeAdapter = new OffsetDateTimeTypeAdapter ();
61+
62+ private OffsetDateTimeTypeAdapter offsetDateTimeTypeAdapter =
63+ new OffsetDateTimeTypeAdapter (RFC3339MICRO_FORMATTER );
64+
5065 private LocalDateTypeAdapter localDateTypeAdapter = new LocalDateTypeAdapter ();
66+
5167 private ByteArrayAdapter byteArrayAdapter = new ByteArrayAdapter ();
5268
5369 public static GsonBuilder createGson () {
54- GsonFireBuilder fireBuilder = new GsonFireBuilder ()
55- ;
56- GsonBuilder builder = fireBuilder .createGsonBuilder ();
70+ GsonFireBuilder fireBuilder = new GsonFireBuilder ();
71+ GsonBuilder builder =
72+ fireBuilder
73+ .registerPreProcessor (V1Status .class , new V1StatusPreProcessor ())
74+ .createGsonBuilder ();
5775 return builder ;
5876 }
5977
6078 private static String getDiscriminatorValue (JsonElement readElement , String discriminatorField ) {
6179 JsonElement element = readElement .getAsJsonObject ().get (discriminatorField );
6280 if (null == element ) {
63- throw new IllegalArgumentException ("missing discriminator field: <" + discriminatorField + ">" );
81+ throw new IllegalArgumentException (
82+ "missing discriminator field: <" + discriminatorField + ">" );
6483 }
6584 return element .getAsString ();
6685 }
6786
6887 /**
69- * Returns the Java class that implements the OpenAPI schema for the specified discriminator value.
88+ * Returns the Java class that implements the OpenAPI schema for the specified discriminator
89+ * value.
7090 *
7191 * @param classByDiscriminatorValue The map of discriminator values to Java classes.
7292 * @param discriminatorValue The value of the OpenAPI discriminator in the input data.
7393 * @return The Java class that implements the OpenAPI schema
7494 */
75- private static Class getClassByDiscriminator (Map classByDiscriminatorValue , String discriminatorValue ) {
95+ private static Class getClassByDiscriminator (
96+ Map classByDiscriminatorValue , String discriminatorValue ) {
7697 Class clazz = (Class ) classByDiscriminatorValue .get (discriminatorValue );
7798 if (null == clazz ) {
78- throw new IllegalArgumentException ("cannot determine model class of name: <" + discriminatorValue + ">" );
99+ throw new IllegalArgumentException (
100+ "cannot determine model class of name: <" + discriminatorValue + ">" );
79101 }
80102 return clazz ;
81103 }
82104
83105 public JSON () {
84- gson = createGson ()
85- .registerTypeAdapter (Date .class , dateTypeAdapter )
86- .registerTypeAdapter (java .sql .Date .class , sqlDateTypeAdapter )
87- .registerTypeAdapter (OffsetDateTime .class , offsetDateTimeTypeAdapter )
88- .registerTypeAdapter (LocalDate .class , localDateTypeAdapter )
89- .registerTypeAdapter (byte [].class , byteArrayAdapter )
90- .create ();
106+ gson =
107+ createGson ()
108+ .registerTypeAdapter (Date .class , dateTypeAdapter )
109+ .registerTypeAdapter (java .sql .Date .class , sqlDateTypeAdapter )
110+ .registerTypeAdapter (OffsetDateTime .class , offsetDateTimeTypeAdapter )
111+ .registerTypeAdapter (LocalDate .class , localDateTypeAdapter )
112+ .registerTypeAdapter (byte [].class , byteArrayAdapter )
113+ .create ();
91114 }
92115
93116 /**
@@ -128,8 +151,8 @@ public String serialize(Object obj) {
128151 /**
129152 * Deserialize the given JSON string to Java object.
130153 *
131- * @param <T> Type
132- * @param body The JSON string
154+ * @param <T> Type
155+ * @param body The JSON string
133156 * @param returnType The type to deserialize into
134157 * @return The deserialized Java object
135158 */
@@ -138,7 +161,8 @@ public <T> T deserialize(String body, Type returnType) {
138161 try {
139162 if (isLenientOnJson ) {
140163 JsonReader jsonReader = new JsonReader (new StringReader (body ));
141- // see https://google-gson.googlecode.com/svn/trunk/gson/docs/javadocs/com/google/gson/stream/JsonReader.html#setLenient(boolean)
164+ // see
165+ // https://google-gson.googlecode.com/svn/trunk/gson/docs/javadocs/com/google/gson/stream/JsonReader.html#setLenient(boolean)
142166 jsonReader .setLenient (true );
143167 return gson .fromJson (jsonReader , returnType );
144168 } else {
@@ -155,18 +179,19 @@ public <T> T deserialize(String body, Type returnType) {
155179 }
156180 }
157181
158- /**
159- * Gson TypeAdapter for Byte Array type
160- */
182+ /** Gson TypeAdapter for Byte Array type */
161183 public class ByteArrayAdapter extends TypeAdapter <byte []> {
162184
163185 @ Override
164186 public void write (JsonWriter out , byte [] value ) throws IOException {
187+ boolean oldHtmlSafe = out .isHtmlSafe ();
188+ out .setHtmlSafe (false );
165189 if (value == null ) {
166190 out .nullValue ();
167191 } else {
168192 out .value (ByteString .of (value ).base64 ());
169193 }
194+ out .setHtmlSafe (oldHtmlSafe );
170195 }
171196
172197 @ Override
@@ -183,9 +208,7 @@ public byte[] read(JsonReader in) throws IOException {
183208 }
184209 }
185210
186- /**
187- * Gson TypeAdapter for JSR310 OffsetDateTime type
188- */
211+ /** Gson TypeAdapter for JSR310 OffsetDateTime type */
189212 public static class OffsetDateTimeTypeAdapter extends TypeAdapter <OffsetDateTime > {
190213
191214 private DateTimeFormatter formatter ;
@@ -220,16 +243,19 @@ public OffsetDateTime read(JsonReader in) throws IOException {
220243 default :
221244 String date = in .nextString ();
222245 if (date .endsWith ("+0000" )) {
223- date = date .substring (0 , date .length ()-5 ) + "Z" ;
246+ date = date .substring (0 , date .length () - 5 ) + "Z" ;
247+ }
248+ try {
249+ return OffsetDateTime .parse (date , formatter );
250+ } catch (DateTimeParseException e ) {
251+ // backward-compatibility for ISO8601 timestamp format
252+ return OffsetDateTime .parse (date , DateTimeFormatter .ISO_OFFSET_DATE_TIME );
224253 }
225- return OffsetDateTime .parse (date , formatter );
226254 }
227255 }
228256 }
229257
230- /**
231- * Gson TypeAdapter for JSR310 LocalDate type
232- */
258+ /** Gson TypeAdapter for JSR310 LocalDate type */
233259 public class LocalDateTypeAdapter extends TypeAdapter <LocalDate > {
234260
235261 private DateTimeFormatter formatter ;
@@ -279,9 +305,8 @@ public JSON setLocalDateFormat(DateTimeFormatter dateFormat) {
279305 }
280306
281307 /**
282- * Gson TypeAdapter for java.sql.Date type
283- * If the dateFormat is null, a simple "yyyy-MM-dd" format will be used
284- * (more efficient than SimpleDateFormat).
308+ * Gson TypeAdapter for java.sql.Date type If the dateFormat is null, a simple "yyyy-MM-dd" format
309+ * will be used (more efficient than SimpleDateFormat).
285310 */
286311 public static class SqlDateTypeAdapter extends TypeAdapter <java .sql .Date > {
287312
@@ -324,7 +349,8 @@ public java.sql.Date read(JsonReader in) throws IOException {
324349 if (dateFormat != null ) {
325350 return new java .sql .Date (dateFormat .parse (date ).getTime ());
326351 }
327- return new java .sql .Date (ISO8601Utils .parse (date , new ParsePosition (0 )).getTime ());
352+ return new java .sql .Date (
353+ Instant .from (DateTimeFormatter .ISO_INSTANT .parse (date )).toEpochMilli ());
328354 } catch (ParseException e ) {
329355 throw new JsonParseException (e );
330356 }
@@ -333,8 +359,7 @@ public java.sql.Date read(JsonReader in) throws IOException {
333359 }
334360
335361 /**
336- * Gson TypeAdapter for java.util.Date type
337- * If the dateFormat is null, ISO8601Utils will be used.
362+ * Gson TypeAdapter for java.util.Date type If the dateFormat is null, ISO8601Utils will be used.
338363 */
339364 public static class DateTypeAdapter extends TypeAdapter <Date > {
340365
@@ -359,7 +384,7 @@ public void write(JsonWriter out, Date date) throws IOException {
359384 if (dateFormat != null ) {
360385 value = dateFormat .format (date );
361386 } else {
362- value = ISO8601Utils . format (date , true );
387+ value = DateTimeFormatter . ISO_INSTANT . format (date . toInstant () );
363388 }
364389 out .value (value );
365390 }
@@ -378,7 +403,7 @@ public Date read(JsonReader in) throws IOException {
378403 if (dateFormat != null ) {
379404 return dateFormat .parse (date );
380405 }
381- return ISO8601Utils . parse (date , new ParsePosition ( 0 ));
406+ return Date . from ( Instant . from ( DateTimeFormatter . ISO_INSTANT . parse (date ) ));
382407 } catch (ParseException e ) {
383408 throw new JsonParseException (e );
384409 }
@@ -398,5 +423,4 @@ public JSON setSqlDateFormat(DateFormat dateFormat) {
398423 sqlDateTypeAdapter .setFormat (dateFormat );
399424 return this ;
400425 }
401-
402426}
0 commit comments