FasterXML / jackson-future-ideas

Repository for SOLE PURPOSE of issue tracker and Wiki for NEW IDEAS. Please: NO BUG REPORTS.
18 stars 6 forks source link

Add JSON BodyHandlers/BodyPublishers support for the new Java 11 HttpClient #45

Open pragmasoft-ua opened 4 years ago

pragmasoft-ua commented 4 years ago

Similar to the described in this SO thread

https://stackoverflow.com/questions/57629401/deserializing-json-using-java-11-httpclient-and-custom-bodyhandler-with-jackson

cowtowncoder commented 4 years ago

I am not quite sure of the part that relates to Jackson here... could you elaborate?

sergeykad commented 3 years ago

BodyHandler that can convert raw InputStream with JSON into a POJO. BodyPublisher that takes a POJO and converts it into a byte array with JSON.

In other words Java 11 HTTP client integration.

cowtowncoder commented 3 years ago

This sounds like some kind of extension module (jackson-jr has couple, for example; and there are JAX-RS providers) or package, then, at least initially. Databind cannot have dependency to Java 11 quite yet.

davinkevin commented 11 months ago

Small up because with all evolutions in Java 17 and 21 now, just using Jackson with the java client is something I do a lot, in addition with native compilation to get something simple & performant.

cowtowncoder commented 11 months ago

As usual, PRs welcome! Could perhaps be added to jackson-modules-base or something. Does not belong to core (jackson-core, jackson-databind) components

JooHyukKim commented 11 months ago

Would be great if someone can share solid usage example tho... like to what extent this "new module" should incorporate HttpClient ?

davinkevin commented 11 months ago

I did that in Kotlin:

class JsonBody {
    companion object {
        val defaultObjectMapper = ObjectMapper().findAndRegisterModules()!!

        fun publisher(body: Any, objectMapper: ObjectMapper? = null): BodyPublisher {
            val mapper = objectMapper ?: this.defaultObjectMapper
            return BodyPublishers.ofString(mapper.writeValueAsString(body))
        }

        inline fun <reified T> handler(objectMapper: ObjectMapper? = null): BodyHandler<T> {
            val mapper = objectMapper ?: this.defaultObjectMapper
            val jsonNodeSubscriber = BodySubscribers.mapping(BodySubscribers.ofByteArray()) {
                mapper.readValue(it, T::class.java)
            }
            return BodyHandler { jsonNodeSubscriber }
        }
    }
}

And usage is very simple:

val request = HttpRequest.newBuilder()
            .uri(URI.create(instance.spec.url.toASCIIString() + "/api/v2/links"))
            .POST(JsonBody.publisher(linkBody))
            .header("Content-Type", MediaType.APPLICATION_JSON_VALUE)
            .header("Authorization", token)
            .build()

return client.send(request, JsonBody.handler<LinkCreationResult>()).body()

It's part of a POC… I kept the opportunity to provide the ObjectMapper as parameter, but the companion has a default one too.