From 2bc8b693b89d31fd59e29c8db9f667b786e59907 Mon Sep 17 00:00:00 2001 From: Marcono1234 Date: Thu, 5 Nov 2020 15:25:59 +0100 Subject: [PATCH] Improve error message when abstract class cannot be constructed --- .../gson/internal/ConstructorConstructor.java | 7 +++ .../internal/ConstructorConstructorTest.java | 59 +++++++++++++++++++ 2 files changed, 66 insertions(+) create mode 100644 gson/src/test/java/com/google/gson/internal/ConstructorConstructorTest.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 5fab460105..860d3af053 100644 --- a/gson/src/main/java/com/google/gson/internal/ConstructorConstructor.java +++ b/gson/src/main/java/com/google/gson/internal/ConstructorConstructor.java @@ -18,6 +18,7 @@ import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Modifier; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.ArrayDeque; @@ -97,6 +98,11 @@ public ObjectConstructor get(TypeToken typeToken) { } private ObjectConstructor newDefaultConstructor(Class rawType) { + // Cannot invoke constructor of abstract class + if (Modifier.isAbstract(rawType.getModifiers())) { + return null; + } + try { final Constructor constructor = rawType.getDeclaredConstructor(); if (!constructor.isAccessible()) { @@ -225,6 +231,7 @@ private ObjectConstructor newUnsafeAllocator( Object newInstance = unsafeAllocator.newInstance(rawType); return (T) newInstance; } catch (Exception e) { + // TODO: JsonParseException ? throw new RuntimeException(("Unable to invoke no-args constructor for " + type + ". " + "Registering an InstanceCreator with Gson for this type may fix this problem."), e); } diff --git a/gson/src/test/java/com/google/gson/internal/ConstructorConstructorTest.java b/gson/src/test/java/com/google/gson/internal/ConstructorConstructorTest.java new file mode 100644 index 0000000000..ca5974bb8c --- /dev/null +++ b/gson/src/test/java/com/google/gson/internal/ConstructorConstructorTest.java @@ -0,0 +1,59 @@ +package com.google.gson.internal; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import java.lang.reflect.Type; +import java.util.Collections; +import java.util.Map; + +import org.junit.Test; + +import com.google.gson.InstanceCreator; +import com.google.gson.reflect.TypeToken; + +public class ConstructorConstructorTest { + private static final Map> NO_INSTANCE_CREATORS = Collections.emptyMap(); + + private abstract static class AbstractClass { + @SuppressWarnings("unused") + public AbstractClass() { } + } + private interface Interface { } + + /** + * Verify that ConstructorConstructor does not try to invoke no-arg constructor + * of abstract class. + */ + @Test + public void testGet_AbstractClassNoArgConstructor() { + ConstructorConstructor constructorFactory = new ConstructorConstructor(NO_INSTANCE_CREATORS); + ObjectConstructor constructor = constructorFactory.get(TypeToken.get(AbstractClass.class)); + try { + constructor.construct(); + fail("Expected exception"); + } catch (RuntimeException exception) { + assertEquals( + "Unable to invoke no-args constructor for " + AbstractClass.class + + ". Registering an InstanceCreator with Gson for this type may fix this problem.", + exception.getMessage() + ); + } + } + + @Test + public void testGet_Interface() { + ConstructorConstructor constructorFactory = new ConstructorConstructor(NO_INSTANCE_CREATORS); + ObjectConstructor constructor = constructorFactory.get(TypeToken.get(Interface.class)); + try { + constructor.construct(); + fail("Expected exception"); + } catch (RuntimeException exception) { + assertEquals( + "Unable to invoke no-args constructor for " + Interface.class + + ". Registering an InstanceCreator with Gson for this type may fix this problem.", + exception.getMessage() + ); + } + } +}