[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