Copy SqlTimestampDeserializer from gwtjsonrpc
Keep package-private in the json package so it can be used by all Gson instances created by OutputFormat. Also copy in JavaSqlTimestampHelper, which is a dependency. Change-Id: Ib9d31d346dbf2fd28b8fc78e425c0bf81a2fe9a6
This commit is contained in:
		
							
								
								
									
										108
									
								
								java/com/google/gerrit/json/JavaSqlTimestampHelper.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										108
									
								
								java/com/google/gerrit/json/JavaSqlTimestampHelper.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,108 @@ | ||||
| // Copyright 2008 Google Inc. | ||||
| // | ||||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| // you may not use this file except in compliance with the License. | ||||
| // You may obtain a copy of the License at | ||||
| // | ||||
| // http://www.apache.org/licenses/LICENSE-2.0 | ||||
| // | ||||
| // Unless required by applicable law or agreed to in writing, software | ||||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| // See the License for the specific language governing permissions and | ||||
| // limitations under the License. | ||||
|  | ||||
| package com.google.gerrit.json; | ||||
|  | ||||
| import java.sql.Timestamp; | ||||
| import java.util.Date; | ||||
|  | ||||
| /** Utility to parse Timestamp from a string. */ | ||||
| public class JavaSqlTimestampHelper { | ||||
|   /** | ||||
|    * Parse a string into a timestamp. | ||||
|    * | ||||
|    * <p>Note that {@link Timestamp}s have no timezone, so the result is relative to the UTC epoch. | ||||
|    * | ||||
|    * <p>Supports the format {@code yyyy-MM-dd[ HH:mm:ss[.SSS][ Z]]} where {@code Z} is a 4-digit | ||||
|    * offset with sign, e.g. {@code -0500}. | ||||
|    * | ||||
|    * @param s input string. | ||||
|    * @return resulting timestamp. | ||||
|    */ | ||||
|   public static Timestamp parseTimestamp(String s) { | ||||
|     String[] components = s.split(" "); | ||||
|     if (components.length < 1 || components.length > 3) { | ||||
|       throw new IllegalArgumentException("Expected date and optional time: " + s); | ||||
|     } | ||||
|     String date = components[0]; | ||||
|     String time = components.length >= 2 ? components[1] : null; | ||||
|     int off = components.length == 3 ? parseTimeZone(components[2]) : 0; | ||||
|     String[] dSplit = date.split("-"); | ||||
|     if (dSplit.length != 3) { | ||||
|       throw new IllegalArgumentException("Invalid date format: " + date); | ||||
|     } | ||||
|     int yy, mm, dd; | ||||
|     try { | ||||
|       yy = Integer.parseInt(dSplit[0]) - 1900; | ||||
|       mm = Integer.parseInt(dSplit[1]) - 1; | ||||
|       dd = Integer.parseInt(dSplit[2]); | ||||
|     } catch (NumberFormatException e) { | ||||
|       throw new IllegalArgumentException("Invalid date format: " + date, e); | ||||
|     } | ||||
|  | ||||
|     int hh, mi, ss, ns; | ||||
|     if (time != null) { | ||||
|       int p = time.indexOf('.'); | ||||
|       String t; | ||||
|       double f; | ||||
|       try { | ||||
|         if (p >= 0) { | ||||
|           t = time.substring(0, p); | ||||
|           f = Double.parseDouble("0." + time.substring(p + 1)); | ||||
|         } else { | ||||
|           t = time; | ||||
|           f = 0; | ||||
|         } | ||||
|         String[] tSplit = t.split(":"); | ||||
|         if (tSplit.length != 3) { | ||||
|           throw new IllegalArgumentException("Invalid time format: " + time); | ||||
|         } | ||||
|         hh = Integer.parseInt(tSplit[0]); | ||||
|         mi = Integer.parseInt(tSplit[1]); | ||||
|         ss = Integer.parseInt(tSplit[2]); | ||||
|         ns = (int) Math.round(f * 1e9); | ||||
|       } catch (NumberFormatException e) { | ||||
|         throw new IllegalArgumentException("Invalid time format: " + time, e); | ||||
|       } | ||||
|     } else { | ||||
|       hh = 0; | ||||
|       mi = 0; | ||||
|       ss = 0; | ||||
|       ns = 0; | ||||
|     } | ||||
|     @SuppressWarnings("deprecation") | ||||
|     Timestamp result = new Timestamp(Date.UTC(yy, mm, dd, hh, mi, ss) - off); | ||||
|     result.setNanos(ns); | ||||
|     return result; | ||||
|   } | ||||
|  | ||||
|   private static int parseTimeZone(String s) { | ||||
|     if (s.length() != 5 || (s.charAt(0) != '-' && s.charAt(0) != '+')) { | ||||
|       throw new IllegalArgumentException("Invalid time zone: " + s); | ||||
|     } | ||||
|     for (int i = 1; i < s.length(); i++) { | ||||
|       if (s.charAt(i) < '0' || s.charAt(i) > '9') { | ||||
|         throw new IllegalArgumentException("Invalid time zone: " + s); | ||||
|       } | ||||
|     } | ||||
|     int off = | ||||
|         (s.charAt(0) == '-' ? -1 : 1) | ||||
|             * 60 | ||||
|             * 1000 | ||||
|             * ((60 * Integer.parseInt(s.substring(1, 3))) + Integer.parseInt(s.substring(3, 5))); | ||||
|     return off; | ||||
|   } | ||||
|  | ||||
|   private JavaSqlTimestampHelper() {} | ||||
| } | ||||
| @@ -17,7 +17,6 @@ package com.google.gerrit.json; | ||||
| import com.google.gson.FieldNamingPolicy; | ||||
| import com.google.gson.Gson; | ||||
| import com.google.gson.GsonBuilder; | ||||
| import com.google.gwtjsonrpc.server.SqlTimestampDeserializer; | ||||
| import java.sql.Timestamp; | ||||
|  | ||||
| /** Standard output format used by an API call. */ | ||||
|   | ||||
							
								
								
									
										66
									
								
								java/com/google/gerrit/json/SqlTimestampDeserializer.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								java/com/google/gerrit/json/SqlTimestampDeserializer.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,66 @@ | ||||
