FasterXML / jackson-dataformats-binary

Uber-project for standard Jackson binary format backends: avro, cbor, ion, protobuf, smile
Apache License 2.0
314 stars 136 forks source link

Add `ProtobufMapper.generateSchemaFor(TypeReference<?>)` overload #148

Closed MrThreepwood closed 5 years ago

MrThreepwood commented 6 years ago

I'm attempting to generate a schema in Kotlin. Conveniently in Kotlin I get access to inline functions that allow me to easily create type tokens for classes with generic parameters, simplifying serialization/deserialization greatly in my JSON code. Unfortunately, I don't have that option here and am finding it difficult to get a similar solution working to create a schema for my protobuf mapper.

I don't immediately see a simple way to convert a type token into a JavaType either, though perhaps there is something simple that I am missing?

MrThreepwood commented 6 years ago

Sorry for changing the title so many times, I've been working with a lot of parsers recently and waffled on whether this was a question or a feature request. I think I do have a workaround for this (I simply use ObjectMapper's TypeFactory's constructType(TypeReference type) method to convert from a TypeReference to a JavaType (looks like this is what readValue does, which is how I found it).

It would still be fairly nice if this were provided in the base functionality, but knowing this workaround it's not as big of a deal.

cowtowncoder commented 6 years ago

If I understood description correctly, I think the main limitation is that any Kotlin-specific types are out for core functionality, and should be only accessed by jackson-module-kotlin. One possible exception could be use of Reflection for dynamic access, but it is pretty difficult to devise API that would be suitable opaque and usable to make it all work.

I am open to suggestions, of course, as opening up new extension points is possible, and a few have been added for Scala and Kotlin support in the past.

I also think this probably belongs more to jackson-databind if anything as this issue is not (I think?) specific to binary codecs (protobuf?)

MrThreepwood commented 6 years ago

It is actually just an issue with getSchema(), possibly across all things in this project, but definitely an issue with ProtobufMapper() and doesn't directly have anything to do with Kotlin.

The getSchema function only works on JavaType and Class, whereas most similar jackson APIs also accept a TypeReference. The only reason I brought up Kotlin is that in Kotlin, it's very easy to make a TypeReference with reified generics in inline functions, whereas it is harder to make a JavaType.

With Kotlin:

inline fun <reified T : Any> createProducer(topic: String): IProducer<T> {
    val type = object: TypeReference<T>(){}
}

It's as easy as that. However, as T may have generic types, it's not enough to simply say: getSchema(T::class.java), as that will fail. And it's relatively difficult to get a JavaType directly from a refied T : Any. For this reason I ended up converting my TypeReference to a JavaType using constructType, but that isn't an obvious solution. It would be easier if getSchema simply accepted a TypeReference directly. However, it's not a huge deal as it's not hard to convert a TypeReference to a JavaType once you know how.

I guess what I'm asking for is just an additional method overload for ProtobufMapper:

public ProtobufSchema generateSchemaFor(TypeReference type) throws JsonMappingException {
    generateSchemaFor(_typeFactory.constructType(type));
}