FasterXML / FasterXML/jackson-databind

Jackson3 Deserialization with Properties Based constructor fails with tools.jackson.databind.exc.InvalidDefinitionException

Open
#5,593 19 comments 0 reactions 0 assignees View on GitHub
need-test-case
Dominant language
Java
Stars
3.7k
Forks
1.5k
Avg merge
3d 6h
Merged PRs (30d)
28

Description

### Search before asking

- [x] I searched in the [issues](https://github.com/FasterXML/jackson-databind/issues) and found nothing similar.

### Describe the bug

Deserialization fails with InvalidDefinitionException: Cannot construct instance of `AuditEvent` (no Creators, like default constructor, exist): cannot deserialize from Object value (no delegate- or property-based Creator)

### Version Information

3.0.3

### Reproduction

The Test attempts to serialize and deserialize the AuditEvent class described below but fails on Deserialization with:
`tools.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `AuditEvent` (no Creators, like default constructor, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
at [Source: (String)"{"timestamp":"2026-01-17T21:00:44.532975Z","principal":"user","type":"type","data":{"keyA":"ValueA","KeyB":"ValueB"}}"; line: 1, column: 2]

at tools.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:70)
at tools.jackson.databind.DeserializationContext.reportBadDefinition(DeserializationContext.java:1950)
at tools.jackson.databind.DatabindContext.reportBadDefinition(DatabindContext.java:448)
at tools.jackson.databind.DeserializationContext.handleMissingInstantiator(DeserializationContext.java:1480)
at tools.jackson.databind.deser.bean.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1432)
at tools.jackson.databind.deser.bean.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:480)
at tools.jackson.databind.deser.bean.BeanDeserializer.deserialize(BeanDeserializer.java:200)
at tools.jackson.databind.deser.DeserializationContextExt.readRootValue(DeserializationContextExt.java:265)`

Class for Serialization/Deserialization tests:

```java
/**
* Copied from Spring Boot 4.0.0 for testing purposes.
* {@link org.springframework.boot.actuate.audit.AuditEvent}
* Simplified version for Jackson3 Deserializer issues.
*/
public class AuditEvent implements Serializable {

private final Instant timestamp;
private final String principal;
private final String type;
private final Map data;

/**
* Create a new audit event for the current time from data provided as name-value
* pairs.
* @param principal the user principal responsible
* @param type the event type
* @param data the event data in the form 'key=value' or simply 'key'
*/
public AuditEvent(@Nullable String principal, String type, String... data) {
this(Instant.now(), principal, type, convert(data));
}

/**
* Create a new audit event.
* @param timestamp the date/time of the event
* @param principal the user principal responsible
* @param type the event type
* @param data the event data
*/
public AuditEvent(Instant timestamp, @Nullable String principal, String type, Map data) {
Assert.notNull(timestamp, "'timestamp' must not be null");
Assert.notNull(type, "'type' must not be null");
this.timestamp = timestamp;
this.principal = (principal != null) ? principal : "";
this.type = type;
this.data = Collections.unmodifiableMap(data);
}

private static Map convert(String[] data) {
Map result = new HashMap<>();
for (String entry : data) {
int index = entry.indexOf('=');
if (index != -1) {
result.put(entry.substring(0, index), entry.substring(index + 1));
}
else {
result.put(entry, null);
}
}
return result;
}
............................
```

The Test:

```java
@ActiveProfiles("test")
@SpringJUnitConfig({JacksonConfig.class})
@WebMvcTest
public class AuditEventDeserializeMvcItVal {

@Autowired
private JsonMapper jsonMapper;

private AuditEvent startAuditEvent;
private String startAuditEventJson;
private String startAuditEventString;

private JsonMapper jsonMapperManual;

@BeforeEach
void serialize(){

startAuditEvent = new AuditEvent("user", "type", "keyA=ValueA","KeyB=ValueB");
startAuditEventJson = jsonMapper.writeValueAsString(startAuditEvent);
startAuditEventString = startAuditEvent.toString();
System.out.println("Starting AuditEvent Json: %s".formatted(startAuditEventJson));
System.out.println("Starting AuditEvent String: %s".formatted(startAuditEventString));

jsonMapperManual =
JsonMapper
.builder()
.enable(StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION)
.constructorDetector(ConstructorDetector.USE_PROPERTIES_BASED)
.build();
}

@Test
void deserializeWithSpringMapper() {

AuditEvent auditEvent =
jsonMapper.readValue(
startAuditEventJson,
AuditEvent.class);

Assertions.assertNotNull(auditEvent);
Assertions.assertEquals("user", auditEvent.getPrincipal());
Assertions.assertEquals("type", auditEvent.getType());
Assertions.assertEquals(2, auditEvent.getData().size());
}

@Test
void deserializeWithLocalMapperDef() {

AuditEvent auditEvent =
jsonMapperManual.readValue(
startAuditEventJson,
AuditEvent.class);

Assertions.assertNotNull(auditEvent);
Assertions.assertEquals("user", auditEvent.getPrincipal());
Assertions.assertEquals("type", auditEvent.getType());
Assertions.assertEquals(2, auditEvent.getData().size());
}
}
```

### Expected behavior

AuditEvent should be constructed as a public constructor for the properties supplied exists.

### Additional context

The defaut builder(which was always enough in Jackson2) fails but I have a Spring config which fails as well.
```java
@Bean
public JsonMapperBuilderCustomizer includeSourceInLocationCustomizer() {
return builder -> {
builder.enable(StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION);
builder.constructorDetector(
ConstructorDetector.USE_PROPERTIES_BASED
.withAllowImplicitWithDefaultConstructor(ConstructorDetector.DEFAULT_ALLOW_IMPLICIT_WITH_DEFAULT_CONSTRUCTOR)
.withRequireAnnotation(false)
.withAllowJDKTypeConstructors(true)
.withSingleArgMode(ConstructorDetector.SingleArgConstructor.PROPERTIES));
};
}
```

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.