We have some web services which are being consumed by mobile clients , in which the mobile clients make some request's and we return response to them. Somehow if the client make any invalid request we throw Custom Exceptions .But recently the mobile client has made some request which was out of range for Long variable. The client has different variables for ex ::
{
"accountId":"343"
"Amount":"90909090909090909090"
}
In case of the value for accountId or Amount are made more than 19 digits we get HttpMessageNotReadable exception as the range is out of long value. But from exception i am not able to fetch for which variable the exception has been raised whether for accountId or Amount. From the exception i am getting this information in _path variable but i am not able to fetch it.
And in the path variable i get something like::
[com.Upload["AccountInfo"], com.Info["Account"]]
Does somebody know how to fetch this information.
The following code prints out the field which causes the exception.
InvalidFormatException invalidFormatException = (InvalidFormatException) exception
.getCause();
System.out.println(invalidFormatException.getPath().get(0)
.getFieldName());
#ArunM's answer works as long as the field is in 1st level viz the example given by OP.
But what happens when the field is in nested json? say paymentType has wrong value in the following example?
{
"userType": "CUSTOMER",
"payment": {
"amount": 123456,
"paymentType": "INTERNET_BANKING"
}
}
In the above example, if there's anything wrong with the value of userType, there will be just one element in _path.
But if any value inside the payment is wrong, say for example paymentType, there will be multiple elements in the _path variable. Each element representing the hierarchical attribute.
So for paymentType, _path will have 2 elements as illustrated below:
_path[0].fieldName = "payment"
_path[1].fieldName = "paymentType"
Hence the correct approach is to get the last element in _path as shown below. If needed, we can build the complete path by using all the elements.
InvalidFormatException ifx = (InvalidFormatException) exception.getCause();
System.out.println(ifx.getPath().get(ifx.size() - 1).getFieldName());
This I believe is the right approach to get the invalid attribute name.
Related
I am new to using springboot and swagger, so not very familiar with this stuff. But what I want to do is to input a JSONArray into a swagger API and get the input into a controller. So, I have the following controller code:
#RestController
public class NameRegisterController{
#Autowired
private NameRegisterService service;
#Postmapping(path="/control")
public void NameRegisterAdd(#RequestParam JSONArray NameList)
{
service.addNames(NameList);
}
}
Here, addNames is a function which takes JSONArray as input. When I go to the swagger API, I add the input as:
["name1","name2","name3"]
Unfortunately, when I execute, I get the error
"ConversionFailedException: Failed to convert from type[java.lang.String] to type [#org.springframework.web.bind.RequestParam org.json.JSONArray] for value 'name1'; nested exception is org.json.JSONException: JSONArray test must start with '[' at 1 [character 2 line 1"
I don't get it because the first character of my input is "[" as put in the swagger API. Would be very grateful if someone can provide some help.
My swagger is in my work environment, so am inserting similar pictures from the internet.
The first pic is what I get. The second pic is what I want
String Array
Frontend Pass with HTTP request
[“a”,”b”,”c”]
Backend receive in controller methods
#RequestParam String[] ids
#RequestParam List<String> ids
And I dont see you defining which request parameter name it should be looking at?
Example:
public String inputControllerMethod(#RequestParam(value="myParam") List<String> myParam){
}
=== Edited ===
You can't.
Using the [Add String Item] button you must insert 1 String at a time.
However if they are not Strings, but rather an Array of Objects, then swagger allows you to write the array:
Use this https://editor.swagger.io/#/ to see an example.
Documentation: https://swagger.io/docs/specification/2-0/describing-parameters/
Your other option also if you really dont want the user to enter and you are limited by specific options is an enum:
parameters:
- name: "status"
in: "query"
description: "Status values that need to be considered for filter"
required: true
type: "array"
items:
type: "string"
enum:
- "placed"
- "approved"
Then the user simply selects multiple/all options:
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 am taking a JSON file as input for a class and parsing the values using gson through respective data classes.
I want to call a function that takes a String value as an argument.
The string value allowed is decided from the values parsed from JSON file. Can I somehow check for that string value passed to the function at compile-time & give an error at compile-time?
Or If I can allow only certain values in the argument for the function based on the values from JSON
Detailed Explanation of use case:
I am building a SDK in which a the person using sdk inputs json String. The json is standardised and is parsed in my code.
{
"name": "Test",
"objects": [
{
"name": "object1",
"type": "object1"
}
]
}
Here name values and other values may vary based on the input by the developer using it but key remains same. But we need to call a function using the value in objects name parameter.
fun testMethod(objectName:String)
So developer calls the testMethod as testMethod(object1).
I need to validate object1 parameter based on json but is there any way possible restricting the test method parameter to object1 only & give error at compile time if the developer calls testMethod(obj1)
Right now I parse JSON & have checks inside the testMethod()
Sure it's possible to do, but somehow in different way, that you described. First of all, as you already mentioned this behavior could be done easily. For this purpose we have Objects.requireNotNull() or Guava.Preconditions(). At the same way you can define you checking but this will work on runtime only.
To do in compile time, you need to create Annotation Preprocessor. The same, as did in different libraries, and one of them, could be Lombok, with their NotNull and Nullable. Android annotation just provide mark and bound for IDE warning, but in their case they adding NotNull checking and throw exception for every annotation usage during compile time.
It's not an easy way, but it's what you are looking for.
No, it's impossible check it in compiler time. It's string handling, as numeric calculation.
In my app, I convert string to JSON and JSON to string, passing class descriptor. My aim is record JSON string in a text file to load in SQLite database. This code I've run in my desktop computer not in Android.
data class calcDescr (
...
)
val calc = CalcDescr(...)
// toJson: internal Kotlin data to JSON
val content = Gson().toJson(calc)
//==================
// Testing validity
// ================
// fromJson: JSON to internal Kotlin data.
// It needs pass the class descriptor. Uses *Java* token, but it's *Kotlin*
var testModel = Gson().fromJson(content, CalcDescr::class.java)
// toJson: internal Kotlin data to JSON again
var contentAgain = Gson().toJson(testModel)
// shoul be equal!
if (content == contentAgain) println("***ok***")
In my file, I write the variable content in a file
I have a config file:
company=My Company
num_users=3
user={
name="John"
age=24
}
user={
name="Anna"
age=27
}
user={
name="Jack"
age=22
}
I'm trying to parse this config file using Java. I tried java.util.Properties but I don't know how to get each single user data.
I still can get company property value using getProperty method.
Please help me with this.
Thanks!
Nothing wrong with having same property name with different value but getProperty(String key) can not differentiate between them as it will return the first value.
Secondly you can not access nested property directly.Right now here getProperty will return whole String including {} as value because that's what your value contains.You may get value and perform some operations to fetch values from that whole String.Because property file should have only key=value format means left hand side should be key and right hand side should be value.That's it.
If you want to store values as you have specified in your code you should go for JSON format than you can store whole JSON data to file and get it back from the file while you want to use it.
If you use java.util.Properties class to load the config file, you will get the following result:
{company=My Company, age=22, user={, name="Jack", }=, num_users=3}
The reason, you could refer to the javaDoc for "public void load(Reader reader)" method of Properties class.
Since you don't describ the detailed syntax format for your config file,
base on your example input, the following sample code could retrive the name=value correctly:
String reg="(\\w+)\\s*=\\s*((?>\\{[^\\{\\}]*\\})|(?>.*$))";
Pattern pMod = Pattern.compile(reg, Pattern.MULTILINE);
Matcher mMod = pMod.matcher(line);
while (mMod.find()) {
System.out.println(mMod.group(1));
System.out.println(mMod.group(2));
}
The output is:
company
My Company
num_users
3
user
{
name="John"
age=24
}
user
{
name="Anna"
age=27
}
user
{
name="Jack"
age=22
}
I read all my likes using FQL with Spring Social Facebook
here is the method:
public List<LikeObject> startF(String token){
Facebook facebook = new FacebookTemplate(token);
FacebookProfile profile = facebook.userOperations().getUserProfile();
//System.out.println(facebook.isAuthorized());
System.out.println("Authenticcated user: "+profile.getFirstName()+" "+profile.getLastName());
PagedList<String> friendListIds = facebook.friendOperations().getFriendIds();
List<LikeObject> resultsLikes = facebook.fqlOperations().query("SELECT object_id, object_id_cursor,object_type, post_id, post_id_cursor, user_id "+
"FROM like "+
"WHERE user_id =me() ", new FqlResultMapper<LikeObject>(){
public LikeObject mapObject(FqlResult result) {
LikeObject like = new LikeObject();
like.object_id = result.getString("object_id");
like.object_id_cursor = result.getString("object_id_cursor");
like.object_type = result.getString("object_type");
like.post_id = result.getString("post_id");
like.post_id_cursor = result.getString("post_id_cursor");
like.user_id = result.getString("user_id");
return like;
}
});
return resultsLikes;
}
Here results:
LikeObject [object_id=578416.., object_id_cursor=null,
object_type=status, post_id=, post_id_cursor=null, user_id=10217..]
Then I would like to parse like.object_id and convert it to java object. But I've no idea how to do it using spring social facebook.
I've tried facebook.fetchObject(like.object_id, PostType.STATUS) . But it seems to be a wrong way.
Is there any possible way to parse an "object_id" in spring social without parsing raw JSON response from GET query?
I've tried this:
LinkPost post = facebook.fetchObject(obj_id, LinkPost.class);
I believe that obj_id has type link, I've checked it
and it cause following exception:
Exception in thread "main" org.springframework.http.converter.HttpMessageNotReadableException: Could not read JSON: Unexpected token (END_OBJECT), expected FIELD_NAME: missing property 'postType' that is to contain type id (for class org.springframework.social.facebook.api.LinkPost)
at [Source: java.io.ByteArrayInputStream#6ca79a6a; line: 1, column: 11114]; nested exception is com.fasterxml.jackson.databind.JsonMappingException: Unexpected token (END_OBJECT), expected FIELD_NAME: missing property 'postType' that is to contain type id (for class org.springframework.social.facebook.api.LinkPost)
at [Source: java.io.ByteArrayInputStream#6ca79a6a; line: 1, column: 11114]
at org.springframework.http.converter.json.MappingJackson2HttpMessageConverter.readJavaType(MappingJackson2HttpMessageConverter.java:171)
at org.springframework.http.converter.json.MappingJackson2HttpMessageConverter.read(MappingJackson2HttpMessageConverter.java:163)
at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:94)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:491)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:460)
at org.springframework.web.client.RestTemplate.getForObject(RestTemplate.java:228)
at org.springframework.social.facebook.api.impl.FacebookTemplate.fetchObject(FacebookTemplate.java:202)
at com.repost.facebook.FbConnection.getLikedPosts(FbConnection.java:58)
at com.repost.facebook.MainClass.main(MainClass.java:15)
I'm still unclear what you mean by "parse". But let me attempt to answer this anyway...
I think you simply want to be able to fetch the object as a Post (or LinkPost) object...is that right? If so, then there's some special magic that I unfortunately had to bake into the API to be able to both grab the post type and do polymorphic deserialization into a specific type of Post (e.g., LinkPost, StatusPost, etc).
You can see the setup taking place in https://github.com/SpringSource/spring-social-facebook/blob/master/spring-social-facebook/src/main/java/org/springframework/social/facebook/api/impl/FeedTemplate.java. In the deserializePost() method, you see that I read the "type" property and copy it into a new "postType" field. One of those fields is used to populate the Post's type property and the other is used to determine which specific subclass of Post should be created. It's a hack to work around a problem I had with Jackson 1.9.x...I think that Jackson 2 will make that hack unnecessary, but I've not tried it yet.
Therefore, I see only one practical way of doing this: Don't do all the work yourself. Instead use facebook.feedOperations().getPost(objectId). It knows how to do the magic under the covers to give you a Post object. From there, if you know the specific kind of Post, you can cast it as (and if) needed to LinkPost, StatusPost, etc.
The only other option I see is to go even lower level and make the request through facebook.restOperations() and to handle the binding for yourself. That's obviously a lot more work on your part.