On Fri, Apr 19, 2019 at 9:39 AM Chris C <[email protected]> wrote:
> > > On Wednesday, April 17, 2019 at 8:59:03 PM UTC-4, Tatu Saloranta wrote: >> >> On Wed, Apr 17, 2019 at 9:02 AM Chris C <[email protected]> wrote: >> > >> > 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 <[email protected]> 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? >> >> Which part? >> >> > > Why is serializing a map as root value is discouraged? Can you give an > example of what you mean please? > > What I mean is that you should -- in my opinion -- not serialize Map (or Collection/List) values directly as values, but only as POJO properties. This is because polymorphic type information is not available at runtime for `Map` instances (or Collections, Lists), whereas it IS available if reference is via POJO. So: class MyWrapper { public Map<KeyType, ValueType> values; } is preferred over directly serialization an instance of `Map<KeyType, ValueType>`. Now... in many cases things work ok with runtime type information being sufficient (Jackson does dynamically figure out serializers for keys and values), but not so if those types are polymorphic. While it is possible to make it all work, by providing type information, like: mapper.writerFor(new TypeRefernece<Map<KeyType, ValueType>>() { }) .writeValue(map); I don't think it's worth the hassle. Especially since I get to answer same question over and over again on "why doesn't Jackson find polymorphic type for my Map values (or List or Set)". :) > >> 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) >> >> This is only "value" serialization: values of this type as POJO >> property values. But it is not >> But it is NOT used when serializing Map keys. This because Map keys >> (and POJO property names, that is, name part of JSON objects). >> >> There is actually `keyUsing` equivalent, but that is only for `Map` >> types to indicate how keys of that Map-valued property are to be >> serialized. >> >> To associate serializer to use for Map keys of specific type you need >> to register key serializer using Modules: `SimpleModule` has method >> `addKeySerializer()` (as well as `addKeyDeserializer()`). You need to >> use these. >> >> > Got it, thanks. Added the key serializers and encapsulated the map in > another class (due to synchronized functionality) and serializing that > class directly works like a charm. > Excellent! -+ Tatu +- -- 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 [email protected]. To post to this group, send email to [email protected]. For more options, visit https://groups.google.com/d/optout.
