Skip to content

JsonCreator factory method is ignored  #660

@iovesnov

Description

@iovesnov

I am using Jackson version 2.4.4

Below two classes Test1 and Test2. Both classes has private constructor and JsonCreator method which accepts the single parameter. In case of Test1 class that parameter has 'double' type and Object in Test2 class.
I've added the code which converts JSON string into the Test1 and Test2 classes and as the result different methods are invoked. For the Test1 class invoked only constructor but for the Test2 factory method is invoked.

Code:

public static void main(String []args) throws IOException {
    ObjectMapper objectMapper = new ObjectMapper();
    String json = objectMapper.writeValueAsString(-0.5);
    objectMapper.readValue(json, Test1.class);
    System.out.println("-----------------");
    objectMapper.readValue(json, Test2.class);
}

class Test1 {
    private final double n;

    private Test1(double n) {
        this.n = n;
    }

    @JsonCreator
    public static Test1 factory(double n) {
        return new Test1(n);
    }
}

class Test2 {
    private final Data n;

    private Test2(Data n) {
        this.n = n;
    }

    @JsonCreator
    public static Test2 checked(Data n) {
        return new Test2(n);
    }
}

Output:

Test 1. Constructor.
-----------------
Test 2. JsonCreator.
Test 2. Constructor.

I debugged the Jackson a little bit and found that different types are treated differently: BasicDeserializerFactory#_handleSingleArgumentConstructor:

    if (type == String.class) {
        if (isCreator || isVisible) {
            creators.addStringCreator(ctor);
        }
        return true;
    }
    if (type == int.class || type == Integer.class) {
        if (isCreator || isVisible) {
            creators.addIntCreator(ctor);
        }
        return true;
    }
    if (type == long.class || type == Long.class) {
        if (isCreator || isVisible) {
            creators.addLongCreator(ctor);
        }
        return true;
    }
    if (type == double.class || type == Double.class) {
        if (isCreator || isVisible) {
            creators.addDoubleCreator(ctor);
        }
        return true;
    }
    if (type == boolean.class || type == Boolean.class) {
        if (isCreator || isVisible) {
            creators.addBooleanCreator(ctor);
        }
        return true;
    }
    // Delegating Creator ok iff it has @JsonCreator (etc)
    if (isCreator) {
        creators.addDelegatingCreator(ctor, null);
        return true;
    }
    return false;

As you can see all Java types has a check isCreator || isVisible but not for the Object or custom class. This is really makes the difference because of the constructor with some Java types (like double or String) will override the factory method...

I personally think that Jackson should work the same independently to the object type.
It is you call but I would also say that factory method annotated with JsonCreator annotation should has higher priority then constructor.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions