Thank you Tatu
It is #2 I'm referring to. I should have included the output when
enableDefaultTyping is on ...
{"singleEnum":"TWO","enumSet":["java.util.HashSet",[["MyTest$MyEnum","TWO"],["MyTest$MyEnum","THREE"],["MyTest$MyEnum","ONE"]]],"mapOfEnumSets":["java.util.LinkedHashMap",{"firstKey":["java.util.HashSet",[["MyTest$MyEnum","TWO"],["MyTest$MyEnum","THREE"],["MyTest$MyEnum","ONE"]]]}]}
I understand your point on typing the Set implementations, but that
becomes a bit awkward considering the map can contain differently typed
sets at the same time.
I have the solution with enableDefaultTyping (or it's newer, safer
equivalent). I was just hoping I could achieve the same with annotations,
as somebody is bound to forget to configure their mapper correctly :)
Thanks
Mark
On Sun, Sep 12, 2021 at 5:12 AM Tatu Saloranta <[email protected]> wrote:
> On Fri, Sep 10, 2021 at 9:02 PM Mark Gibson <[email protected]>
> wrote:
> >
> > Hi,
> >
> > I have a case where a map is used to store many sets of values.
> >
> > Map<String, Set<?>>
> >
> > Each set instance is a set of homogenous data types. But the different
> entries in the map hold a heterogenous collection of set types. Difficult
> to put in to English, but the example code below is actually quite simple.
> The description here is to imply that the set always has to be Set<?> and
> can't be fully typed.
> >
> > Obviously, to successfully deserialize such a heterogeneous map, type
> information must be included in the serialized Json. This is achievable by
> configuring the ObjectMapper. For example,
> >
> > mapper.enableDefaultTyping( );
> >
> > means all type information is recorded in the serialized JSON. However,
> I'm trying to use @JonTypeInfo attribute so that callers of our library do
> not need to remember to use a correctly configured ObjectMapper.
> JsonTypeInfo seems to work for a simple set, but does not work when applied
> to the map ...
> >
> > public class MyTest
> > {
> > @JsonTypeInfo(
> > use = JsonTypeInfo.Id.CLASS,
> > include = JsonTypeInfo.As.PROPERTY,
> > property = "@type",
> > visible = true
> > )
> > public enum MyEnum
> > {
> > ONE,
> > TWO,
> > THREE
> > }
> >
> > @JsonAutoDetect( fieldVisibility = JsonAutoDetect.Visibility.NONE,
> getterVisibility = JsonAutoDetect.Visibility.NONE, setterVisibility =
> JsonAutoDetect.Visibility.NONE, isGetterVisibility =
> JsonAutoDetect.Visibility.NONE )
> > public static class MyClass
> > {
> > @JsonProperty( )
> > MyEnum singleEnum;
> >
> > @JsonTypeInfo(
> > use = JsonTypeInfo.Id.CLASS,
> > include = JsonTypeInfo.As.PROPERTY,
> > property = "@type",
> > visible = true
> > )
> > @JsonProperty( )
> > Set<?> enumSet;
> >
> > @JsonProperty( )
> > @JsonTypeInfo(
> > use = JsonTypeInfo.Id.CLASS,
> > include = JsonTypeInfo.As.PROPERTY,
> > property = "@type",
> > visible = true
> > )
> > Map<String, Set<?>> mapOfEnumSets = new LinkedHashMap<>( );
> > }
> >
> > public static void main( String[] args ) throws
> JsonProcessingException
> > {
> > MyClass mc = new MyClass( );
> > mc.singleEnum = MyEnum.TWO;
> > mc.enumSet = Stream.of( MyEnum.ONE, MyEnum.TWO, MyEnum.THREE
> ).collect( Collectors.toSet( ) );
> > mc.mapOfEnumSets.put( "firstKey", Stream.of( MyEnum.ONE,
> MyEnum.TWO, MyEnum.THREE ).collect( Collectors.toSet( ) ) );
> >
> > ObjectMapper om = new ObjectMapper( );
> >
> > String jsonString = om.writeValueAsString( mc );
> >
> > System.out.println( jsonString );
> > }
> > }
> >
> >
> > This is the serialized JSON:
> >
> >
> {"singleEnum":["MyTest$MyEnum","TWO"],"enumSet":[["MyTest$MyEnum","TWO"],["MyTest$MyEnum","THREE"],["MyTest$MyEnum","ONE"]],"mapOfEnumSets":{"firstKey":["java.util.HashSet",["TWO","THREE","ONE"]]}}
> > .
> > Is it possible to get the type info generated for the contents of the
> sets in the map using JsonTypeInfo and/or other annotations? Or are we
> limited to the direct configuration of the ObjectMapper?
>
> Not sure I understand the exact question, but couple of notes that may
> help:
>
> 1. Use of `@JsonTypeInfo` on Enum types does not really make sense
> (here for MyEnum), since enum types can not be extended. (not a big
> problem here, but worth mentioning). Adding @JsonTypeInfo on enum has
> no effect on Set, Map, since the declared value base type is not
> MyEnum.
> 2. Use of `@JsonTypeInfo` for structured types (Collections, Maps,
> arrays) affects main-level values/elements. So, works fine for
> `Set<Object>` (which is what `Set<?>` is from Jackson's perspective),
> but not really for multiple levels (Map<String, Set<?>> ) -- in latter
> case it'd mean "polymorphic subtype of Set<?>"
>
> I assume (2) is the problem wrt nested Maps: polymorphic handling can
> only be enabled for the immediate child value, but not to the
> innermost level.
>
> You could, however, declare your own special `Set` type there... something
> like
>
> @JsonTypeInfo(....)
> static class MySet<T> extends HashSet<T> { }
>
> and then use that
>
> > Map<String, MySet<?> mapOfEnumSets = new LinkedHashMap<>( );
>
> in declaration. This would, I think, force inclusion and use of
> polymorphic type information.
>
> -+ 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 view this discussion on the web visit
> https://groups.google.com/d/msgid/jackson-user/CAL4a10jGUvqaYVWRnht5TiOEMLM2%2B%3Dc7zYGvS7XuaAFw-SKhqA%40mail.gmail.com
> .
>
--
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 view this discussion on the web visit
https://groups.google.com/d/msgid/jackson-user/CAG%3D-QZMyKaiYiddf5FeaPB2E9Yeauh%2Brfgui3VRq5%3DKxS4EM7Q%40mail.gmail.com.