From 47dea2eefc6d2816cddb3f30689070285491733c Mon Sep 17 00:00:00 2001 From: Marcono1234 Date: Fri, 4 Feb 2022 23:19:47 +0100 Subject: [PATCH] Improve error message when abstract class cannot be constructed (#1814) --- .../gson/internal/ConstructorConstructor.java | 6 ++ .../internal/ConstructorConstructorTest.java | 59 +++++++++++++++++++ 2 files changed, 65 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 beacaaba82..489e37db07 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; @@ -99,6 +100,11 @@ public ObjectConstructor get(TypeToken typeToken) { } private ObjectConstructor newDefaultConstructor(Class rawType) { + // Cannot invoke constructor of abstract class + if (Modifier.isAbstract(rawType.getModifiers())) { + return null; + } + final Constructor constructor; try { constructor = rawType.getDeclaredConstructor(); 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..e2940b88ee --- /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, true); + ObjectConstructor constructor = constructorFactory.get(TypeToken.get(AbstractClass.class)); + try { + constructor.construct(); + fail("Expected exception"); + } catch (RuntimeException exception) { + assertEquals( + "Unable to create instance of class com.google.gson.internal.ConstructorConstructorTest$AbstractClass. " + + "Registering an InstanceCreator or a TypeAdapter for this type, or adding a no-args constructor may fix this problem.", + exception.getMessage() + ); + } + } + + @Test + public void testGet_Interface() { + ConstructorConstructor constructorFactory = new ConstructorConstructor(NO_INSTANCE_CREATORS, true); + ObjectConstructor constructor = constructorFactory.get(TypeToken.get(Interface.class)); + try { + constructor.construct(); + fail("Expected exception"); + } catch (RuntimeException exception) { + assertEquals( + "Unable to create instance of interface com.google.gson.internal.ConstructorConstructorTest$Interface. " + + "Registering an InstanceCreator or a TypeAdapter for this type, or adding a no-args constructor may fix this problem.", + exception.getMessage() + ); + } + } +}