thmmy95
thmmy95

Reputation: 371

Hashmap unrecognized by CsvMapper

I'm trying to serialize an object which contains a HashMap and i get following exception.

com.fasterxml.jackson.dataformat.csv.CsvMappingException: Unrecognized column 'tags': known columns: ["_id","insertDate"] (through reference chain.

Also, I don't understand why it's necessary to have a schema when it's about serialization. In my mind, there is no way to have an unrecognized field because all it's specified inside the class.

Because i don't know well Jackson, i searched and tried various combination of these 2 annotations. @JsonUnwrapped @JsonAnyGetter

class Product{
    public @Id String _id;

    @JsonUnwrapped
    private HashMap<String, String> tags = new HashMap<>();

    public String insertDate;

    @JsonAnyGetter
    public HashMap<String, String> getTags() {
        return tags;
    }
    @JsonAnySetter
    public void setTags(HashMap<String, String> tags) {
        this.tags = tags;
    }
}

Code used for serialization

CsvSchema schema = csvMapper.schemaFor(Product.class).withHeader();
ObjectWriter myObjectWriter = csvMapper.writer(schema);
csvMapper.enable(CsvParser.Feature.IGNORE_TRAILING_UNMAPPABLE);
csvMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
string = myObjectWriter.writeValueAsString(someProduct);

TRY NR 2

public class Product {

public @Id String _id;

public Map<String, String> tags = new HashMap<>();

public String insertDate;

@JsonAnyGetter
public Map<String, String> getTags() {
    return tags;
}
@JsonAnySetter
public void setTags(Map<String, String> tags) {
    this.tags = tags;
}

}

NEW ERROR

com.fasterxml.jackson.dataformat.csv.CsvMappingException: CSV generator does not support Object values for properties (nested Objects) (through reference chain: main.model.Product["tags"])

Upvotes: 1

Views: 2611

Answers (1)

Bartosz Piorunski
Bartosz Piorunski

Reputation: 114

Using Collection implementation class HashMap<String, String> for field type (rather than only for its initial value type) confuses Jackson.

Jackson checks for interface java.util.Map to choose proper Serializer, as evidenced in constructor of

com.fasterxml.jackson.databind.ser.std.MapSerializer

As per Schema question, according to jackson-dataformat-csv docs

It is important to note that the schema object is needed to ensure correct ordering of columns;

Note also that while explicit type can help efficiency it is usually not required, as Jackson data binding can do common conversions/coercions

I guess ObjectWriter.writeValueAsString(Object) could check reflexively to infer type for serialized object.

Due to tabular nature of CSV format, deeply nested data structures are not well supported.

@JsonUnwrapped is for (nested) POJO-s only. What you want is to use @JsonAnyGetter. And it needs to return java.util.Map. JavaDocs:

Note that the return type of annotated methods must be Map).

If you are only serializing, @JsonAnySetter won't be needed.

I'm curious why are you using Map for tags. Maybe List<String> tags would suffice, tags have only names.

Worth checking out: https://www.baeldung.com/jackson-mapping-dynamic-object

Upvotes: 1

Related Questions