On Tuesday, April 16, 2019 at 5:05:14 PM UTC-4, Tatu Saloranta wrote: > > On Tue, Apr 16, 2019 at 1:05 PM Chris C <yahoo...@gmail.com <javascript:>> > wrote: > >> I have a map of type >> >> Map<Key1, Map<Key2, Integer>> >> >> that I want to serialize to json to store in as a field in a database >> record. >> >> Key1 and Key2 are my own classes with getters defined and the >> constructors annotated as JsonCreators. >> >> I have been able to process single level maps for the same purpose by >> configuring the type factory for the object mapper, but I am unsure how to >> go about it for nested maps with different keys. >> > > There are 2 challenges: > > 1. Expressing `JavaType` to use for deserialization (serialization is > usually fine, although if you try to serialize Map as root value [Strongly > Discouraged practice!], then there too) >
Can you explain what you mean please? 2. Allowing custom Map key types -- may need to register Key deserializers, > key serializers (common types like `String`, `Number` supported out of the > box) > - note: Map keys must be scalar types; read from String, written as > Strings > > First one is done using `TypeFactory`, either with TypeReference: > > JavaType mapRef = typeFactory.constructType(new TypeReference<Map<Key1, > Map<Key2, Integer>>>) {} ()) > > Or constructing it in two parts, something like > > JavaType mapRef = typeFactory.constructMapType(Map.class, > typeFactory.constructType(Key1.class), > typeFactory.constructMapType(Map.class, > typeFactory.constructType(Key2.class), > typeFactory.constructType(Integer.class))); > > Second part may be more involved, but if you have already handled > non-nested maps with custom types, you probably know how that works. > > I didn't even think to chain the type factory calls here. Before I tackle the deserialization I ran into serialization. Expanding on the structure I have the following (was using https://www.baeldung.com/jackson-map as a starting point) public class Basket { // other fields // this is what I am trying to de/serialize separately private Map<Seller,Map<BasketItem,Integer>> contents; // other stuff removed @JsonSerialize(using = Seller.Serializer.class) public static final class Seller { private final Long id; private final String name; @JsonCreator Seller(@JsonProperty("id") Long id, @JsonProperty("name") String name) { this.id = id; this.name = name; } // getters, equals, hashcode, tostring public static class Serializer extends StdSerializer<Seller> { private static final long serialVersionUID = 1L; public Serializer() { super(Seller.class); } public Serializer(Class<Seller> t) { super(t); } @Override public void serialize(Seller seller, JsonGenerator jsonGenerator , SerializerProvider serializerProvider) throws IOException { jsonGenerator.writeStartObject(); jsonGenerator.writeNumberField("id", seller.getId()); jsonGenerator.writeStringField("name", seller.getName()); jsonGenerator.writeEndObject(); } } } @JsonSerialize(using = BasketItem.Serializer.class) public static final class BasketItem { private final Long itemId; private final String itemName; private final Price unitPrice; @JsonCreator BasketItem(@JsonProperty("itemId") Long itemId, @JsonProperty("itemName") String itemName, @JsonProperty("unitPrice") Price unitPrice) { this.itemId = itemId; this.itemName = itemName; this.unitPrice = unitPrice; } // getters, equals, hashCode, toString public static final class Serializer extends StdSerializer<BasketItem> { public Serializer() { super(BasketItem.class); } public Serializer(Class<BasketItem> t) { super(t); } @Override public void serialize(BasketItem basketItem, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException { jsonGenerator.writeStartObject(); jsonGenerator.writeNumberField("itemId", basketItem. getItemId()); jsonGenerator.writeStringField("itemName", basketItem. getItemName()); jsonGenerator.writeObjectField("unitPrice", basketItem. getUnitPrice()); jsonGenerator.writeEndObject(); } } } } public final class Price { private final BigDecimal amount; // this is an enum private final Currency currency; @JsonCreator public Price(@JsonProperty("amount") BigDecimal amount, @JsonProperty( "currency") Currency currency) { this.amount = amount; this.currency = currency; } // getters, equals, hashCode, toString } When I try to serialize this using either String json = new ObjectMapper().writeValueAsString(contents) or final ObjectMapper mapper = new ObjectMapper(); final SimpleModule module = new SimpleModule(); module.addSerializer(BasketItem.class, new BasketItem.Serializer()); module.addSerializer(Seller.class, new Seller.Serializer()); mapper.registerModule(module); String json = mapper.writeValueAsString(contents); it uses my toString(), but not the serializer from the annotation. If I remove my toString, it falls back to Object.toString(). No exceptions are being thrown. Why is my Serializer not being used? After that, what do I need to implement and register for deserialization? Thanks Chris -- You received this message because you are subscribed to the Google Groups "jackson-user" group. To unsubscribe from this group and stop receiving emails from it, send an email to jackson-user+unsubscr...@googlegroups.com. To post to this group, send email to jackson-user@googlegroups.com. For more options, visit https://groups.google.com/d/optout.