Not able to get my head over SPEL for Message payloads. I want to extract data from certain fields of my message payload which is essentially the following JSON converted to Map<String, Object>
and passed to a @Transformer
{
"expand":"renderedFields,names,schema,transitions,operations,editmeta,changelog,versionedRepresentations",
"id":"14730",
"self":"https://jira.foo.com/rest/api/2/issue/14730",
"key":"SDP-145",
"fields":{
"issuetype":{
"self":"https://jira.foo.com/rest/api/2/issuetype/10200",
"id":"10200",
"description":"gh.issue.epic.desc",
"iconUrl":"https://jira.foo.com/ghanghor/viewkaka?size=xsmall&kakaId=10501&kakaType=issuetype",
"name":"Epic",
"subtask":false,
"kakaId":10501
},
"priority":{
"self":"https://jira.foo.com/rest/api/2/priority/3",
"iconUrl":"https://jira.foo.com/images/icons/priorities/major.svg",
"name":"Major",
"id":"3"
},
"labels":[
"Lizzy",
"kanban",
"rughani"
],
"updated":"2021-01-21T10:33:38.000+0000",
"status":{
"self":"https://jira.foo.com/rest/api/2/status/1",
"description":"The issue is open and ready for the assignee to start work on it.",
"iconUrl":"https://jira.foo.com/images/icons/statuses/open.png",
"name":"Open",
"id":"1",
"statusCategory":{
"self":"https://jira.foo.com/rest/api/2/statuscategory/2",
"id":2,
"key":"new",
"colorName":"blue-gray",
"name":"To Do"
}
},
"summary":"new epic for Tazzy",
"creator":{
"self":"https://jira.foo.com/rest/api/2/user?username=skadmin",
"name":"skadmin",
"key":"skadmin",
"emailAddress":"Lizzy.t@foo.com",
"displayName":"Lizzy Rughani",
"active":true,
"timeZone":"Asia/Kolkata"
},
"subtasks":[
],
}
}
I'm interested in three nested values here which I'm trying to fetch via following expressions
issueDataMap = {LinkedHashMap@4867} size = 3
"name" -> "#payload['fields']['summary']"
"description" -> "#payload['description']"
"text3" -> "#payload['key']"
I get this error when the expression is applied
org.springframework.expression.spel.SpelEvaluationException: EL1012E: Cannot index into a null value
Here's how I get the payload in the as argument to my transformer
@Transformer
public Map<String, Object> generateCardData(Map<String, Object> payload,
@Header("X-UPSTREAM-WEBHOOK-SOURCE") String projectId) {
followed by
StandardEvaluationContext evaluationContext = evaluationContextFactory.getObject();
and here's how I evaluate it
new SpelExpressionParser().parseExpression(issueDataMap.get(key)).getValue(
evaluationContext, payload, String.class)));
I have the app annotated with @SpringBootApplication
and @EnableInegration
and I autowire an instance of IntegrationEvaluationContextFactoryBean
to get the StandardEvaluationContext
I also tried the variant
issueDataMap = {LinkedHashMap@4867} size = 3
"name" -> "payload['fields']['summary']"
"description" -> "payload['description']"
"text3" -> "payload['key']"
but then I get
EL1008E: Property or field 'payload' cannot be found on object of type 'java.util.LinkedHashMap' - maybe not public or not valid?
First of all it is not clear why would one use SpEL in the code manually, when you have full access to the object. Plus you should keep in mind that create StandardEvaluationContext
, parse an expression and evaluate it on every single call is kinda an overhead by performance. You probably just need to change your generateCardData()
signature to accept a result of the expression instead of the whole map. See @Payload.expression
attribute.
Anyway this is not what you would like to hear for your problem. And it is here:
getValue(evaluationContext, payload, String.class)))
. The root evaluation object is your payload
- a Map
. So, what you just need to assume in your expression definition that you get access to that root object. Therefore expressions must be like this: fields.summary
, description
, key
.
You typically see in the docs and samples a payload
(or header
) as a first token in the expression. That is just because Spring Integration uses a Message
as a root object for expressions to evaluate.
Now in regards to performance. Even if your logic to select an expression by some key at runtime (issueDataMap.get(key)
), you still could parse it only once.