RicoSuter / NJsonSchema

JSON Schema reader, generator and validator for .NET
http://NJsonSchema.org
MIT License
1.38k stars 532 forks source link

Polymorphism of types I don't control with NSwag/NJsonSchema #585

Closed crystalcodesoftware closed 6 years ago

crystalcodesoftware commented 6 years ago

I asked a question on Stack Overflow pertaining to this issue, and I've drilled through the source, but I can't find anywhere a feature/workaround for this exists.

A quick copy/paste from the question:

[...] what if I don't own (or cannot change) the types in the relevant inheritance hierarchy?

Consider this:

// LibAssembly (cannot change)

[DataContract]
[KnownType(nameof(CommonThingBase.GetKnownTypes))]
public abstract class CommonThingBase
{ 
    public static IEnumerable<Type> GetKnownTypes() { /* works as expected */ }
}

[DataContract]
public class ACommonThing : CommonThingBase { }

[DataContract]
public class BCommonThing : CommonThingBase { }
// ApiAssembly (mine, references LibAssembly)

public class ViewModelThing
{
    public CommonThingBase CommonThing { get; }
}

public class CommonThingController : ApiController
{
    [HttpGet]
    [Route("/CommonThing")]
    [ResponseType(typeof(ViewModelThing))]
    public IHttpActionResult GetCommonThing() { /* works as expected */ }
}

Assuming I don't own (or cannot change) the CommonThingBase and it's derived types in LibAssembly, how can I generate a Swagger schema that includes the derived types of CommonThingBase?

Is there a way to retrofit closed types with [JsonConverter(typeof(JsonInheritanceConverter), "discriminator")]?

crystalcodesoftware commented 6 years ago

Sorry, itchy fingers.

RicoSuter commented 6 years ago

Currently there is no way to achieve this. If the converter does not exist, then the discriminator property is not set, however, inheritance should be generated if the base type is used somewhere. It should be simple to externally define a discriminator...

RicoSuter commented 6 years ago

Just checked this. If you enable GenerateKnownTypes then all required schemas should be generated. The problem is however that the "discriminator" property is missing so the (generated) deserializer does not know how to determine the actual type.

To completely fix this, we have two problems:

  1. Additionally generate the "discriminator" property (i.e. configure the name and class externally)
  2. Extend the serialization process of the existing classes/application so that it can handle the discriminator (e.g. a global JsonInheritanceConverter) (deserialization only)
crystalcodesoftware commented 6 years ago

Interesting. Unless I'm mistaken, I don't believe the generated schema contained type information about the derived types; I'll have to have another look though.

I'm going to play with this a bit more and determine concretely where I found it breaking down on my end. A global JsonInheritanceConverter was sort of what I was thinking (though perhaps not "global", so much as DI managed)

RicoSuter commented 6 years ago

I've added this capability, just check the unit tests... The new DiscriminatorSchemaProcessor can only be defined in code. Currently it's not possible to define it in NSwagStudio