58

Gson user guide states that we should define default no-args constructor for any class to work with Gson properly. Even more, in the javadoc on Gson's InstanceCreator class said that exception will be thrown if we try to deserialize instance of class missing default constructor and we should use InstanceCreator in such cases. However, I've tried to test use Gson with class lacking default constructor and both serialization and deserialization work without any trouble.

Here is the piece of code for deserializaiton. A class without non-args constructor:

public class Mushroom {
    private String name;
    private double diameter;

    public Mushroom(String name, double diameter) {
        this.name = name;
        this.diameter = diameter;
    }

    //equals(), hashCode(), etc.
}

and a test:

@Test
public void deserializeMushroom() {
    assertEquals(
            new Mushroom("Fly agaric", 4.0),
            new Gson().fromJson(
                    "{name:\"Fly agaric\", diameter:4.0}", Mushroom.class));
}

which works fine.

So my question is: could I actually use Gson without need to have default constructor or there is any circumstances when it will not work?

raindev
  • 1,017
  • 1
  • 12
  • 25

3 Answers3

104

As of Gson 2.3.1.

Regardless of what the Gson documentation says, if your class doesn't have an no-args constructor and you have not registered any InstanceCreater objects, then it will create an ObjectConstructor (which constructs your Object) with an UnsafeAllocator which uses Reflection to get the allocateInstance method of the class sun.misc.Unsafe to create your class' instance.

This Unsafe class goes around the lack of no-args constructor and has many other dangerous uses. allocateInstance states

Allocate an instance but do not run any constructor. Initializes the class if it has not yet been.

So it doesn't actually need a constructor and will go around your two argument constructor. See some examples here.

If you do have a no-args constructor, Gson will use an ObjectConstructor which uses that default Constructor by calling

yourClassType.getDeclaredConstructor(); // ie. empty, no-args

My 2 cents: Follow what Gson says and create your classes with a no-arg constructor or register an InstanceCreator. You might find yourself in a bad position using Unsafe.

Community
  • 1
  • 1
Sotirios Delimanolis
  • 274,122
  • 60
  • 696
  • 724
  • 1
    @thomas.mc.work Gson will be able to set the field directly through reflection (and potentially some unsafe work) and you can retrieve it through a getter (or directly through the field. I don't recommend this design. – Sotirios Delimanolis Mar 20 '15 at 14:40
  • 3
    According to [https://sites.google.com/site/gson/gson-user-guide#TOC-Using-Gson](https://sites.google.com/site/gson/gson-user-guide#TOC-Using-Gson) you can use a private constructor which will prevent the use of unsafe. From what I've tested, when I've used a private constructor GSON used the following method: com.google.gson.internal.newDefaultConstructor When I removed the private constructor GSON used the following method: com.google.gson.internal.newUnsafeAllocator – Tzach Solomon Sep 13 '16 at 14:03
  • Having a no-argument constructor means that now you can have uninitialized objects loose in your code, which is a great way to kneecap the compiler's ability to detect errors and to get `NullPointerExceptions`. Unless Gson is actually warning you that bad things might happen if you don't have a no-argument constructor, I see no reason to implement it. – user986730 Sep 07 '19 at 09:45
  • 1
    @user986730 actually it's the other way around: without a no-args constructor, the compiler would believe fields are always in a neat state because it assumes normal instantiation will take place (field initializers are run, one of the declared constructors was called). Then, reality will hit you with impossible NPEs because unsafe instantiation is what actually happened when you were not looking. – Paulo Dec 31 '19 at 17:01
  • 1
    In Gson 2.9.0 the method [`GsonBuilder.disableJdkUnsafe()`](https://javadoc.io/doc/com.google.code.gson/gson/latest/com.google.gson/com/google/gson/GsonBuilder.html#disableJdkUnsafe()) was added to prevent you from accidentally relying on usage of `Unsafe`, which might not be portable or can cause bugs which are difficult to track down. – Marcono1234 Jun 27 '22 at 10:29
0

There is a good solution in the Jackson library as described here:

https://stackoverflow.com/a/11838468/2854723

The point is to tell the serializer via the Mix-Ins feature which JSON fields to use when using the constructor with arguments.

If that entity is part of an external library then you can "remote annotate" with the Creator feature.

turbanoff
  • 2,439
  • 6
  • 42
  • 99
thomas.mc.work
  • 6,404
  • 2
  • 26
  • 41
-1

For the example of raindev, its OK because you have all value in your JSON, so they will overwrite every variable even they did not init. But in many case there may have some Transient field, or optional field which don't have value in the JSON. Then if you don't have a no-args constructor the field will remain null and NPE when someone try to read it.

Eric Chan
  • 49
  • 3