Details
Description
When trying to implement type overriding in a webapp, I noticed that despite xsi:type attributes being sent over correctly, the server wouldn't deserialise into the correct concrete implementations of the declared interface. Upon further examination, it seems that in AegisBindingProvider.getReadType() line 160, the TypeMapping returned by type.getTypeMapping() can't find the overriding class. The TypeMapping that corresponds to my service does have the overriding classes defined in it. Somewhere along the way the two got confused.
The actual object I'm trying to deserialise is a bean that contains a List of the interface I want to override. AegisBindingParameter.readParameter() gets the correct TypeMapping for my Service, which is then used to find the CollectionType for my interface (all well and good so far), and then that type's TypeMapping (also the same one) is used to find the BeanType for my interface. Then getReadType() uses the BeanType's TypeMapping to find the overriding type. But lo and behold, the TypeMapping returned by getTypeMapping() on my interface's BeanType is NOT the same TypeMapping defined by my Service and used by all the other types - and so it can't find the overriding types.
Amazed at this, I set a conditional breakpoint on CustomTypeMapping.register(), and found that it's seemingly not uncommon for a type that already has an associated TypeMapping to be registered with another TypeMapping, thus losing the link back to its previous mapping. This leads to a situation where for a TypeMapping tm, tm.getType(foo).getTypeMapping() != tm. My reading of the code is that this condition is assumed to always hold.
So either:
i) That assumption's correct, and a Type should only ever be registered with one TypeMapping. In which case the problem code is around BeanTypeInfo.getType(), which (in the 3rd case) creates a Type that is already registered with another TypeMapping other than the tm variable in that method. The root cause of this is that tm.getTypeCreator().getTypeMapping() != tm, so we've got yet another level of multiple registration. Where this happens I'm not so sure - though in DefaultTypeMappingRegistry.createTypeMapping() we get an instance where a TypeCreator that is registered with one TypeMapping is then registered with another.
ii) The assumption is wrong and Types are allowed to be registered with multiple TypeMappings. Then the AegisBindingProvider makes this assumption too, and as a result it can't find overriding types properly. I'm not sure what the solution would be here - if you can get a reference to the Service, you can get the service's TypeMapping which will be guaranteed to have the overridden types registered with it. Otherwise you just don't know which TypeMappings are associated with which Types.
FYI, this is 100% reproducible for me (and fails in the same way each time) so it's not some strange thread safety issue.
Sorry I missed this issue before. Scheduling now so I can investigate more in depth.