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.

Reply via email to