* Fixed https://github.com/google/gson/issues/1310

Also renamed VersionUtils to more readable abstraction JavaVersion
Added support for debian naming convention
Using min supported version (6) as the default if JDK version can't be figured out

* Moved JavaVersion to an internal package
This commit is contained in:
inder123 2018-05-09 13:10:08 -07:00 committed by GitHub
parent 57085d6212
commit a6890bbaba
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 194 additions and 71 deletions

View File

@ -27,12 +27,12 @@ import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import com.google.gson.internal.JavaVersion;
import com.google.gson.internal.PreJava9DateFormatProvider; import com.google.gson.internal.PreJava9DateFormatProvider;
import com.google.gson.internal.bind.util.ISO8601Utils; import com.google.gson.internal.bind.util.ISO8601Utils;
import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken; import com.google.gson.stream.JsonToken;
import com.google.gson.stream.JsonWriter; import com.google.gson.stream.JsonWriter;
import com.google.gson.util.VersionUtils;
/** /**
* This type adapter supports three subclasses of date: Date, Timestamp, and * This type adapter supports three subclasses of date: Date, Timestamp, and
@ -59,7 +59,7 @@ final class DefaultDateTypeAdapter extends TypeAdapter<Date> {
if (!Locale.getDefault().equals(Locale.US)) { if (!Locale.getDefault().equals(Locale.US)) {
dateFormats.add(DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT)); dateFormats.add(DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT));
} }
if (VersionUtils.isJava9OrLater()) { if (JavaVersion.isJava9OrLater()) {
dateFormats.add(PreJava9DateFormatProvider.getUSDateTimeFormat(DateFormat.DEFAULT, DateFormat.DEFAULT)); dateFormats.add(PreJava9DateFormatProvider.getUSDateTimeFormat(DateFormat.DEFAULT, DateFormat.DEFAULT));
} }
} }
@ -78,7 +78,7 @@ final class DefaultDateTypeAdapter extends TypeAdapter<Date> {
if (!Locale.getDefault().equals(Locale.US)) { if (!Locale.getDefault().equals(Locale.US)) {
dateFormats.add(DateFormat.getDateInstance(style)); dateFormats.add(DateFormat.getDateInstance(style));
} }
if (VersionUtils.isJava9OrLater()) { if (JavaVersion.isJava9OrLater()) {
dateFormats.add(PreJava9DateFormatProvider.getUSDateFormat(style)); dateFormats.add(PreJava9DateFormatProvider.getUSDateFormat(style));
} }
} }
@ -93,7 +93,7 @@ final class DefaultDateTypeAdapter extends TypeAdapter<Date> {
if (!Locale.getDefault().equals(Locale.US)) { if (!Locale.getDefault().equals(Locale.US)) {
dateFormats.add(DateFormat.getDateTimeInstance(dateStyle, timeStyle)); dateFormats.add(DateFormat.getDateTimeInstance(dateStyle, timeStyle));
} }
if (VersionUtils.isJava9OrLater()) { if (JavaVersion.isJava9OrLater()) {
dateFormats.add(PreJava9DateFormatProvider.getUSDateTimeFormat(dateStyle, timeStyle)); dateFormats.add(PreJava9DateFormatProvider.getUSDateTimeFormat(dateStyle, timeStyle));
} }
} }

View File

@ -0,0 +1,90 @@
/*
* 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;
/**
* Utility to check the major Java version of the current JVM.
*/
public final class JavaVersion {
// Oracle defines naming conventions at http://www.oracle.com/technetwork/java/javase/versioning-naming-139433.html
// However, many alternate implementations differ. For example, Debian used 9-debian as the version string
private static final int majorJavaVersion = determineMajorJavaVersion();
private static int determineMajorJavaVersion() {
String javaVersion = System.getProperty("java.version");
return getMajorJavaVersion(javaVersion);
}
// Visible for testing only
static int getMajorJavaVersion(String javaVersion) {
int version = parseDotted(javaVersion);
if (version == -1) {
version = extractBeginningInt(javaVersion);
}
if (version == -1) {
return 6; // Choose minimum supported JDK version as default
}
return version;
}
// Parses both legacy 1.8 style and newer 9.0.4 style
private static int parseDotted(String javaVersion) {
try {
String[] parts = javaVersion.split("[._]");
int firstVer = Integer.parseInt(parts[0]);
if (firstVer == 1 && parts.length > 1) {
return Integer.parseInt(parts[1]);
} else {
return firstVer;
}
} catch (NumberFormatException e) {
return -1;
}
}
private static int extractBeginningInt(String javaVersion) {
try {
StringBuilder num = new StringBuilder();
for (int i = 0; i < javaVersion.length(); ++i) {
char c = javaVersion.charAt(i);
if (Character.isDigit(c)) {
num.append(c);
} else {
break;
}
}
return Integer.parseInt(num.toString());
} catch (NumberFormatException e) {
return -1;
}
}
/**
* @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;
}
}

View File

@ -20,13 +20,13 @@ import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException; import com.google.gson.JsonSyntaxException;
import com.google.gson.TypeAdapter; import com.google.gson.TypeAdapter;
import com.google.gson.TypeAdapterFactory; import com.google.gson.TypeAdapterFactory;
import com.google.gson.internal.JavaVersion;
import com.google.gson.internal.PreJava9DateFormatProvider; import com.google.gson.internal.PreJava9DateFormatProvider;
import com.google.gson.internal.bind.util.ISO8601Utils; import com.google.gson.internal.bind.util.ISO8601Utils;
import com.google.gson.reflect.TypeToken; import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken; import com.google.gson.stream.JsonToken;
import com.google.gson.stream.JsonWriter; import com.google.gson.stream.JsonWriter;
import com.google.gson.util.VersionUtils;
import java.io.IOException; import java.io.IOException;
import java.text.DateFormat; import java.text.DateFormat;
@ -62,7 +62,7 @@ public final class DateTypeAdapter extends TypeAdapter<Date> {
if (!Locale.getDefault().equals(Locale.US)) { if (!Locale.getDefault().equals(Locale.US)) {
dateFormats.add(DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT)); dateFormats.add(DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT));
} }
if (VersionUtils.isJava9OrLater()) { if (JavaVersion.isJava9OrLater()) {
dateFormats.add(PreJava9DateFormatProvider.getUSDateTimeFormat(DateFormat.DEFAULT, DateFormat.DEFAULT)); dateFormats.add(PreJava9DateFormatProvider.getUSDateTimeFormat(DateFormat.DEFAULT, DateFormat.DEFAULT));
} }
} }

View File

@ -15,10 +15,10 @@
*/ */
package com.google.gson.internal.reflect; package com.google.gson.internal.reflect;
import com.google.gson.util.VersionUtils;
import java.lang.reflect.AccessibleObject; import java.lang.reflect.AccessibleObject;
import com.google.gson.internal.JavaVersion;
/** /**
* Provides a replacement for {@link AccessibleObject#setAccessible(boolean)}, which may be used to * 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} * avoid reflective access issues appeared in Java 9, like {@link java.lang.reflect.InaccessibleObjectException}
@ -33,7 +33,7 @@ import java.lang.reflect.AccessibleObject;
public abstract class ReflectionAccessor { public abstract class ReflectionAccessor {
// the singleton instance, use getInstance() to obtain // the singleton instance, use getInstance() to obtain
private static final ReflectionAccessor instance = VersionUtils.getMajorJavaVersion() < 9 ? new PreJava9ReflectionAccessor() : new UnsafeReflectionAccessor(); private static final ReflectionAccessor instance = JavaVersion.getMajorJavaVersion() < 9 ? new PreJava9ReflectionAccessor() : new UnsafeReflectionAccessor();
/** /**
* Does the same as {@code ao.setAccessible(true)}, but never throws * Does the same as {@code ao.setAccessible(true)}, but never throws

View File

@ -1,49 +0,0 @@
/*
* 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;
}
}

View File

@ -23,7 +23,8 @@ import java.util.Date;
import java.util.Locale; import java.util.Locale;
import java.util.TimeZone; import java.util.TimeZone;
import com.google.gson.util.VersionUtils; import com.google.gson.internal.JavaVersion;
import junit.framework.TestCase; import junit.framework.TestCase;
/** /**
@ -47,9 +48,9 @@ public class DefaultDateTypeAdapterTest extends TestCase {
Locale defaultLocale = Locale.getDefault(); Locale defaultLocale = Locale.getDefault();
Locale.setDefault(locale); Locale.setDefault(locale);
try { try {
String afterYearSep = VersionUtils.isJava9OrLater() ? ", " : " "; String afterYearSep = JavaVersion.isJava9OrLater() ? ", " : " ";
String afterYearLongSep = VersionUtils.isJava9OrLater() ? " at " : " "; String afterYearLongSep = JavaVersion.isJava9OrLater() ? " at " : " ";
String utcFull = VersionUtils.isJava9OrLater() ? "Coordinated Universal Time" : "UTC"; String utcFull = JavaVersion.isJava9OrLater() ? "Coordinated Universal Time" : "UTC";
assertFormatted(String.format("Jan 1, 1970%s12:00:00 AM", afterYearSep), assertFormatted(String.format("Jan 1, 1970%s12:00:00 AM", afterYearSep),
new DefaultDateTypeAdapter(Date.class)); new DefaultDateTypeAdapter(Date.class));
assertFormatted("1/1/70", new DefaultDateTypeAdapter(Date.class, DateFormat.SHORT)); assertFormatted("1/1/70", new DefaultDateTypeAdapter(Date.class, DateFormat.SHORT));
@ -75,7 +76,7 @@ public class DefaultDateTypeAdapterTest extends TestCase {
Locale defaultLocale = Locale.getDefault(); Locale defaultLocale = Locale.getDefault();
Locale.setDefault(Locale.FRANCE); Locale.setDefault(Locale.FRANCE);
try { try {
String afterYearSep = VersionUtils.isJava9OrLater() ? " à " : " "; String afterYearSep = JavaVersion.isJava9OrLater() ? " à " : " ";
assertParsed(String.format("1 janv. 1970%s00:00:00", afterYearSep), assertParsed(String.format("1 janv. 1970%s00:00:00", afterYearSep),
new DefaultDateTypeAdapter(Date.class)); new DefaultDateTypeAdapter(Date.class));
assertParsed("01/01/70", new DefaultDateTypeAdapter(Date.class, DateFormat.SHORT)); assertParsed("01/01/70", new DefaultDateTypeAdapter(Date.class, DateFormat.SHORT));
@ -87,7 +88,7 @@ public class DefaultDateTypeAdapterTest extends TestCase {
new DefaultDateTypeAdapter(DateFormat.MEDIUM, DateFormat.MEDIUM)); new DefaultDateTypeAdapter(DateFormat.MEDIUM, DateFormat.MEDIUM));
assertParsed(String.format("1 janvier 1970%s00:00:00 UTC", afterYearSep), assertParsed(String.format("1 janvier 1970%s00:00:00 UTC", afterYearSep),
new DefaultDateTypeAdapter(DateFormat.LONG, DateFormat.LONG)); new DefaultDateTypeAdapter(DateFormat.LONG, DateFormat.LONG));
assertParsed(VersionUtils.isJava9OrLater() ? assertParsed(JavaVersion.isJava9OrLater() ?
"jeudi 1 janvier 1970 à 00:00:00 Coordinated Universal Time" : "jeudi 1 janvier 1970 à 00:00:00 Coordinated Universal Time" :
"jeudi 1 janvier 1970 00 h 00 UTC", "jeudi 1 janvier 1970 00 h 00 UTC",
new DefaultDateTypeAdapter(DateFormat.FULL, DateFormat.FULL)); new DefaultDateTypeAdapter(DateFormat.FULL, DateFormat.FULL));
@ -127,7 +128,7 @@ public class DefaultDateTypeAdapterTest extends TestCase {
Locale defaultLocale = Locale.getDefault(); Locale defaultLocale = Locale.getDefault();
Locale.setDefault(Locale.US); Locale.setDefault(Locale.US);
try { try {
String afterYearSep = VersionUtils.isJava9OrLater() ? ", " : " "; String afterYearSep = JavaVersion.isJava9OrLater() ? ", " : " ";
assertFormatted(String.format("Dec 31, 1969%s4:00:00 PM", afterYearSep), assertFormatted(String.format("Dec 31, 1969%s4:00:00 PM", afterYearSep),
new DefaultDateTypeAdapter(Date.class)); new DefaultDateTypeAdapter(Date.class));
assertParsed("Dec 31, 1969 4:00:00 PM", new DefaultDateTypeAdapter(Date.class)); assertParsed("Dec 31, 1969 4:00:00 PM", new DefaultDateTypeAdapter(Date.class));

View File

@ -27,6 +27,7 @@ import com.google.gson.JsonParseException;
import com.google.gson.JsonPrimitive; import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSyntaxException; import com.google.gson.JsonSyntaxException;
import com.google.gson.TypeAdapter; import com.google.gson.TypeAdapter;
import com.google.gson.internal.JavaVersion;
import com.google.gson.reflect.TypeToken; import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter; import com.google.gson.stream.JsonWriter;
@ -56,7 +57,6 @@ import java.util.TimeZone;
import java.util.TreeSet; import java.util.TreeSet;
import java.util.UUID; import java.util.UUID;
import com.google.gson.util.VersionUtils;
import junit.framework.TestCase; import junit.framework.TestCase;
/** /**
@ -330,7 +330,7 @@ public class DefaultTypeAdaptersTest extends TestCase {
public void testDefaultDateSerialization() { public void testDefaultDateSerialization() {
Date now = new Date(1315806903103L); Date now = new Date(1315806903103L);
String json = gson.toJson(now); String json = gson.toJson(now);
if (VersionUtils.isJava9OrLater()) { if (JavaVersion.isJava9OrLater()) {
assertEquals("\"Sep 11, 2011, 10:55:03 PM\"", json); assertEquals("\"Sep 11, 2011, 10:55:03 PM\"", json);
} else { } else {
assertEquals("\"Sep 11, 2011 10:55:03 PM\"", json); assertEquals("\"Sep 11, 2011 10:55:03 PM\"", json);
@ -375,7 +375,7 @@ public class DefaultTypeAdaptersTest extends TestCase {
public void testDefaultJavaSqlTimestampSerialization() { public void testDefaultJavaSqlTimestampSerialization() {
Timestamp now = new java.sql.Timestamp(1259875082000L); Timestamp now = new java.sql.Timestamp(1259875082000L);
String json = gson.toJson(now); String json = gson.toJson(now);
if (VersionUtils.isJava9OrLater()) { if (JavaVersion.isJava9OrLater()) {
assertEquals("\"Dec 3, 2009, 1:18:02 PM\"", json); assertEquals("\"Dec 3, 2009, 1:18:02 PM\"", json);
} else { } else {
assertEquals("\"Dec 3, 2009 1:18:02 PM\"", json); assertEquals("\"Dec 3, 2009 1:18:02 PM\"", json);
@ -405,7 +405,7 @@ public class DefaultTypeAdaptersTest extends TestCase {
Gson gson = new GsonBuilder().create(); Gson gson = new GsonBuilder().create();
Date now = new Date(1315806903103L); Date now = new Date(1315806903103L);
String json = gson.toJson(now); String json = gson.toJson(now);
if (VersionUtils.isJava9OrLater()) { if (JavaVersion.isJava9OrLater()) {
assertEquals("\"Sep 11, 2011, 10:55:03 PM\"", json); assertEquals("\"Sep 11, 2011, 10:55:03 PM\"", json);
} else { } else {
assertEquals("\"Sep 11, 2011 10:55:03 PM\"", json); assertEquals("\"Sep 11, 2011 10:55:03 PM\"", json);

View File

@ -33,6 +33,7 @@ import com.google.gson.common.TestTypes.ClassWithObjects;
import com.google.gson.common.TestTypes.ClassWithTransientFields; import com.google.gson.common.TestTypes.ClassWithTransientFields;
import com.google.gson.common.TestTypes.Nested; import com.google.gson.common.TestTypes.Nested;
import com.google.gson.common.TestTypes.PrimitiveArray; import com.google.gson.common.TestTypes.PrimitiveArray;
import com.google.gson.internal.JavaVersion;
import com.google.gson.reflect.TypeToken; import com.google.gson.reflect.TypeToken;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.util.ArrayList; import java.util.ArrayList;
@ -44,7 +45,6 @@ import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.TimeZone; import java.util.TimeZone;
import com.google.gson.util.VersionUtils;
import junit.framework.TestCase; import junit.framework.TestCase;
/** /**
@ -484,7 +484,7 @@ public class ObjectTest extends TestCase {
public void testDateAsMapObjectField() { public void testDateAsMapObjectField() {
HasObjectMap a = new HasObjectMap(); HasObjectMap a = new HasObjectMap();
a.map.put("date", new Date(0)); a.map.put("date", new Date(0));
if (VersionUtils.isJava9OrLater()) { if (JavaVersion.isJava9OrLater()) {
assertEquals("{\"map\":{\"date\":\"Dec 31, 1969, 4:00:00 PM\"}}", gson.toJson(a)); assertEquals("{\"map\":{\"date\":\"Dec 31, 1969, 4:00:00 PM\"}}", gson.toJson(a));
} else { } else {
assertEquals("{\"map\":{\"date\":\"Dec 31, 1969 4:00:00 PM\"}}", gson.toJson(a)); assertEquals("{\"map\":{\"date\":\"Dec 31, 1969 4:00:00 PM\"}}", gson.toJson(a));

View File

@ -0,0 +1,81 @@
/*
* 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 static org.junit.Assert.*;
import org.junit.Test;
import com.google.gson.internal.JavaVersion;
/**
* Unit and functional tests for {@link JavaVersion}
*
* @author Inderjeet Singh
*/
public class JavaVersionTest {
// Borrowed some of test strings from https://github.com/prestodb/presto/blob/master/presto-main/src/test/java/com/facebook/presto/server/TestJavaVersion.java
@Test
public void testGetMajorJavaVersion() {
JavaVersion.getMajorJavaVersion();
}
@Test
public void testJava6() {
assertEquals(6, JavaVersion.getMajorJavaVersion("1.6.0")); // http://www.oracle.com/technetwork/java/javase/version-6-141920.html
}
@Test
public void testJava7() {
assertEquals(7, JavaVersion.getMajorJavaVersion("1.7.0")); // http://www.oracle.com/technetwork/java/javase/jdk7-naming-418744.html
}
@Test
public void testJava8() {
assertEquals(8, JavaVersion.getMajorJavaVersion("1.8"));
assertEquals(8, JavaVersion.getMajorJavaVersion("1.8.0"));
assertEquals(8, JavaVersion.getMajorJavaVersion("1.8.0_131"));
assertEquals(8, JavaVersion.getMajorJavaVersion("1.8.0_60-ea"));
assertEquals(8, JavaVersion.getMajorJavaVersion("1.8.0_111-internal"));
// openjdk8 per https://github.com/AdoptOpenJDK/openjdk-build/issues/93
assertEquals(8, JavaVersion.getMajorJavaVersion("1.8.0-internal"));
assertEquals(8, JavaVersion.getMajorJavaVersion("1.8.0_131-adoptopenjdk"));
}
@Test
public void testJava9() {
// Legacy style
assertEquals(9, JavaVersion.getMajorJavaVersion("9.0.4")); // Oracle JDK 9
assertEquals(9, JavaVersion.getMajorJavaVersion("9-Debian")); // Debian as reported in https://github.com/google/gson/issues/1310
// New style
assertEquals(9, JavaVersion.getMajorJavaVersion("9-ea+19"));
assertEquals(9, JavaVersion.getMajorJavaVersion("9+100"));
assertEquals(9, JavaVersion.getMajorJavaVersion("9.0.1+20"));
assertEquals(9, JavaVersion.getMajorJavaVersion("9.1.1+20"));
}
@Test
public void testJava10() {
assertEquals(10, JavaVersion.getMajorJavaVersion("10.0.1")); // Oracle JDK 10.0.1
}
@Test
public void testUnknownVersionFormat() {
assertEquals(6, JavaVersion.getMajorJavaVersion("Java9")); // unknown format
}
}