colleagues! I've encountered an issue with object mapping during deserialization. We have an interface Source
, which is implemented by two classes (SimpleSource
and ComplexSource
). Instances of these classes are contained in lists within a separate object called SourceContainer
. The JSON stores the configuration of SourceContainer
, which we want to deserialize. The error is as follows:
com.fasterxml.jackson.databind.exc.InvalidTypeIdException: Could not resolve subtype of [simple type, class org.example.SimpleSource]: missing type id property 'jacksonType' (for POJO property 'simpleSources')
at [Source: REDACTED (`StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION` disabled); line: 5, column: 5] (through reference chain: org.example.SourceContainer["simpleSources"]->java.util.ArrayList[0])
To reproduce the error, I'll provide a concise list of all the classes in my program
package org.example;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import java.io.InputStream;
public class Main {
public static void main(String[] args) {
InputStream jsonFile = Main.class.getClassLoader().getResourceAsStream("sourceContainer.json");
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
try {
SourceContainer sourceContainer = objectMapper.readValue(jsonFile, SourceContainer.class);
sourceContainer.printAllSources();
} catch (IOException e) {
e.printStackTrace();
}
}
}
package org.example;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY,
property = "jacksonType"
)
@JsonSubTypes({
@JsonSubTypes.Type(value = SimpleSource.class, name = "simpleSource"),
@JsonSubTypes.Type(value = ComplexSource.class, name = "complexSource")
})
public interface Source {
String getDescription();
}
package org.example;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Getter
@Setter
@NoArgsConstructor
public class SimpleSource implements Source {
private String description;
public SimpleSource(String description) {
this.description = description;
}
@Override
public String getDescription() {
return "Simple Source: " + description;
}
}
package org.example;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Getter
@Setter
@NoArgsConstructor
public class ComplexSource implements Source {
private String description;
private String details;
public ComplexSource(String description, String details) {
this.description = description;
this.details = details;
}
@Override
public String getDescription() {
return "Complex Source: " + description + " - " + details;
}
}
package org.example;
import lombok.Getter;
import lombok.Setter;
import java.util.ArrayList;
import java.util.List;
@Getter
@Setter
public class SourceContainer {
private List<SimpleSource> simpleSources;
private List<ComplexSource> complexSources;
public SourceContainer() {
this.simpleSources = new ArrayList<>();
this.complexSources = new ArrayList<>();
}
// Добавление SimpleSource
public void addSimpleSource(SimpleSource source) {
simpleSources.add(source);
}
// Добавление ComplexSource
public void addComplexSource(ComplexSource source) {
complexSources.add(source);
}
// Печать всех источников
public void printAllSources() {
System.out.println("Simple Sources:");
for (SimpleSource source : simpleSources) {
System.out.println(source.getDescription());
}
System.out.println("Complex Sources:");
for (ComplexSource source : complexSources) {
System.out.println(source.getDescription());
}
}
}
The issue is with mapping objects to the model during deserialization
Jackson is failing to deserialize your JSON because the data structure described in the file sourceContainer.json
does not exhibit the property jacksonType
.
Could not resolve subtype of [simple type, class org.example.SimpleSource]: missing type id property 'jacksonType' (for POJO property 'simpleSources')
The property jacksonType
is necessary because it's used by the annotation @JsonSubTypes
to determine the correct subtype of Source
and to properly deserialize your JSON.