Skip to content

If there is a no-parameter constructor marked as JsonCreator and a constructor reported as DefaultCreator, latter is incorrectly used. #5045

@k163377

Description

@k163377

Search before asking

  • I searched in the issues and found nothing similar.

Describe the bug

If both JsonCreator and DefaultCreator are reported, the JsonCreator should take precedence.
On the other hand, in certain cases, the DefaultCreator may take precedence.

This issue is a Javaized version of the following
FasterXML/jackson-module-kotlin#932
#5040

Version Information

  • 2.19.0-SNAPSHOT
  • Probably the same for 2.18.3.

Reproduction

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.cfg.MapperConfig;
import com.fasterxml.jackson.databind.introspect.AnnotatedClass;
import com.fasterxml.jackson.databind.introspect.NopAnnotationIntrospector;
import com.fasterxml.jackson.databind.introspect.PotentialCreator;
import com.fasterxml.jackson.databind.json.JsonMapper;
import org.junit.jupiter.api.Test;

import java.util.List;

public class Kotlin932Java {
    static class User {
        private final int age;

        public User(int age) { this.age = age; }

        @JsonCreator
        public User() { this(0); }

        public int getAge() { return age; }
    }

    static class AI extends NopAnnotationIntrospector {
        @Override
        public PotentialCreator findDefaultCreator(MapperConfig<?> config,
                                                   AnnotatedClass valueClass,
                                                   List<PotentialCreator> declaredConstructors,
                                                   List<PotentialCreator> declaredFactories) {
            if (valueClass.getRawType() != User.class) return null;

            return declaredConstructors.stream()
                    .filter(it -> it.paramCount() != 0)
                    .findFirst()
                    .orElse(null);
        }
    }

    @Test
    public void kotlin932() throws JsonProcessingException {
        ObjectMapper mapper = JsonMapper.builder().annotationIntrospector(new AI()).build();
        String json =
                "{\n" +
                "  \"age\": 25\n" +
                "}";

        User user = mapper.readValue(json, User.class);

        System.out.println(user);
    }
}

Expected behavior

Deserialization should succeed, but in fact has no property name ... is reported.

Additional context

The full stack trace when run on the 2.19 branch of kotlin-module.

com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Invalid type definition for type `com.fasterxml.jackson.module.kotlin.test.github.Kotlin932Java$User`: Argument #0 of Creator [constructor for `com.fasterxml.jackson.module.kotlin.test.github.Kotlin932Java$User` (1 arg), annotations: [null] has no property name (and is not Injectable): can not use as property-based Creator
 at [Source: REDACTED (`StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION` disabled); line: 1, column: 1]

	at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:62)
	at com.fasterxml.jackson.databind.DeserializationContext.reportBadTypeDefinition(DeserializationContext.java:1893)
	at com.fasterxml.jackson.databind.deser.BasicDeserializerFactory._addSelectedPropertiesBasedCreator(BasicDeserializerFactory.java:535)
	at com.fasterxml.jackson.databind.deser.BasicDeserializerFactory._constructDefaultValueInstantiator(BasicDeserializerFactory.java:259)
	at com.fasterxml.jackson.databind.deser.BasicDeserializerFactory.findValueInstantiator(BasicDeserializerFactory.java:209)
	at com.fasterxml.jackson.databind.deser.BeanDeserializerFactory.buildBeanDeserializer(BeanDeserializerFactory.java:263)
	at com.fasterxml.jackson.databind.deser.BeanDeserializerFactory.createBeanDeserializer(BeanDeserializerFactory.java:152)
	at com.fasterxml.jackson.databind.deser.DeserializerCache._createDeserializer2(DeserializerCache.java:472)
	at com.fasterxml.jackson.databind.deser.DeserializerCache._createDeserializer(DeserializerCache.java:416)
	at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCache2(DeserializerCache.java:318)
	at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCacheValueDeserializer(DeserializerCache.java:285)
	at com.fasterxml.jackson.databind.deser.DeserializerCache.findValueDeserializer(DeserializerCache.java:175)
	at com.fasterxml.jackson.databind.DeserializationContext.findRootValueDeserializer(DeserializationContext.java:669)
	at com.fasterxml.jackson.databind.ObjectMapper._findRootDeserializer(ObjectMapper.java:5102)
	at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4972)
	at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3887)
	at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3855)
	at com.fasterxml.jackson.module.kotlin.test.github.Kotlin932Java.kotlin932(Kotlin932Java.java:50)
	at java.base/java.lang.reflect.Method.invoke(Method.java:569)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions