Search before asking
- [x] I searched in the issues and found nothing similar.
Describe the bug
Continuation of https://github.com/FasterXML/jackson-databind/issues/4922.
Version Information
2.19.1, 2.19.2, 2.18.3
Reproduction
When the containing class of the Map
is constructed with a @JsonCreator
constructor, the issue comes back.
import java.util.HashMap;
import java.util.Map;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonMerge;
import com.fasterxml.jackson.core.JsonParser.Feature;
import com.fasterxml.jackson.databind.json.JsonMapper;
import com.fasterxml.jackson.module.paramnames.ParameterNamesModule;
interface MyMap<K, V> extends Map<K, V> {}
class MapImpl<K, V> extends HashMap<K, V> implements MyMap<K, V> {}
class MapUtils {
static <K, V> MyMap<K, V> createMyMap() {
return new MapImpl<K, V>();
}
}
class MergeMap {
@JsonCreator
MergeMap(int inter, String s) {
System.out.println("creator for " + map.getClass().getSimpleName());
this.inter = inter;
this.s = s;
}
int inter;
String s;
public int getInter() {
return inter;
}
// public String getS() {
// return s;
// }
@JsonMerge
MyMap<Integer, String> map = MapUtils.createMyMap();
public MyMap<Integer, String> getMap() {
System.out.println("getMap");
return map;
}
@Override
public String toString() {
return map.toString() + " " + inter + " " + s;
}
public static void main(String[] args) throws Exception {
JsonMapper MAPPER = JsonMapper.builder()
.addModule(new ParameterNamesModule())
.configure(Feature.INCLUDE_SOURCE_IN_LOCATION, true)
.build();
var merge = new MergeMap(5, "f");
merge.getMap().put(3, "ADS");
System.out.println(merge);
System.out.println(" == serializing --");
var string = MAPPER.writerWithDefaultPrettyPrinter().writeValueAsString(merge);
System.out.println(string);
System.out.println(" == deserializing --");
var merge2 = MAPPER.readValue(string, MergeMap.class);
System.out.println(" == checking --");
System.out.println(merge2);
}
}
Gives
creator for MapImpl
getMap
{3=ADS} 5 f
== serializing --
getMap
{
"inter" : 5,
"map" : {
"3" : "ADS"
}
}
== deserializing --
Exception in thread "main" com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `example.MyMap` (no Creators, like default constructor, exist): no default constructor found
at [Source: (String)"{
"inter" : 5,
"map" : {
"3" : "ADS"
}
}"; line: 3, column: 11] (through reference chain: example.MergeMap["map"])
at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:67)
at com.fasterxml.jackson.databind.DeserializationContext.reportBadDefinition(DeserializationContext.java:1915)
at com.fasterxml.jackson.databind.DatabindContext.reportBadDefinition(DatabindContext.java:415)
at com.fasterxml.jackson.databind.DeserializationContext.handleMissingInstantiator(DeserializationContext.java:1402)
at com.fasterxml.jackson.databind.deser.std.MapDeserializer.deserialize(MapDeserializer.java:440)
at com.fasterxml.jackson.databind.deser.std.MapDeserializer.deserialize(MapDeserializer.java:31)
at com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:543)
at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeWithErrorWrapping(BeanDeserializer.java:587)
at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeUsingPropertyBased(BeanDeserializer.java:480)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1499)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:340)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:177)
at com.fasterxml.jackson.databind.deser.DefaultDeserializationContext.readRootValue(DefaultDeserializationContext.java:342)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4971)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3887)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3855)
at example.MergeMap.main(MergeMap.java:74)
Uncommenting the getS()
method resolves the issue, but shouldn't have affected the construction of the map.
Also, declaring Map<Integer, String> map = MapUtils.createMyMap();
instead also works, but the whole point is to merge to an initialized custom type. It shows that the containing class construction is valid, however.
Expected behavior
No response
Additional context
No response