Read Facebook Post-related Object with Spring Social - java

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.

Related

Convert XML to and from Java

I am trying to get the XML response from the rest API. And I am getting JSON response for all customers and XML for single customer from API. PFB the screen print for the case for both cases:
Case 1: When URL= http://localhost:8080/spring-crm-rest/api/customers/ then I am getting JSON response
JSON Response
Case 2: When URL = http://localhost:8080/spring-crm-rest/api/customers/1 then I am getting XML response
XML Response
Please find below the URL for the complete code to replicate the same at your end.
Link for the code: https://drive.google.com/file/d/1fd7DyUsfOvY4fX0nm6j4fzrwxHyg9ZGz/view?usp=sharing
Ok I think the reason why that happens is the following:
the path /spring-crm-rest/api/customers/ has return type List<Customer> -> default java List as top level -> json result
while /spring-crm-rest/api/customers/1 has return type Customer as top level which has the javax.xml.bind annotations -> xml result
Changing this may be a bit tricky but these are some possible things you can try:
specifically set the content type of the endpoint like this: #GetMapping(produces = {"application/json"})
removing the #Xml.* annotations -> spring will can serialize the class without any annotations but without them you have less of a control over the resulting json (e.g. renaming fields, etc). Depending on your usecase it might not be needed though

Input a JSONArray into swagger API for a springboot controller

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:

Compile time check while passing values to a function in Kotlin Android

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

Accessing JWT nested claims with jose4j

I am having trouble accessing nested claims from a JWT using jose4j. I have a JWT whose claim set looks like this:
{
"iss": "awesome.issuer",
"iat": 1300819370,
"exp": 1300819380,
"clm": "string claim",
"sub": "batman",
"context": {
"username": "mpdavis",
"firstName": "Michael",
"lastName": "Davis
}
}
I am running into issues when I try to access and of the nested claims inside the context claim. I can access top level claims easily with the getClaimValue.
private String qsh;
qsh = jwtClaims.getClaimValue("qsh", String.class);
It seems like I have two options if I want to get a nested claim.
The first option is to find a way to return the context claim as a Map<String,Object> and pull each claim out of that object. The other option is to use flattenClaims to flatten all of the claims into a Map<String,List<Object>> and grab the first object off of the map for the nested claims.
Neither one of these options seem particularly resilient if the service granting these JWTs alters the schema very much.
Is there a better way?
That's about right.
You can get the claim value as a Map and access its content like this (or iterate on it).
#SuppressWarnings("unchecked")
Map<String,String> context = claims.getClaimValue("context", Map.class);
String username = context.get("username");
String firstName = context.get("firstName");
Using flattenClaims might look something like this:
Map<String,List<Object>> flattened = claims.flattenClaims();
String username = (String)flattened.get("context.username").iterator().next();
String firstName = (String)flattened.get("context.firstName").iterator().next();
Or you could iterate the whole thing and convert it to whatever data structure makes sense for your application.
You could likely make things more resilient to changes in the claims JSON with things like isClaimValueOfType(...) and hasClaim(...) and things like that on JwtClaims.
Or you can also use getRawJson() on JwtClaims and pass the JSON to the JSON processor of your choice, if you want.

Get path variable out of HttpMessageNotReadable exception

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.

Categories

Resources