From eea2981fac51bcb371e4f862855074b8b03aa26e Mon Sep 17 00:00:00 2001 From: Jesse Wilson Date: Sat, 26 Oct 2019 22:02:49 -0400 Subject: [PATCH] Go back to using Unsafe APIs to create instances without constructors. The attempted fix replaced a warning with a crash. I believe that a warning is a better developer experience than a crash. This reverts commit c0639316b108ea4ba98d7c74187de4078858c660. --- .../java/com/squareup/moshi/ClassFactory.java | 63 +++++++------------ 1 file changed, 22 insertions(+), 41 deletions(-) diff --git a/moshi/src/main/java/com/squareup/moshi/ClassFactory.java b/moshi/src/main/java/com/squareup/moshi/ClassFactory.java index 87d21ae..b332039 100644 --- a/moshi/src/main/java/com/squareup/moshi/ClassFactory.java +++ b/moshi/src/main/java/com/squareup/moshi/ClassFactory.java @@ -34,9 +34,6 @@ abstract class ClassFactory { abstract T newInstance() throws InvocationTargetException, IllegalAccessException, InstantiationException; - private static volatile boolean androidChecked = false; - private static volatile boolean tryUnsafe = true; - public static ClassFactory get(final Class rawType) { // Try to find a no-args constructor. May be any visibility including private. try { @@ -57,45 +54,29 @@ abstract class ClassFactory { // No no-args constructor. Fall back to something more magical... } - if (!androidChecked) { - try { - Class androidBuildClass = Class.forName("android.os.Build$VERSION"); - Field sdkIntField = androidBuildClass.getDeclaredField("SDK_INT"); - int sdk = (int) sdkIntField.get(null); - if (sdk >= 29) { - tryUnsafe = false; + // Try the JVM's Unsafe mechanism. + // public class Unsafe { + // public Object allocateInstance(Class type); + // } + try { + Class unsafeClass = Class.forName("sun.misc.Unsafe"); + Field f = unsafeClass.getDeclaredField("theUnsafe"); + f.setAccessible(true); + final Object unsafe = f.get(null); + final Method allocateInstance = unsafeClass.getMethod("allocateInstance", Class.class); + return new ClassFactory() { + @SuppressWarnings("unchecked") + @Override public T newInstance() throws InvocationTargetException, IllegalAccessException { + return (T) allocateInstance.invoke(unsafe, rawType); } - } catch (Exception ignored) { - } finally { - androidChecked = true; - } - } - if (tryUnsafe) { - // Try the JVM's Unsafe mechanism. - // public class Unsafe { - // public Object allocateInstance(Class type); - // } - try { - Class unsafeClass = Class.forName("sun.misc.Unsafe"); - Field f = unsafeClass.getDeclaredField("theUnsafe"); - f.setAccessible(true); - final Object unsafe = f.get(null); - final Method allocateInstance = unsafeClass.getMethod("allocateInstance", Class.class); - return new ClassFactory() { - @SuppressWarnings("unchecked") - @Override - public T newInstance() throws InvocationTargetException, IllegalAccessException { - return (T) allocateInstance.invoke(unsafe, rawType); - } - @Override public String toString() { - return rawType.getName(); - } - }; - } catch (IllegalAccessException e) { - throw new AssertionError(); - } catch (ClassNotFoundException | NoSuchMethodException | NoSuchFieldException ignored) { - // Not the expected version of the Oracle Java library! - } + @Override public String toString() { + return rawType.getName(); + } + }; + } catch (IllegalAccessException e) { + throw new AssertionError(); + } catch (ClassNotFoundException | NoSuchMethodException | NoSuchFieldException ignored) { + // Not the expected version of the Oracle Java library! } // Try (post-Gingerbread) Dalvik/libcore's ObjectStreamClass mechanism.