I am having trouble passing valid JSON between two different Java AWS Lambda functions. The first function generates rawJson "String" that is formatted like this:
rawJson: [
{
"id": 1,
"createdOn": 1535177185000,
"text": "test text"
}
]
This is passed to a second Lambda function:
request.withFunctionName(FUNCTION_NAME).withPayload(rawJson);
awsLambdaClient.invoke(request);
At the beginning of the second Lambda function, I print the value of the input Object:
inputObject: [{id=1, createdOn=1535177185000, text=test text}]
The quotes have been stripped and this is no longer valid JSON. Any attempt to map this back to my POJOs (or to even have my Lambda function accept a "String" like it should, instead of an "Object") results in a JSON-related exception.
Why is my valid JSON becoming malformed between the two Lambdas?
This was my fault. Like I mentioned, I had a RequestHandler like this:
RequestHandler<Object, Void>
That wasn't necessary. Lambda is smart enough on its own to serialize and deserialize my objects. Works fine with my code updated to:
RequestHandler<List<MyClass>, Void>
Related
I have a JSON which has an attribute with its List type. Can someone help me on how to read the value in Apache Velocity template? Following is an example of JSON. The challenge is to read the list of University from JSON and iterate through it.
{
"StudentName":"XYZ",
"List<Univesity>": [
{
"Name": "NYU",
"City": "NY",
"Country":"US",
} ]
}
The solution is dependent upon the JSON library you use, but for many of them, the following code should work:
#set( $universities = $document.get('List<University>') )
#foreach( $university in $universities )
... do something ...
#end
The main point to note here is that you can call any Java method on the object you get.
Also, if the security uberspector is not present, for debugging purposes you can display the Java class name of any object in the context, for instance: $document.class.name should display, in your case, something like com.fasterxml.jackson.databind.node.ObjectNode.
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 #EnableInegrationand 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.
i'm trying to send JSON object to my free marker, but i getting error while testing JUnit
here is my object
{
"filename": "test",
"orderId": "123435",
"orderDate": "23.09.2020г.",
"itemsCount": "4",
"items": [
{
"itemName": "ТВ Приставка 400",
"itemCount": "2 шт Х 400₽",
"itemSum": "800.00"
}
],
"totalSumm": "3000.00"
}
here is my error:
FreeMarker template error:
The value you try to list is an extended_hash+string (org.camunda.bpm.engine.impl.util.json.JSONArray wrapped into f.e.b.StringModel), thus you must specify two loop variables after the "as"; one for the key, and another for the value, like <#... as k, v>).
how could i resolve it?
items is a arrays of JSON objects
FreeMarker knows nothing about org.camunda.bpm.engine.impl.util.json.JSONArray, so it doesn't see it as a list-like thing (as a sequence, as it's called in FTL). So you can do one of these:
Using the objectWrapper Configuration setting, you teach FreeMarker how to treat JSONArray as a list. (You can find more about custom ObjectWrapper-s elsewhere.) Then you can just #list such objects, and use all the other operations applicable to sequences.
Or, you call the Java API-s of JSONArray from the template. That will be less convenient of course, but requires no prior investment.
I'm experiencing a different json structure of a returned list when running on Tomcat.
{
"apartment": [
{
"apartmentName": "ABC",
"id": "1"
},
{
"apartmentName": "DEF",
"id": "2"
}
]
}
Since the controller is returning List of apartments; ideally it should start with square braces [] instead of curly braces. This results into JSON parser on client side think that it's a JSONObject instead of JSONArray. I am not sure how to fix this. Below are the various POM dependency and their version.
Tomcat version I am using is 7.0.67
jersey-server-1.19
jersey-servlet-1.19
jersey-json-1.19
jersey-spring-1.19
jersey-core-1.19
This is because you're returning a List of Apartments from your servlet. You can fix this by returning an array like this
return new Apartment[]; // Collect all apartment objects and return it as an array
and Jackson will convert it accordingly. In your case I think you have Java object that has a parameter called apartments of type List. I assume you're using Jackson as the provider.
When Parsing JSON I normally just constuct an object and use the gsonlibrary to parse my String into that object.
However, I now find myself with a rather complex response which consists of many elements each with sub elements of objects and arrays and arrays of objects. It looks something like this...
{
"type": "thetype",
"object":{
"text": "texthere",
"moretext": "more here"
},
...,
...,
...,
...,
"fieldIwant": [
{
"object":"object!"
},
....
....
{
"object":"object!"
},
]
}
The thing is, I'm only really interested in fieldIwantand nothing else. Is there not a way in Java for me to just extract that field and work with it alone and not all this other dead weight I do not need?
According to this http://sites.google.com/site/gson/gson-design-document it looks like gson does this for you by default.
When you are deserializing a Json string into an object of desired type, you can either navigate the tree of the input, or the type tree of the desired type. Gson uses the latter approach of navigating the type of the target object. This keeps you in tight control of instantiating only the type of objects that you are expecting (essentially validating the input against the expected "schema"). By doing this, you also ignore any extra fields that the Json input has but were not expected.
In other words, it doesn't deserialize any of the fields you don't need. You should be good to go.
You can use the low level JsonParser API
JsonObject jsonObject = new JsonParser().parse(json).getAsJsonObject();
yourArray = new Gson().fromJson(jsonObject.get("fieldIwant"), yourArrayType);
Alternatively you can create an ExclusionStrategy to use with a GsonBuilder