Spring MVC + RequestParam as Map + get URL array parameters not working - arrays

I'm currently working on an API controller. This controller should be able to catch any - unknown - parameter and put it in a Map object. Now I'm using this code to catch all parameters and put them in a Map
public String processGetRequest(final #RequestParam Map params)
Now the url I call is as follows:
server/api.json?action=doSaveDeck&Card_IDS[]=1&Card_IDS[]=2&Card_IDS[]=3
Then I print out the parameters, for debugging purposes, with this piece of code:
if (logger.isDebugEnabled()) {
for (Object objKey : params.keySet()) {
logger.debug(objKey.toString() + ": " + params.get(objKey));
}
}
The result of that is:
10:43:01,224 DEBUG ApiRequests:79 - action: doSaveDeck
10:43:01,226 DEBUG ApiRequests:79 - Card_IDS[]: 1
But the expected result should be something like:
10:43:XX DEBUG ApiRequests:79 - action: doSaveDeck
10:43:XX DEBUG ApiRequests:79 - Card_IDS[]: 1
10:43:XX DEBUG ApiRequests:79 - Card_IDS[]: 2
10:43:XX DEBUG ApiRequests:79 - Card_IDS[]: 3
Or atleast tell me that the Card_IDS is an String[] / List<String> and therefore should be casted. I also tried casting the parameter to a List<String> manually but that does not work either:
for (Object objKey : params.keySet()) {
if(objKey.equals(NameConfiguration.PARAM_NAME_CARDIDS)){ //Never reaches this part
List<String> ids = (List<String>)params.get(objKey);
for(String id : ids){
logger.debug("Card: " + id);
}
} else {
logger.debug(objKey + ": " + params.get(objKey));
}
}
Could someone tell me how to get the array Card_IDS - It must be dynamically - from the Map params by using the NameConfiguration.PARAM_NAME_CARDIDS?

When you request a Map annotated with #RequestParam Spring creates a map containing all request parameter name/value pairs. If there are two pairs with the same name, then only one can be in the map. So it's essentially a Map<String, String>
You can access all parameters through a MultiValueMap:
public String processGetRequest(#RequestParam MultiValueMap parameters) {
This map is essentially a Map<String, List<String>>. So parameters with the same name would be in the same list.

Related

Receiving errors on Apex class to match fields for two different custom objects

I've been stuck for 18 hours on this apex class. I would really appreciate some help to figure out what's wrong. Basically this code should match the fields between two objects and I don't know why I'm receiving the following errors:
Missing return statement required return type: String - Line 2
Expecting '}' but was: 'for' - Line 26
The output should show that when location and position title from Candidate object matches location and title from Position object then it will just show those values that match on a data table in a lightning web component I made on Visual Studio.
I'd like some help improving this code so I can run it on the dev console.
public class Matchposition {
public static String matchPositionsWithCandidate() {
Set<String> statuses = new Set<String> {'New', 'Open'};
List<Position__c> openPositions = [SELECT Id, Name, Location__c, Status__c FROM Position__c WHERE Status__c IN :statuses];
//system.debug(openPositions);
Set<String> openPositionAndLocation = new Set<String>();
Map<String, Position__c> openPositionMap = new Map<String, Position__c>();
for (Position__c position : openPositions) {
openPositionMap.put(position.Name + '-' + position.Location__c, position);
openPositionAndLocation.add(position.Name + '-' + position.Location__c);
}
}
//for(String key : openPositionMap.keySet()) {
// system.debug('*** Start ***');
// system.debug('key :' + key);
// system.debug('value :' + openPositionMap.get(key));
// system.debug('*** End ***');
//}
Map<String, List<Candidate__c>> candidatesMap = new Map<String, List<Candidate__c>>();
List<Candidate__c> candidates = [SELECT Position__c, Location__c, Mobile__c, First_Name__c, Last_Name__c, Email__c FROM Candidate__c];
for (Candidate__c candidate : candidates) {
if(candidatesMap.containsKey(candidate.Position__c + '-' + candidate.Location__c)) {
candidatesMap.get(candidate.Position__c + '-' + candidate.Location__c).add(candidate);
} else {
candidatesMap.put(candidate.Position__c + '-' + candidate.Location__c, new List<Candidate__c> {candidate});
}
}
system.debug('*************** OPEN POSITIONS ***************');
for (String key : openPositionAndLocation) {
system.debug('====> ' + openPositionMap.get(key).Name);
if(candidatesMap.containsKey(key)) {
system.debug('***** Candidates *****');
for(Candidate__c candidate : candidatesMap.get(key)) {
system.debug('------- Name : ' + candidate.First_Name__c + ' ' + candidate.Last_Name__c);
system.debug('------- Email : ' + candidate.Email__c);
system.debug('------- Mobile : ' + candidate.Mobile__c);
}
} else {
system.debug('********* No Candidates');
}
}
One issue you certainly have, apropos of nothing else, is overall structure. Removing the actual lines of code, here's how your class is laid out now:
public class Matchposition {
public static String matchPositionsWithCandidate() {
// Code here
}
// more code here - problem!
}
You have much of your logic loose in the body of your class, which is not valid in Apex. Additionally, the code in the class body references variables declared inside the method matchPositionsWithCandidate(), which are scoped (visible) to that method.
matchPositionsWithCandidate() is also declared to return a string, but in fact returns nothing at all.
Since you're not returning any data anywhere, one step you can take to try to get this code running is to ensure that all of your logic is inside the scope (the curly braces) of the method matchPositionsWithCandidate(), and declare that method to return void, not String.
You may also have unbalanced braces - it looks like there is one missing after the final else - if it wasn't simply omitted in the copy and paste.
I'm not sure why this code exists. While much of the logic is correct, it makes far more sense to model your data with a relationship between Candidate__c and Position__c, rather than just storing a name in both positions. Then, you don't need any "matching" code at all - just a simple SOQL relationship query.

how to retrieve values of the map returned by jsonPath().getMap methods of rest assured

how to retrieve values of the map returned by jsonPath().getMap methods of rest assured
I am trying to get the response on below api in Map, which I am able to successfully get but when I try to access the value of key "id" in the below code, I get cast Error on line "String id = test.get("id");"
public void testRestAssured() {
Response apiResponse = RestAssured.given().get("https://reqres.in/api/user/2");
Map<String, String> test = apiResponse.jsonPath().getMap("data");
System.out.println(test);
String id = test.get("id");
System.out.println("ID : " + id);
}
Error
java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
I tried to do many things like
String id = test.get("id").toString();
or
String id = String.valueOf(test.get("id"));
but nothing helped in resolution
api response is as follows
{
"data": {
"id": 2,
"name": "fuchsia rose",
"year": 2001,
"color": "#C74375",
"pantone_value": "17-2031"
}
}
Try the below code, it is working fine for me:
Response apiResponse = RestAssured.given().get("http://reqres.in/api/user/2");
Map<Object, Object> test = apiResponse.jsonPath().getMap("data");
System.out.println(test);
String id = test.get("id").toString();
System.out.println("ID : " + id);
The changes I have done is: change Map of (String, String) to Map (Object, Object) because we know that each key of map is string but value could be of any data type.
I hope it will solve your problem.
Correct code is
Response apiResponse = RestAssured.given().get("http://reqres.in/api/user/2");
Map<Object, Object> test = apiResponse.jsonPath().getMap("data");
System.out.println(test);
for (Object e : test.keySet()) {
System.out.println(" Key is " + e + " , value is " + test.get(e));
simply try this:
import com.jayway.restassured.path.json.JsonPath;
JsonPath extractor = JsonPath.from(apiResponse.toString());
String id = extractor.getString("data.id");
You should define Object for map value. Because your json values are different types (String and int).
// define Object type for map values
Map<String, Object> test = apiResponse.jsonPath().getMap("data");
// use casting for assigning
int id = (int) test.get("id");
Do you really need to make from your response map object?
If not you can use this one:
String id = RestAssured.given().get("https://reqres.in/api/user/2")
.then().extract().jsonPath().getString("data.id");

Cannot update request parameters in custom Search Component

I have written Solr Custom Search Component as described here
My goal is to update the query parameters, specifically to remove Unicode Quotes as early as possible in the pipeline.
However, after intercepting the request and editing the parameters, the request does not seem to update.
public void updateSolrRequest(SolrQueryRequest req) {
SolrParams params = req.getParams();
System.out.println( "params = " + req.getParamString());
String newQuery = params.get(CommonParams.Q);
newQuery = newQuery.toString().replaceAll("[A]","XXX");
ModifiableSolrParams newParams = new ModifiableSolrParams(params);
newParams.remove(CommonParams.Q);
newParams.add(CommonParams.Q, newQuery);
// all good to here, the next line should
// overwrite the old params with the new ones
// but it does not
req.setParams(newParams);
System.out.println("newQuery = " + newQuery);
System.out.println("newParams = " + newParams.get(CommonParams.Q));
System.out.println("updated req = " + req.getParamString());
}
Output
params = q=“A+Game+of+Thrones“&defType=dismax&q.alt=thrones&fq=Game&_=1548262845155
newQuery = “XXX Game of Thrones“
newParams = “XXX Game of Thrones“
updated req = q=“A+Game+of+Thrones“&defType=dismax&q.alt=thrones&fq=Game&_=1548262845155
The problem here is, that
public String getParamString() {
return origParams.toString();
}
is actually returning original params, which aren't affected by setParams called
/** Change the parameters for this request. This does not affect
* the original parameters returned by getOriginalParams()
*/
void setParams(SolrParams params);
You should use org.apache.solr.request.SolrQueryRequest#getParams to check your updated parameters.

Pagination in Google cloud endpoints + Datastore + Objectify

I want to return a List of "Posts" from an endpoint with optional pagination.
I need 100 results per query.
The Code i have written is as follows, it doesn't seem to work.
I am referring to an example at Objectify Wiki
Another option i know of is using query.offset(100);
But i read somewhere that this just loads the entire table and then ignores the first 100 entries which is not optimal.
I guess this must be a common use case and an optimal solution will be available.
public CollectionResponse<Post> getPosts(#Nullable #Named("cursor") String cursor,User auth) throws OAuthRequestException {
if (auth!=null){
Query<Post> query = ofy().load().type(Post.class).filter("isReviewed", true).order("-timeStamp").limit(100);
if (cursor!=null){
query.startAt(Cursor.fromWebSafeString(cursor));
log.info("Cursor received :" + Cursor.fromWebSafeString(cursor));
} else {
log.info("Cursor received : null");
}
QueryResultIterator<Post> iterator = query.iterator();
for (int i = 1 ; i <=100 ; i++){
if (iterator.hasNext()) iterator.next();
else break;
}
log.info("Cursor generated :" + iterator.getCursor());
return CollectionResponse.<Post>builder().setItems(query.list()).setNextPageToken(iterator.getCursor().toWebSafeString()).build();
} else throw new OAuthRequestException("Login please.");
}
This is a code using Offsets which seems to work fine.
#ApiMethod(
name = "getPosts",
httpMethod = ApiMethod.HttpMethod.GET
)
public CollectionResponse<Post> getPosts(#Nullable #Named("offset") Integer offset,User auth) throws OAuthRequestException {
if (auth!=null){
if (offset==null) offset = 0;
Query<Post> query = ofy().load().type(Post.class).filter("isReviewed", true).order("-timeStamp").offset(offset).limit(LIMIT);
log.info("Offset received :" + offset);
log.info("Offset generated :" + (LIMIT+offset));
return CollectionResponse.<Post>builder().setItems(query.list()).setNextPageToken(String.valueOf(LIMIT + offset)).build();
} else throw new OAuthRequestException("Login please.");
}
Be sure to assign the query:
query = query.startAt(cursor);
Objectify's API uses a functional style. startAt() does not mutate the object.
Try the following:
Remove your for loop -- not sure why it is there. But just iterate through your list and build out the list of items that you want to send back. You should stick to the iterator and not force it for 100 items in a loop.
Next, once you have iterated through it, use the iterator.getStartCursor() as the value of the cursor.

Capture all url segments after the initial match with Nancy

I would like to have nancy rule that matches/captures all url segments after the initial match.
For example I would like to do this:
have a url like: /views/viewname/pageid/visitid/someother
and a rule like this:
Get["/views/{view}/{all other values}"] = parameters =>
{
string view = parameters.view;
List<string> listOfOtherValues = all other parameters..
return ...
};
listOfOtherValues would end up being:
pageid
visitid
someother
I would also like to do this for querystring parameters.
given the a url like: /views/viewname?pageid=1&visitid=34&someother=hello
then listOfOtherValues would end up being:
1
34
hello
Is this even possible with Nancy?
For your first problem you can use regular expression as well as simple names to define your capture groups. So you just define a catch all RegEx.
For your second, you just need to enumerate through the Request.Query dictionary.
Here is some code that demonstrates both in a single route.
public class CustomModule : NancyModule
{
public CustomModule() {
Get["/views/{view}/(?<all>.*)"] = Render;
}
private Response Render(dynamic parameters) {
String result = "View: " + parameters.view + "<br/>";
foreach (var other in ((string)parameters.all).Split('/'))
result += other + "<br/>";
foreach (var name in Request.Query)
result += name + ": " + Request.Query[name] + "<br/>";
return result;
}
}
With this in place you can call a URL such as /views/home/abc/def/ghi/?x=1&y=2 and get the output
View: home
abc
def
ghi
x: 1
y: 2
Note:
The foreach over Request.Query is support in v0.9+

Resources