From d2ec5714fc7edccc47ed2a84d05c75f3bbb38d70 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 | 54 +++++++++++++++++++ 2 files changed, 61 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..62cd130f14 --- /dev/null +++ b/gson/src/test/java/com/google/gson/internal/ConstructorConstructorTest.java @@ -0,0 +1,54 @@ +package com.google.gson.internal; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import java.util.Collections; + +import org.junit.Test; + +import com.google.gson.reflect.TypeToken; + +public class ConstructorConstructorTest { + 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(Collections.emptyMap()); + 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(Collections.emptyMap()); + 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() + ); + } + } +}