No puedo pensar en SPEL para cargas útiles de mensajes. Quiero extraer datos de ciertos campos de la carga útil de mi mensaje, que es esencialmente el siguiente JSON convertido a Map<String, Object> y pasado 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":[

    ],
  }
}

Estoy interesado en tres valores anidados aquí que estoy tratando de recuperar a través de las siguientes expresiones

issueDataMap = {LinkedHashMap@4867}  size = 3
 "name" -> "#payload['fields']['summary']"
 "description" -> "#payload['description']"
 "text3" -> "#payload['key']"

Recibo este error cuando se aplica la expresión.

org.springframework.expression.spel.SpelEvaluationException: EL1012E: Cannot index into a null value

Así es como obtengo la carga útil en el argumento as de mi transformador

@Transformer
public Map<String, Object> generateCardData(Map<String, Object> payload,
                                            @Header("X-UPSTREAM-WEBHOOK-SOURCE") String projectId) {

Seguido por

StandardEvaluationContext evaluationContext = evaluationContextFactory.getObject();

Y así es como lo evalúo

new SpelExpressionParser().parseExpression(issueDataMap.get(key)).getValue(
                            evaluationContext, payload, String.class)));

Tengo la aplicación anotada con @SpringBootApplication y @EnableInegration y autowire una instancia de IntegrationEvaluationContextFactoryBean para obtener el StandardEvaluationContext

También probé la variante

issueDataMap = {LinkedHashMap@4867}  size = 3
 "name" -> "payload['fields']['summary']"
 "description" -> "payload['description']"
 "text3" -> "payload['key']"

Pero luego me sale

EL1008E: Property or field 'payload' cannot be found on object of type 'java.util.LinkedHashMap' - maybe not public or not valid?
1
Anadi Misra 23 ene. 2021 a las 10:45

1 respuesta

La mejor respuesta

En primer lugar, no está claro por qué se usaría SpEL en el código manualmente, cuando tiene acceso completo al objeto. Además, debe tener en cuenta que crear StandardEvaluationContext, analizar una expresión y evaluarla en cada llamada es una sobrecarga de rendimiento. Probablemente solo necesite cambiar su firma generateCardData() para aceptar un resultado de la expresión en lugar de todo el mapa. Consulte el atributo @Payload.expression.

De todos modos, esto no es lo que le gustaría escuchar sobre su problema. Y esta aqui: getValue(evaluationContext, payload, String.class))). El objeto de evaluación raíz es su payload - un Map. Entonces, lo que solo necesita asumir en la definición de su expresión es que obtiene acceso a ese objeto raíz. Por lo tanto, las expresiones deben ser así: fields.summary, description, key.

Por lo general, ve en los documentos y ejemplos un payload (o header) como primer token en la expresión. Eso es solo porque Spring Integration usa un Message como un objeto raíz para que las expresiones evalúen.

Ahora en lo que respecta al rendimiento. Incluso si su lógica para seleccionar una expresión por alguna clave en tiempo de ejecución (issueDataMap.get(key)), aún podría analizarla solo una vez.

1
Artem Bilan 25 ene. 2021 a las 13:42