My service has to redirect a json data to another service. In all examples I saw on feign client, sender knows the data type of the sent object, and so it looks like this:
@RequestMapping("some/path", consumes = [MediaType.APPLICATION_JSON_VALUE])
interface UploadClient {
@PostMapping("upload")
fun upload(book: Book): Long
}
My problem is I have no Book class, I just have to forward json. I've tried to do it with String, like this:
Client interface:
@RequestMapping("some/path")
interface UploadClient {
@PostMapping("/upload", consumes = arrayOf(MediaType.APPLICATION_JSON_VALUE))
fun import(@RequestBody strangeData: String): Long
}
Feign Factory:
class DefaultFeignClientFactory() : FeignClientFactory {
override fun <T> getClient(target: Class<T>, url: String): T {
return registry.getOrPut(target) {
Feign.builder()
.target(target, url)
} as T
}
}
Client is instantiated using OSGi:
<bean id="uploadClient" factory-ref="feignClientFactory" factory-method="getClient">
<argument value="com.blah.blahblah.UploadClient"/>
</bean>
And the same interface on the receiver side is:
@RequestMapping("some/path")
interface Loader {
@PostMapping("/upload")
fun import(@RequestBody myBooks: Collection<Book>): Long
}
If I throw json in the receiver directly (curl/postman/etc), it deserializes it and works fine. Passing the string to feign client works, but unfortunately, receiver can't deserialize it that way. So I tried to change it to byte[] (ByteArray in Kotlin):
@PostMapping("/upload", consumes = arrayOf(MediaType.APPLICATION_JSON_VALUE))
fun import(@RequestBody strangeData: ByteArray): Long
and it falls with org.springframework.web.HttpMediaTypeNotSupportedException message: Unsupported Media Type
Same luck with MediaType.APPLICATION_OCTET_STREAM_VALUE
and MediaType.ALL_VALUE
(actually ALL_VALUE fell with some other error) - data is not sent to the receiver service in any form.
What Java data type and what MediaType do I have to choose in those circumstances? Thanks in advance.
One way to state that your method is accepting generic JSON is by using Jackson's JsonNode as your parameter type.
@RequestMapping(value = ["some/path"], consumes = [MediaType.APPLICATION_JSON_VALUE])
interface UploadClient {
@PostMapping("upload")
fun upload(@RequestBody book: JsonNode): Long
}
This way, you are able to post JSON Objects, JSON Arrays, Strings, Numbers or Booleans with arbitrary nesting. Here's an example:
val book: ObjectNode = JsonNodeFactory.instance.objectNode()
.put("authors", JsonNodeFactory.instance.arrayNode()
.add("John Doe")
.add("Jane Doe"))
.put("title", "First Book about the Does")
.put("year", 2018)
val id = uploadClient.upload(book)
This is equivalent to the following request
POST /some/path HTTP/1.1
Host: localhost:8080
Content-Type: application/json
{
"authors": ["John Doe", "Jane Doe"],
"title": "First Book about the Does",
"year": 2018
}
Using JsonNode will also work on the server side.