I would like to enrich collection of orders with person details.
Suppose I've (example is in json):
[
{
"orderId": 123,
"quantity": 5,
"buyerId": "84aa820f-2301-4d01-8c4c-2b71204da7dd"
},
{
"orderId": 124,
"quantity": 5,
"buyerId": "7158a748-dfd0-47e5-b620-e8ca4d3ac84d"
}
]
And now I would like extract all buyer identifiers to hit other message endpoint, so I will get in result:
[
{
"personId": "84aa820f-2301-4d01-8c4c-2b71204da7dd",
"name": "Johny",
"surname": "Bravo"
},
{
"personId": "7158a748-dfd0-47e5-b620-e8ca4d3ac84d",
"name": "Felica",
"surname": "Good"
}
]
With this information I need to enrich each of the objects with person details, so the final result will be like this:
[
{
"orderId": 123,
"quantity": 5,
"buyerId": "84aa820f-2301-4d01-8c4c-2b71204da7dd",
"buyer": {
"personId": "84aa820f-2301-4d01-8c4c-2b71204da7dd",
"name": "Johny",
"surname": "Bravo"
}
},
{
"orderId": 124,
"quantity": 5,
"buyerId": "7158a748-dfd0-47e5-b620-e8ca4d3ac84d",
"buyer": {
"personId": "7158a748-dfd0-47e5-b620-e8ca4d3ac84d",
"name": "Felica",
"surname": "Good"
}
}
]
Is that possible to achieve this using enrichers?
Well, ContentEnricher
is exactly for this reason. You receive a message, send enrich request, wait of reply and produce output.
What you are asking about enriching JSON string is a bit unusual task and comes out of Spring Integration scope. I can only suggest to implement some service method to accept that JSON, to do parsing, iteration and modification. In the end of method you would produce a desired JSON. This one is really can be used from the @ServiceActivator
to listen for the enrich request message channel and return reply to the replyChannel
header.
How to do a JSON parsing and so on seems for me is out of the question scope. However I can suggest to take a look into the JsonToObjectTransformer
to get a List
of some POJOs to iterate and modify. However a simple Map
for each record is sufficient as well. For converting back from the List<Map>
to JSON you can consider to use ObjectToJsonTransformer
.
UPDATE
If you are able to covert that JSON to the List<POJO>
or List<Map>
, then the splitter-aggregator
pattern is for you.
I would make it like this, though:
@Bean
public IntegrationFlow enrichJson() {
return f -> f
.transform(Transformers.fromJson(List.class))
.split()
.channel(c -> c.executor(Executors.newCachedThreadPool()))
.enrich(e -> e
.requestPayloadExpression("payload.buyerId")
.requestChannel(getBuyerChannel())
.propertyExpression("buyer", "payload"))
.aggregate()
.transform(Transformers.toJson());
}
UPDATE2
If you'd prefer to obtain list of buyers in one go through the data base, for example, then let's consider this solution.
If your original list is really JSON, we can do something like this:
.enrich(e -> e
.requestPayloadExpression("#jsonPath(payload, '$.buyerId')")
.requestChannel(getBuyersChannel())
.headerExpression("buyers", "payload"))
The jsonPath
extracts all the buyerId
properties and produces a List
of their values.
The getBuyersChannel
flow must perform some query and return, example, a Map<String, String>
- buyerId -> buyer_as_json
. This result is going to be stored in the mentioned above buyers
header.
After this .enrich()
you need to write a custom .transform()
code and iterate over that buyers
header and perform String.replaceFirst("(\" + buyer.getKey() + \",)", "$1" + buyer.getValue())
.
If your JSON is already List<POJO>
or List<Map>
, you can use similar approach but using Java 8 Streams:
.<List<Map<?, ?>>>requestPayload(m ->
m.getPayload()
.stream()
.map(entry -> entry.get("buyerId"))
.collect(Collectors.toList()))
The result from the DB could be like Map<String, Map<?, ?>>
and you can perform similar iteration to extend maps for orders with their buyers.