[libgoogle-gson-java] 09/20: Fix FTBFS with Java 9.
Markus Koschany
apo at moszumanska.debian.org
Sun Apr 8 19:16:40 UTC 2018
This is an automated email from the git hooks/post-receive script.
apo pushed a commit to branch master
in repository libgoogle-gson-java.
commit a92baba1447bbd85dad0cf38ab891763a7c237f5
Author: Markus Koschany <apo at debian.org>
Date: Sun Apr 8 01:03:13 2018 +0200
Fix FTBFS with Java 9.
---
debian/patches/java9-dateformat.patch | 552 ++++++++++++++++++++++++++++++++++
debian/patches/java9-reflection.patch | 276 +++++++++++++++++
debian/patches/series | 2 +
3 files changed, 830 insertions(+)
diff --git a/debian/patches/java9-dateformat.patch b/debian/patches/java9-dateformat.patch
new file mode 100644
index 0000000..26add3b
--- /dev/null
+++ b/debian/patches/java9-dateformat.patch
@@ -0,0 +1,552 @@
+From 0aaf5ff408a54eb7dc238d3569b5d1cef9273047 Mon Sep 17 00:00:00 2001
+From: Andrey Mogilev <amogilev at gmail.com>
+Date: Sat, 30 Dec 2017 02:14:43 +0700
+Subject: [PATCH] fix Java9 DateFormat changes (#1211)
+
+* fix Java9 DateFormat changes
+
+* fix Codacy warnings
+---
+ .../com/google/gson/DefaultDateTypeAdapter.java | 88 ++++++++++++++--------
+ .../gson/internal/PreJava9DateFormatProvider.java | 86 +++++++++++++++++++++
+ .../google/gson/internal/bind/DateTypeAdapter.java | 37 ++++++---
+ .../java/com/google/gson/util/VersionUtils.java | 49 ++++++++++++
+ .../google/gson/DefaultDateTypeAdapterTest.java | 32 +++++---
+ .../gson/functional/DefaultTypeAdaptersTest.java | 20 ++++-
+ .../com/google/gson/functional/ObjectTest.java | 8 +-
+ 7 files changed, 263 insertions(+), 57 deletions(-)
+ create mode 100644 gson/src/main/java/com/google/gson/internal/PreJava9DateFormatProvider.java
+ create mode 100644 gson/src/main/java/com/google/gson/util/VersionUtils.java
+
+diff --git a/gson/src/main/java/com/google/gson/DefaultDateTypeAdapter.java b/gson/src/main/java/com/google/gson/DefaultDateTypeAdapter.java
+index 3ce97fe89..0cbf77cea 100644
+--- a/gson/src/main/java/com/google/gson/DefaultDateTypeAdapter.java
++++ b/gson/src/main/java/com/google/gson/DefaultDateTypeAdapter.java
+@@ -22,13 +22,17 @@
+ import java.text.ParseException;
+ import java.text.ParsePosition;
+ import java.text.SimpleDateFormat;
++import java.util.ArrayList;
+ import java.util.Date;
++import java.util.List;
+ import java.util.Locale;
+
++import com.google.gson.internal.PreJava9DateFormatProvider;
+ import com.google.gson.internal.bind.util.ISO8601Utils;
+ import com.google.gson.stream.JsonReader;
+ import com.google.gson.stream.JsonToken;
+ import com.google.gson.stream.JsonWriter;
++import com.google.gson.util.VersionUtils;
+
+ /**
+ * This type adapter supports three subclasses of date: Date, Timestamp, and
+@@ -42,42 +46,63 @@
+ private static final String SIMPLE_NAME = "DefaultDateTypeAdapter";
+
+ private final Class<? extends Date> dateType;
+- private final DateFormat enUsFormat;
+- private final DateFormat localFormat;
+-
++
++ /**
++ * List of 1 or more different date formats used for de-serialization attempts.
++ * The first of them is used for serialization as well.
++ */
++ private final List<DateFormat> dateFormats = new ArrayList<DateFormat>();
++
+ DefaultDateTypeAdapter(Class<? extends Date> dateType) {
+- this(dateType,
+- DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT, Locale.US),
+- DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT));
++ this.dateType = verifyDateType(dateType);
++ dateFormats.add(DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT, Locale.US));
++ if (!Locale.getDefault().equals(Locale.US)) {
++ dateFormats.add(DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT));
++ }
++ if (VersionUtils.isJava9OrLater()) {
++ dateFormats.add(PreJava9DateFormatProvider.getUSDateTimeFormat(DateFormat.DEFAULT, DateFormat.DEFAULT));
++ }
+ }
+
+ DefaultDateTypeAdapter(Class<? extends Date> dateType, String datePattern) {
+- this(dateType, new SimpleDateFormat(datePattern, Locale.US), new SimpleDateFormat(datePattern));
++ this.dateType = verifyDateType(dateType);
++ dateFormats.add(new SimpleDateFormat(datePattern, Locale.US));
++ if (!Locale.getDefault().equals(Locale.US)) {
++ dateFormats.add(new SimpleDateFormat(datePattern));
++ }
+ }
+
+ DefaultDateTypeAdapter(Class<? extends Date> dateType, int style) {
+- this(dateType, DateFormat.getDateInstance(style, Locale.US), DateFormat.getDateInstance(style));
++ this.dateType = verifyDateType(dateType);
++ dateFormats.add(DateFormat.getDateInstance(style, Locale.US));
++ if (!Locale.getDefault().equals(Locale.US)) {
++ dateFormats.add(DateFormat.getDateInstance(style));
++ }
++ if (VersionUtils.isJava9OrLater()) {
++ dateFormats.add(PreJava9DateFormatProvider.getUSDateFormat(style));
++ }
+ }
+
+ public DefaultDateTypeAdapter(int dateStyle, int timeStyle) {
+- this(Date.class,
+- DateFormat.getDateTimeInstance(dateStyle, timeStyle, Locale.US),
+- DateFormat.getDateTimeInstance(dateStyle, timeStyle));
++ this(Date.class, dateStyle, timeStyle);
+ }
+
+ public DefaultDateTypeAdapter(Class<? extends Date> dateType, int dateStyle, int timeStyle) {
+- this(dateType,
+- DateFormat.getDateTimeInstance(dateStyle, timeStyle, Locale.US),
+- DateFormat.getDateTimeInstance(dateStyle, timeStyle));
++ this.dateType = verifyDateType(dateType);
++ dateFormats.add(DateFormat.getDateTimeInstance(dateStyle, timeStyle, Locale.US));
++ if (!Locale.getDefault().equals(Locale.US)) {
++ dateFormats.add(DateFormat.getDateTimeInstance(dateStyle, timeStyle));
++ }
++ if (VersionUtils.isJava9OrLater()) {
++ dateFormats.add(PreJava9DateFormatProvider.getUSDateTimeFormat(dateStyle, timeStyle));
++ }
+ }
+
+- DefaultDateTypeAdapter(final Class<? extends Date> dateType, DateFormat enUsFormat, DateFormat localFormat) {
++ private static Class<? extends Date> verifyDateType(Class<? extends Date> dateType) {
+ if ( dateType != Date.class && dateType != java.sql.Date.class && dateType != Timestamp.class ) {
+ throw new IllegalArgumentException("Date type must be one of " + Date.class + ", " + Timestamp.class + ", or " + java.sql.Date.class + " but was " + dateType);
+ }
+- this.dateType = dateType;
+- this.enUsFormat = enUsFormat;
+- this.localFormat = localFormat;
++ return dateType;
+ }
+
+ // These methods need to be synchronized since JDK DateFormat classes are not thread-safe
+@@ -88,8 +113,8 @@ public void write(JsonWriter out, Date value) throws IOException {
+ out.nullValue();
+ return;
+ }
+- synchronized (localFormat) {
+- String dateFormatAsString = enUsFormat.format(value);
++ synchronized(dateFormats) {
++ String dateFormatAsString = dateFormats.get(0).format(value);
+ out.value(dateFormatAsString);
+ }
+ }
+@@ -114,13 +139,12 @@ public Date read(JsonReader in) throws IOException {
+ }
+
+ private Date deserializeToDate(String s) {
+- synchronized (localFormat) {
+- try {
+- return localFormat.parse(s);
+- } catch (ParseException ignored) {}
+- try {
+- return enUsFormat.parse(s);
+- } catch (ParseException ignored) {}
++ synchronized (dateFormats) {
++ for (DateFormat dateFormat : dateFormats) {
++ try {
++ return dateFormat.parse(s);
++ } catch (ParseException ignored) {}
++ }
+ try {
+ return ISO8601Utils.parse(s, new ParsePosition(0));
+ } catch (ParseException e) {
+@@ -131,9 +155,11 @@ private Date deserializeToDate(String s) {
+
+ @Override
+ public String toString() {
+- StringBuilder sb = new StringBuilder();
+- sb.append(SIMPLE_NAME);
+- sb.append('(').append(localFormat.getClass().getSimpleName()).append(')');
+- return sb.toString();
++ DateFormat defaultFormat = dateFormats.get(0);
++ if (defaultFormat instanceof SimpleDateFormat) {
++ return SIMPLE_NAME + '(' + ((SimpleDateFormat) defaultFormat).toPattern() + ')';
++ } else {
++ return SIMPLE_NAME + '(' + defaultFormat.getClass().getSimpleName() + ')';
++ }
+ }
+ }
+diff --git a/gson/src/main/java/com/google/gson/internal/PreJava9DateFormatProvider.java b/gson/src/main/java/com/google/gson/internal/PreJava9DateFormatProvider.java
+new file mode 100644
+index 000000000..beb527c9e
+--- /dev/null
++++ b/gson/src/main/java/com/google/gson/internal/PreJava9DateFormatProvider.java
+@@ -0,0 +1,86 @@
++/*
++ * Copyright (C) 2017 The Gson authors
++ *
++ * 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.gson.internal;
++
++import java.text.DateFormat;
++import java.text.SimpleDateFormat;
++import java.util.Locale;
++
++/**
++ * Provides DateFormats for US locale with patterns which were the default ones before Java 9.
++ */
++public class PreJava9DateFormatProvider {
++
++ /**
++ * Returns the same DateFormat as {@code DateFormat.getDateInstance(style, Locale.US)} in Java 8 or below.
++ */
++ public static DateFormat getUSDateFormat(int style) {
++ return new SimpleDateFormat(getDateFormatPattern(style), Locale.US);
++ }
++
++ /**
++ * Returns the same DateFormat as {@code DateFormat.getDateTimeInstance(dateStyle, timeStyle, Locale.US)}
++ * in Java 8 or below.
++ */
++ public static DateFormat getUSDateTimeFormat(int dateStyle, int timeStyle) {
++ String pattern = getDatePartOfDateTimePattern(dateStyle) + " " + getTimePartOfDateTimePattern(timeStyle);
++ return new SimpleDateFormat(pattern, Locale.US);
++ }
++
++ private static String getDateFormatPattern(int style) {
++ switch (style) {
++ case DateFormat.SHORT:
++ return "M/d/yy";
++ case DateFormat.MEDIUM:
++ return "MMM d, y";
++ case DateFormat.LONG:
++ return "MMMM d, y";
++ case DateFormat.FULL:
++ return "EEEE, MMMM d, y";
++ default:
++ throw new IllegalArgumentException("Unknown DateFormat style: " + style);
++ }
++ }
++
++ private static String getDatePartOfDateTimePattern(int dateStyle) {
++ switch (dateStyle) {
++ case DateFormat.SHORT:
++ return "M/d/yy";
++ case DateFormat.MEDIUM:
++ return "MMM d, yyyy";
++ case DateFormat.LONG:
++ return "MMMM d, yyyy";
++ case DateFormat.FULL:
++ return "EEEE, MMMM d, yyyy";
++ default:
++ throw new IllegalArgumentException("Unknown DateFormat style: " + dateStyle);
++ }
++ }
++
++ private static String getTimePartOfDateTimePattern(int timeStyle) {
++ switch (timeStyle) {
++ case DateFormat.SHORT:
++ return "h:mm a";
++ case DateFormat.MEDIUM:
++ return "h:mm:ss a";
++ case DateFormat.FULL:
++ case DateFormat.LONG:
++ return "h:mm:ss a z";
++ default:
++ throw new IllegalArgumentException("Unknown DateFormat style: " + timeStyle);
++ }
++ }
++}
+diff --git a/gson/src/main/java/com/google/gson/internal/bind/DateTypeAdapter.java b/gson/src/main/java/com/google/gson/internal/bind/DateTypeAdapter.java
+index 561af1985..c3a3de1b5 100644
+--- a/gson/src/main/java/com/google/gson/internal/bind/DateTypeAdapter.java
++++ b/gson/src/main/java/com/google/gson/internal/bind/DateTypeAdapter.java
+@@ -20,16 +20,21 @@
+ import com.google.gson.JsonSyntaxException;
+ import com.google.gson.TypeAdapter;
+ import com.google.gson.TypeAdapterFactory;
++import com.google.gson.internal.PreJava9DateFormatProvider;
+ import com.google.gson.internal.bind.util.ISO8601Utils;
+ import com.google.gson.reflect.TypeToken;
+ import com.google.gson.stream.JsonReader;
+ import com.google.gson.stream.JsonToken;
+ import com.google.gson.stream.JsonWriter;
++import com.google.gson.util.VersionUtils;
++
+ import java.io.IOException;
+ import java.text.DateFormat;
+ import java.text.ParseException;
+ import java.text.ParsePosition;
++import java.util.ArrayList;
+ import java.util.Date;
++import java.util.List;
+ import java.util.Locale;
+
+ /**
+@@ -46,10 +51,21 @@
+ }
+ };
+
+- private final DateFormat enUsFormat
+- = DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT, Locale.US);
+- private final DateFormat localFormat
+- = DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT);
++ /**
++ * List of 1 or more different date formats used for de-serialization attempts.
++ * The first of them (default US format) is used for serialization as well.
++ */
++ private final List<DateFormat> dateFormats = new ArrayList<DateFormat>();
++
++ public DateTypeAdapter() {
++ dateFormats.add(DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT, Locale.US));
++ if (!Locale.getDefault().equals(Locale.US)) {
++ dateFormats.add(DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT));
++ }
++ if (VersionUtils.isJava9OrLater()) {
++ dateFormats.add(PreJava9DateFormatProvider.getUSDateTimeFormat(DateFormat.DEFAULT, DateFormat.DEFAULT));
++ }
++ }
+
+ @Override public Date read(JsonReader in) throws IOException {
+ if (in.peek() == JsonToken.NULL) {
+@@ -60,13 +76,10 @@
+ }
+
+ private synchronized Date deserializeToDate(String json) {
+- try {
+- return localFormat.parse(json);
+- } catch (ParseException ignored) {
+- }
+- try {
+- return enUsFormat.parse(json);
+- } catch (ParseException ignored) {
++ for (DateFormat dateFormat : dateFormats) {
++ try {
++ return dateFormat.parse(json);
++ } catch (ParseException ignored) {}
+ }
+ try {
+ return ISO8601Utils.parse(json, new ParsePosition(0));
+@@ -80,7 +93,7 @@ private synchronized Date deserializeToDate(String json) {
+ out.nullValue();
+ return;
+ }
+- String dateFormatAsString = enUsFormat.format(value);
++ String dateFormatAsString = dateFormats.get(0).format(value);
+ out.value(dateFormatAsString);
+ }
+
+diff --git a/gson/src/main/java/com/google/gson/util/VersionUtils.java b/gson/src/main/java/com/google/gson/util/VersionUtils.java
+new file mode 100644
+index 000000000..d81e43c09
+--- /dev/null
++++ b/gson/src/main/java/com/google/gson/util/VersionUtils.java
+@@ -0,0 +1,49 @@
++/*
++ * Copyright (C) 2017 The Gson authors
++ *
++ * 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.gson.util;
++
++/**
++ * Utility to check the major Java version of the current JVM.
++ */
++public class VersionUtils {
++
++ private static final int majorJavaVersion = determineMajorJavaVersion();
++
++ private static int determineMajorJavaVersion() {
++ String[] parts = System.getProperty("java.version").split("[._]");
++ int firstVer = Integer.parseInt(parts[0]);
++ if (firstVer == 1 && parts.length > 1) {
++ return Integer.parseInt(parts[1]);
++ } else {
++ return firstVer;
++ }
++ }
++
++ /**
++ * @return the major Java version, i.e. '8' for Java 1.8, '9' for Java 9 etc.
++ */
++ public static int getMajorJavaVersion() {
++ return majorJavaVersion;
++ }
++
++ /**
++ * @return {@code true} if the application is running on Java 9 or later; and {@code false} otherwise.
++ */
++ public static boolean isJava9OrLater() {
++ return majorJavaVersion >= 9;
++ }
++}
+diff --git a/gson/src/test/java/com/google/gson/DefaultDateTypeAdapterTest.java b/gson/src/test/java/com/google/gson/DefaultDateTypeAdapterTest.java
+index 3c787a665..a074bea0c 100644
+--- a/gson/src/test/java/com/google/gson/DefaultDateTypeAdapterTest.java
++++ b/gson/src/test/java/com/google/gson/DefaultDateTypeAdapterTest.java
+@@ -22,6 +22,8 @@
+ import java.util.Date;
+ import java.util.Locale;
+ import java.util.TimeZone;
++
++import com.google.gson.util.VersionUtils;
+ import junit.framework.TestCase;
+
+ /**
+@@ -45,17 +47,21 @@ private void assertFormattingAlwaysEmitsUsLocale(Locale locale) {
+ Locale defaultLocale = Locale.getDefault();
+ Locale.setDefault(locale);
+ try {
+- assertFormatted("Jan 1, 1970 12:00:00 AM", new DefaultDateTypeAdapter(Date.class));
++ String afterYearSep = VersionUtils.isJava9OrLater() ? ", " : " ";
++ String afterYearLongSep = VersionUtils.isJava9OrLater() ? " at " : " ";
++ String utcFull = VersionUtils.isJava9OrLater() ? "Coordinated Universal Time" : "UTC";
++ assertFormatted(String.format("Jan 1, 1970%s12:00:00 AM", afterYearSep),
++ new DefaultDateTypeAdapter(Date.class));
+ assertFormatted("1/1/70", new DefaultDateTypeAdapter(Date.class, DateFormat.SHORT));
+ assertFormatted("Jan 1, 1970", new DefaultDateTypeAdapter(Date.class, DateFormat.MEDIUM));
+ assertFormatted("January 1, 1970", new DefaultDateTypeAdapter(Date.class, DateFormat.LONG));
+- assertFormatted("1/1/70 12:00 AM",
++ assertFormatted(String.format("1/1/70%s12:00 AM", afterYearSep),
+ new DefaultDateTypeAdapter(DateFormat.SHORT, DateFormat.SHORT));
+- assertFormatted("Jan 1, 1970 12:00:00 AM",
++ assertFormatted(String.format("Jan 1, 1970%s12:00:00 AM", afterYearSep),
+ new DefaultDateTypeAdapter(DateFormat.MEDIUM, DateFormat.MEDIUM));
+- assertFormatted("January 1, 1970 12:00:00 AM UTC",
++ assertFormatted(String.format("January 1, 1970%s12:00:00 AM UTC", afterYearLongSep),
+ new DefaultDateTypeAdapter(DateFormat.LONG, DateFormat.LONG));
+- assertFormatted("Thursday, January 1, 1970 12:00:00 AM UTC",
++ assertFormatted(String.format("Thursday, January 1, 1970%s12:00:00 AM %s", afterYearLongSep, utcFull),
+ new DefaultDateTypeAdapter(DateFormat.FULL, DateFormat.FULL));
+ } finally {
+ TimeZone.setDefault(defaultTimeZone);
+@@ -69,17 +75,21 @@ public void testParsingDatesFormattedWithSystemLocale() throws Exception {
+ Locale defaultLocale = Locale.getDefault();
+ Locale.setDefault(Locale.FRANCE);
+ try {
+- assertParsed("1 janv. 1970 00:00:00", new DefaultDateTypeAdapter(Date.class));
++ String afterYearSep = VersionUtils.isJava9OrLater() ? " à " : " ";
++ assertParsed(String.format("1 janv. 1970%s00:00:00", afterYearSep),
++ new DefaultDateTypeAdapter(Date.class));
+ assertParsed("01/01/70", new DefaultDateTypeAdapter(Date.class, DateFormat.SHORT));
+ assertParsed("1 janv. 1970", new DefaultDateTypeAdapter(Date.class, DateFormat.MEDIUM));
+ assertParsed("1 janvier 1970", new DefaultDateTypeAdapter(Date.class, DateFormat.LONG));
+ assertParsed("01/01/70 00:00",
+ new DefaultDateTypeAdapter(DateFormat.SHORT, DateFormat.SHORT));
+- assertParsed("1 janv. 1970 00:00:00",
++ assertParsed(String.format("1 janv. 1970%s00:00:00", afterYearSep),
+ new DefaultDateTypeAdapter(DateFormat.MEDIUM, DateFormat.MEDIUM));
+- assertParsed("1 janvier 1970 00:00:00 UTC",
++ assertParsed(String.format("1 janvier 1970%s00:00:00 UTC", afterYearSep),
+ new DefaultDateTypeAdapter(DateFormat.LONG, DateFormat.LONG));
+- assertParsed("jeudi 1 janvier 1970 00 h 00 UTC",
++ assertParsed(VersionUtils.isJava9OrLater() ?
++ "jeudi 1 janvier 1970 à 00:00:00 Coordinated Universal Time" :
++ "jeudi 1 janvier 1970 00 h 00 UTC",
+ new DefaultDateTypeAdapter(DateFormat.FULL, DateFormat.FULL));
+ } finally {
+ TimeZone.setDefault(defaultTimeZone);
+@@ -117,7 +127,9 @@ public void testFormatUsesDefaultTimezone() throws Exception {
+ Locale defaultLocale = Locale.getDefault();
+ Locale.setDefault(Locale.US);
+ try {
+- assertFormatted("Dec 31, 1969 4:00:00 PM", new DefaultDateTypeAdapter(Date.class));
++ String afterYearSep = VersionUtils.isJava9OrLater() ? ", " : " ";
++ assertFormatted(String.format("Dec 31, 1969%s4:00:00 PM", afterYearSep),
++ new DefaultDateTypeAdapter(Date.class));
+ assertParsed("Dec 31, 1969 4:00:00 PM", new DefaultDateTypeAdapter(Date.class));
+ } finally {
+ TimeZone.setDefault(defaultTimeZone);
+diff --git a/gson/src/test/java/com/google/gson/functional/DefaultTypeAdaptersTest.java b/gson/src/test/java/com/google/gson/functional/DefaultTypeAdaptersTest.java
+index 198667162..635c20887 100644
+--- a/gson/src/test/java/com/google/gson/functional/DefaultTypeAdaptersTest.java
++++ b/gson/src/test/java/com/google/gson/functional/DefaultTypeAdaptersTest.java
+@@ -55,6 +55,8 @@
+ import java.util.TimeZone;
+ import java.util.TreeSet;
+ import java.util.UUID;
++
++import com.google.gson.util.VersionUtils;
+ import junit.framework.TestCase;
+
+ /**
+@@ -328,7 +330,11 @@ public void testBitSetDeserialization() throws Exception {
+ public void testDefaultDateSerialization() {
+ Date now = new Date(1315806903103L);
+ String json = gson.toJson(now);
+- assertEquals("\"Sep 11, 2011 10:55:03 PM\"", json);
++ if (VersionUtils.isJava9OrLater()) {
++ assertEquals("\"Sep 11, 2011, 10:55:03 PM\"", json);
++ } else {
++ assertEquals("\"Sep 11, 2011 10:55:03 PM\"", json);
++ }
+ }
+
+ public void testDefaultDateDeserialization() {
+@@ -369,7 +375,11 @@ public void testDefaultJavaSqlDateDeserialization() {
+ public void testDefaultJavaSqlTimestampSerialization() {
+ Timestamp now = new java.sql.Timestamp(1259875082000L);
+ String json = gson.toJson(now);
+- assertEquals("\"Dec 3, 2009 1:18:02 PM\"", json);
++ if (VersionUtils.isJava9OrLater()) {
++ assertEquals("\"Dec 3, 2009, 1:18:02 PM\"", json);
++ } else {
++ assertEquals("\"Dec 3, 2009 1:18:02 PM\"", json);
++ }
+ }
+
+ public void testDefaultJavaSqlTimestampDeserialization() {
+@@ -395,7 +405,11 @@ public void testDefaultDateSerializationUsingBuilder() throws Exception {
+ Gson gson = new GsonBuilder().create();
+ Date now = new Date(1315806903103L);
+ String json = gson.toJson(now);
+- assertEquals("\"Sep 11, 2011 10:55:03 PM\"", json);
++ if (VersionUtils.isJava9OrLater()) {
++ assertEquals("\"Sep 11, 2011, 10:55:03 PM\"", json);
++ } else {
++ assertEquals("\"Sep 11, 2011 10:55:03 PM\"", json);
++ }
+ }
+
+ public void testDefaultDateDeserializationUsingBuilder() throws Exception {
+diff --git a/gson/src/test/java/com/google/gson/functional/ObjectTest.java b/gson/src/test/java/com/google/gson/functional/ObjectTest.java
+index de1219a6a..cf82457a3 100644
+--- a/gson/src/test/java/com/google/gson/functional/ObjectTest.java
++++ b/gson/src/test/java/com/google/gson/functional/ObjectTest.java
+@@ -43,6 +43,8 @@
+ import java.util.Locale;
+ import java.util.Map;
+ import java.util.TimeZone;
++
++import com.google.gson.util.VersionUtils;
+ import junit.framework.TestCase;
+
+ /**
+@@ -482,7 +484,11 @@ public void testSingletonLists() {
+ public void testDateAsMapObjectField() {
+ HasObjectMap a = new HasObjectMap();
+ a.map.put("date", new Date(0));
+- assertEquals("{\"map\":{\"date\":\"Dec 31, 1969 4:00:00 PM\"}}", gson.toJson(a));
++ if (VersionUtils.isJava9OrLater()) {
++ assertEquals("{\"map\":{\"date\":\"Dec 31, 1969, 4:00:00 PM\"}}", gson.toJson(a));
++ } else {
++ assertEquals("{\"map\":{\"date\":\"Dec 31, 1969 4:00:00 PM\"}}", gson.toJson(a));
++ }
+ }
+
+ public class HasObjectMap {
diff --git a/debian/patches/java9-reflection.patch b/debian/patches/java9-reflection.patch
new file mode 100644
index 0000000..ea8ed43
--- /dev/null
+++ b/debian/patches/java9-reflection.patch
@@ -0,0 +1,276 @@
+From 8445689e4d1159298179580b4e260ed23bb2b9bc Mon Sep 17 00:00:00 2001
+From: Andrey Mogilev <amogilev at gmail.com>
+Date: Thu, 4 Jan 2018 02:08:50 +0700
+Subject: [PATCH] Java 9 support: use Unsafe-based reflection in Java 9+
+ (#1218)
+
+* Java 9 support: use Unsafe-based reflection in Java 9+
+
+fixes "illegal reflective access" warnings and exceptions
+
+* fix Codacy warnings
+
+* improve code quality based on PR review
+
+* improve code quality based on PR review
+
+* fix Codacy warning
+
+* improve code quality based on PR review
+
+* inlined createReflectionAccessor method
+---
+ .../gson/internal/ConstructorConstructor.java | 4 +-
+ .../bind/ReflectiveTypeAdapterFactory.java | 4 +-
+ .../reflect/PreJava9ReflectionAccessor.java | 36 ++++++++++++
+ .../gson/internal/reflect/ReflectionAccessor.java | 54 ++++++++++++++++++
+ .../internal/reflect/UnsafeReflectionAccessor.java | 64 ++++++++++++++++++++++
+ .../java/com/google/gson/reflect/package-info.java | 2 +-
+ 6 files changed, 161 insertions(+), 3 deletions(-)
+ create mode 100644 gson/src/main/java/com/google/gson/internal/reflect/PreJava9ReflectionAccessor.java
+ create mode 100644 gson/src/main/java/com/google/gson/internal/reflect/ReflectionAccessor.java
+ create mode 100644 gson/src/main/java/com/google/gson/internal/reflect/UnsafeReflectionAccessor.java
+
+diff --git a/gson/src/main/java/com/google/gson/internal/ConstructorConstructor.java b/gson/src/main/java/com/google/gson/internal/ConstructorConstructor.java
+index 6d1e7c967..5fab46010 100644
+--- a/gson/src/main/java/com/google/gson/internal/ConstructorConstructor.java
++++ b/gson/src/main/java/com/google/gson/internal/ConstructorConstructor.java
+@@ -40,6 +40,7 @@
+
+ import com.google.gson.InstanceCreator;
+ import com.google.gson.JsonIOException;
++import com.google.gson.internal.reflect.ReflectionAccessor;
+ import com.google.gson.reflect.TypeToken;
+
+ /**
+@@ -47,6 +48,7 @@
+ */
+ public final class ConstructorConstructor {
+ private final Map<Type, InstanceCreator<?>> instanceCreators;
++ private final ReflectionAccessor accessor = ReflectionAccessor.getInstance();
+
+ public ConstructorConstructor(Map<Type, InstanceCreator<?>> instanceCreators) {
+ this.instanceCreators = instanceCreators;
+@@ -98,7 +100,7 @@ public ConstructorConstructor(Map<Type, InstanceCreator<?>> instanceCreators) {
+ try {
+ final Constructor<? super T> constructor = rawType.getDeclaredConstructor();
+ if (!constructor.isAccessible()) {
+- constructor.setAccessible(true);
++ accessor.makeAccessible(constructor);
+ }
+ return new ObjectConstructor<T>() {
+ @SuppressWarnings("unchecked") // T is the same raw type as is requested
+diff --git a/gson/src/main/java/com/google/gson/internal/bind/ReflectiveTypeAdapterFactory.java b/gson/src/main/java/com/google/gson/internal/bind/ReflectiveTypeAdapterFactory.java
+index 42798d059..777e7dee3 100644
+--- a/gson/src/main/java/com/google/gson/internal/bind/ReflectiveTypeAdapterFactory.java
++++ b/gson/src/main/java/com/google/gson/internal/bind/ReflectiveTypeAdapterFactory.java
+@@ -28,6 +28,7 @@
+ import com.google.gson.internal.Excluder;
+ import com.google.gson.internal.ObjectConstructor;
+ import com.google.gson.internal.Primitives;
++import com.google.gson.internal.reflect.ReflectionAccessor;
+ import com.google.gson.reflect.TypeToken;
+ import com.google.gson.stream.JsonReader;
+ import com.google.gson.stream.JsonToken;
+@@ -49,6 +50,7 @@
+ private final FieldNamingStrategy fieldNamingPolicy;
+ private final Excluder excluder;
+ private final JsonAdapterAnnotationTypeAdapterFactory jsonAdapterFactory;
++ private final ReflectionAccessor accessor = ReflectionAccessor.getInstance();
+
+ public ReflectiveTypeAdapterFactory(ConstructorConstructor constructorConstructor,
+ FieldNamingStrategy fieldNamingPolicy, Excluder excluder,
+@@ -154,7 +156,7 @@ static boolean excludeField(Field f, boolean serialize, Excluder excluder) {
+ if (!serialize && !deserialize) {
+ continue;
+ }
+- field.setAccessible(true);
++ accessor.makeAccessible(field);
+ Type fieldType = $Gson$Types.resolve(type.getType(), raw, field.getGenericType());
+ List<String> fieldNames = getFieldNames(field);
+ BoundField previous = null;
+diff --git a/gson/src/main/java/com/google/gson/internal/reflect/PreJava9ReflectionAccessor.java b/gson/src/main/java/com/google/gson/internal/reflect/PreJava9ReflectionAccessor.java
+new file mode 100644
+index 000000000..2f006517e
+--- /dev/null
++++ b/gson/src/main/java/com/google/gson/internal/reflect/PreJava9ReflectionAccessor.java
+@@ -0,0 +1,36 @@
++/*
++ * Copyright (C) 2017 The Gson authors
++ *
++ * 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.gson.internal.reflect;
++
++import java.lang.reflect.AccessibleObject;
++
++/**
++ * A basic implementation of {@link ReflectionAccessor} which is suitable for Java 8 and below.
++ * <p>
++ * This implementation just calls {@link AccessibleObject#setAccessible(boolean) setAccessible(true)}, which worked
++ * fine before Java 9.
++ */
++final class PreJava9ReflectionAccessor extends ReflectionAccessor {
++
++ /**
++ * {@inheritDoc}
++ */
++ @Override
++ public void makeAccessible(AccessibleObject ao) {
++ ao.setAccessible(true);
++ }
++
++}
+diff --git a/gson/src/main/java/com/google/gson/internal/reflect/ReflectionAccessor.java b/gson/src/main/java/com/google/gson/internal/reflect/ReflectionAccessor.java
+new file mode 100644
+index 000000000..42230d254
+--- /dev/null
++++ b/gson/src/main/java/com/google/gson/internal/reflect/ReflectionAccessor.java
+@@ -0,0 +1,54 @@
++/*
++ * Copyright (C) 2017 The Gson authors
++ *
++ * 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.gson.internal.reflect;
++
++import com.google.gson.util.VersionUtils;
++
++import java.lang.reflect.AccessibleObject;
++
++/**
++ * Provides a replacement for {@link AccessibleObject#setAccessible(boolean)}, which may be used to
++ * avoid reflective access issues appeared in Java 9, like {@link java.lang.reflect.InaccessibleObjectException}
++ * thrown or warnings like
++ * <pre>
++ * WARNING: An illegal reflective access operation has occurred
++ * WARNING: Illegal reflective access by ...
++ * </pre>
++ * <p/>
++ * Works both for Java 9 and earlier Java versions.
++ */
++public abstract class ReflectionAccessor {
++
++ // the singleton instance, use getInstance() to obtain
++ private static final ReflectionAccessor instance = VersionUtils.getMajorJavaVersion() < 9 ? new PreJava9ReflectionAccessor() : new UnsafeReflectionAccessor();
++
++ /**
++ * Does the same as {@code ao.setAccessible(true)}, but never throws
++ * {@link java.lang.reflect.InaccessibleObjectException}
++ */
++ public abstract void makeAccessible(AccessibleObject ao);
++
++ /**
++ * Obtains a {@link ReflectionAccessor} instance suitable for the current Java version.
++ * <p>
++ * You may need one a reflective operation in your code throws {@link java.lang.reflect.InaccessibleObjectException}.
++ * In such a case, use {@link ReflectionAccessor#makeAccessible(AccessibleObject)} on a field, method or constructor
++ * (instead of basic {@link AccessibleObject#setAccessible(boolean)}).
++ */
++ public static ReflectionAccessor getInstance() {
++ return instance;
++ }
++}
+diff --git a/gson/src/main/java/com/google/gson/internal/reflect/UnsafeReflectionAccessor.java b/gson/src/main/java/com/google/gson/internal/reflect/UnsafeReflectionAccessor.java
+new file mode 100644
+index 000000000..5bc59bd8e
+--- /dev/null
++++ b/gson/src/main/java/com/google/gson/internal/reflect/UnsafeReflectionAccessor.java
+@@ -0,0 +1,64 @@
++/*
++ * Copyright (C) 2017 The Gson authors
++ *
++ * 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.gson.internal.reflect;
++
++import sun.misc.Unsafe;
++
++import java.lang.reflect.AccessibleObject;
++import java.lang.reflect.Field;
++
++/**
++ * An implementation of {@link ReflectionAccessor} based on {@link Unsafe}.
++ * <p>
++ * NOTE: This implementation is designed for Java 9. Although it should work with earlier Java releases, it is better to
++ * use {@link PreJava9ReflectionAccessor} for them.
++ */
++final class UnsafeReflectionAccessor extends ReflectionAccessor {
++
++ private final Unsafe theUnsafe = getUnsafeInstance();
++ private final Field overrideField = getOverrideField();
++
++ /**
++ * {@inheritDoc}
++ */
++ @Override
++ public void makeAccessible(AccessibleObject ao) {
++ if (theUnsafe != null && overrideField != null) {
++ long overrideOffset = theUnsafe.objectFieldOffset(overrideField);
++ theUnsafe.putBoolean(ao, overrideOffset, true);
++ }
++ }
++
++ private static Unsafe getUnsafeInstance() {
++ try {
++ Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
++ unsafeField.setAccessible(true);
++ return (Unsafe) unsafeField.get(null);
++ } catch (Exception e) {
++ e.printStackTrace();
++ return null;
++ }
++ }
++
++ private static Field getOverrideField() {
++ try {
++ return AccessibleObject.class.getDeclaredField("override");
++ } catch (NoSuchFieldException e) {
++ e.printStackTrace();
++ return null;
++ }
++ }
++}
+diff --git a/gson/src/main/java/com/google/gson/reflect/package-info.java b/gson/src/main/java/com/google/gson/reflect/package-info.java
+index e666c4311..5e43ee9fc 100644
+--- a/gson/src/main/java/com/google/gson/reflect/package-info.java
++++ b/gson/src/main/java/com/google/gson/reflect/package-info.java
+@@ -1,6 +1,6 @@
+ /**
+ * This package provides utility classes for finding type information for generic types.
+- *
++ *
+ * @author Inderjeet Singh, Joel Leitch
+ */
+ package com.google.gson.reflect;
+\ No newline at end of file
diff --git a/debian/patches/series b/debian/patches/series
new file mode 100644
index 0000000..110a611
--- /dev/null
+++ b/debian/patches/series
@@ -0,0 +1,2 @@
+java9-dateformat.patch
+java9-reflection.patch
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-java/libgoogle-gson-java.git
More information about the pkg-java-commits
mailing list