| // Copyright 2008 Google Inc. | ||||
| // | ||||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| // you may not use this file except in compliance with the License. | ||||
| // You may obtain a copy of the License at | ||||
| // | ||||
| // http://www.apache.org/licenses/LICENSE-2.0 | ||||
| // | ||||
| // Unless required by applicable law or agreed to in writing, software | ||||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| // See the License for the specific language governing permissions and | ||||
| // limitations under the License. | ||||
|  | ||||
| package com.google.gerrit.json; | ||||
|  | ||||
| import com.google.gson.JsonDeserializationContext; | ||||
| import com.google.gson.JsonDeserializer; | ||||
| import com.google.gson.JsonElement; | ||||
| import com.google.gson.JsonNull; | ||||
| import com.google.gson.JsonParseException; | ||||
| import com.google.gson.JsonPrimitive; | ||||
| import com.google.gson.JsonSerializationContext; | ||||
| import com.google.gson.JsonSerializer; | ||||
| import java.lang.reflect.Type; | ||||
| import java.text.SimpleDateFormat; | ||||
| import java.util.TimeZone; | ||||
|  | ||||
| class SqlTimestampDeserializer | ||||
|     implements JsonDeserializer<java.sql.Timestamp>, JsonSerializer<java.sql.Timestamp> { | ||||
|   private static final TimeZone UTC = TimeZone.getTimeZone("UTC"); | ||||
|  | ||||
|   @Override | ||||
|   public java.sql.Timestamp deserialize( | ||||
|       final JsonElement json, final Type typeOfT, final JsonDeserializationContext context) | ||||
|       throws JsonParseException { | ||||
|     if (json.isJsonNull()) { | ||||
|       return null; | ||||
|     } | ||||
|     if (!json.isJsonPrimitive()) { | ||||
|       throw new JsonParseException("Expected string for timestamp type"); | ||||
|     } | ||||
|     final JsonPrimitive p = (JsonPrimitive) json; | ||||
|     if (!p.isString()) { | ||||
|       throw new JsonParseException("Expected string for timestamp type"); | ||||
|     } | ||||
|  | ||||
|     return JavaSqlTimestampHelper.parseTimestamp(p.getAsString()); | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public JsonElement serialize( | ||||
|       final java.sql.Timestamp src, final Type typeOfSrc, final JsonSerializationContext context) { | ||||
|     if (src == null) { | ||||
|       return new JsonNull(); | ||||
|     } | ||||
|     return new JsonPrimitive(newFormat().format(src) + "000000"); | ||||
|   } | ||||
|  | ||||
|   private static SimpleDateFormat newFormat() { | ||||
|     final SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); | ||||
|     f.setTimeZone(UTC); | ||||
|     f.setLenient(true); | ||||
|     return f; | ||||
|   } | ||||
| } | ||||
							
								
								
									
										11
									
								
								javatests/com/google/gerrit/json/BUILD
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								javatests/com/google/gerrit/json/BUILD
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | ||||
| load("//tools/bzl:junit.bzl", "junit_tests") | ||||
|  | ||||
| junit_tests( | ||||
|     name = "json_tests", | ||||
|     srcs = glob(["*.java"]), | ||||
|     deps = [ | ||||
|         "//java/com/google/gerrit/json", | ||||
|         "//lib:guava", | ||||
|         "//lib/truth", | ||||
|     ], | ||||
| ) | ||||
| @@ -0,0 +1,87 @@ | ||||
| // Copyright (C) 2014 Google Inc. All Rights Reserved. | ||||
| // | ||||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| // you may not use this file except in compliance with the License. | ||||
| // You may obtain a copy of the License at | ||||
| // | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0 | ||||
| // | ||||
| // Unless required by applicable law or agreed to in writing, software | ||||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| // See the License for the specific language governing permissions and | ||||
| // limitations under the License. | ||||
|  | ||||
| package com.google.gerrit.json; | ||||
|  | ||||
| import static com.google.common.truth.Truth.assertThat; | ||||
| import static com.google.common.truth.Truth.assert_; | ||||
| import static com.google.gerrit.json.JavaSqlTimestampHelper.parseTimestamp; | ||||
|  | ||||
| import java.text.SimpleDateFormat; | ||||
| import java.util.TimeZone; | ||||
| import org.junit.After; | ||||
| import org.junit.Before; | ||||
| import org.junit.Test; | ||||
|  | ||||
| public class JavaSqlTimestampHelperTest { | ||||
|   private SimpleDateFormat format; | ||||
|   private TimeZone systemTimeZone; | ||||
|  | ||||
|   @Before | ||||
|   public void setUp() throws Exception { | ||||
|     synchronized (TimeZone.class) { | ||||
|       systemTimeZone = TimeZone.getDefault(); | ||||
|       TimeZone.setDefault(TimeZone.getTimeZone("GMT-5:00")); | ||||
|       format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS Z"); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   @After | ||||
|   public void resetTimeZone() { | ||||
|     TimeZone.setDefault(systemTimeZone); | ||||
|   } | ||||
|  | ||||
|   @Test | ||||
|   public void parseFullTimestamp() { | ||||
|     assertThat(reformat("2006-01-02 20:04:05.789000000")) | ||||
|         .isEqualTo("2006-01-02 15:04:05.789 -0500"); | ||||
|     assertThat(reformat("2006-01-02 20:04:05")).isEqualTo("2006-01-02 15:04:05.000 -0500"); | ||||
|   } | ||||
|  | ||||
|   @Test | ||||
|   public void parseDateOnly() { | ||||
|     assertThat(reformat("2006-01-02")).isEqualTo("2006-01-01 19:00:00.000 -0500"); | ||||
|   } | ||||
|  | ||||
|   @Test | ||||
|   public void parseTimeZone() { | ||||
|     assertThat(reformat("2006-01-02 15:04:05.789 -0100")) | ||||
|         .isEqualTo("2006-01-02 11:04:05.789 -0500"); | ||||
|     assertThat(reformat("2006-01-02 15:04:05.789 -0000")) | ||||
|         .isEqualTo("2006-01-02 10:04:05.789 -0500"); | ||||
|     assertThat(reformat("2006-01-02 15:04:05.789 +0100")) | ||||
|         .isEqualTo("2006-01-02 09:04:05.789 -0500"); | ||||
|   } | ||||
|  | ||||
|   @Test | ||||
|   public void parseInvalidTimestamps() { | ||||
|     assertInvalid("2006-01-02-15:04:05.789000000"); | ||||
|     assertInvalid("2006-01-02T15:04:05.789000000"); | ||||
|     assertInvalid("15:04:05"); | ||||
|     assertInvalid("15:04:05.999000000"); | ||||
|   } | ||||
|  | ||||
|   private static void assertInvalid(String input) { | ||||
|     try { | ||||
|       parseTimestamp(input); | ||||
|       assert_().fail("Expected IllegalArgumentException for: " + input); | ||||
|     } catch (IllegalArgumentException e) { | ||||
|       // Expected; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   private String reformat(String input) { | ||||
|     return format.format(parseTimestamp(input)); | ||||
|   } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user
	 Dave Borowitz
					Dave Borowitz