How to create query from HashMap? [duplicate] - java

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
How can I obtain values of key-value pair from a Hashmap?
QueryStats queryStats=new QueryStats();
Map parameterMap = request.getParameterMap()==null? null:new HashMap(request.getParameterMap());
System.out.println("Query2:" + parameterMap);
Collection newParamsValue=parameterMap.values();
Object newParams[]=newParamsValue.toArray();
StringBuffer strParam=new StringBuffer() ;
int l=newParams.length;
for(int i=0;i<l;i++){
strParam=strParam.append(newParams[i].toString());
}
output: Query2:{sortPrefix=[Ljava.lang.String;#1d66aa9, searsOnly=[Ljava.lang.String;#1f4bdca, globalPrefix=[Ljava.lang.String;#d81cda, indent=[Ljava.lang.String;#4e57ba, qt=[Ljava.lang.String;#1619137, wt=[Ljava.lang.String;#84c1f9, fq=[Ljava.lang.String;#1dae27f}
From this parameterMap, I want to create a query? How is it possible?

If the request is a HTTP request (and I suspect it is) and the query is a database query, then what you're trying to do is a big no-no. Always, always, always sanitize your input. Just stop for a moment and think with the mind of a malicious person trying to wreck or obtain your database content, trying to forge a HTTP request that fools your unsuspecting application into doing exactly that.
Another thing about HTTP request parameters is that they come in string arrays. If you want the string value of an input, you need to cast your values to String[] first, then grab the first element of that array. Please note that the array can be empty though, and this method only works for single value inputs, multiple selection inputs will return multiple elements.

The problem you face is that the map returned from getParameterMap maps String keys to arrays of String values. So each element of newParamsValue is a String[]. You need to do a little more work to get a sensible (comma-separated) string out of these than calling toString(). Something like this (untested) might do what you want:
ArrayList<String> toStrings(Collection requestValues) {
ArrayList<String> strings;
for (Object object : requestValues) {
String[] vals = (String[]) object;
if (vals.length() == 1) {
strings.add(vals[0]);
} else if (vals.length() > 1) {
StringBuilder sb = new StringBuilder(vals[0]);
for (int i = 1; i < vals.length(); ++i) {
sb.append(',');
sb.append(vals[i]);
}
strings.add(sb.toString());
}
}
return strings;
}

Related

Cannot unbox null value

I have the following code:
List<Details> detailsList = new ArrayList<>();
List<String[]> csv = csvReader.readAll();
final Map<String, Integer> mappedHeaders = mapHeaders(csv.get(0));
List<String[]> data = csv.subList(1, csv.size());
for (String[] entry : data) {
Details details = new Details(
entry[mappedHeaders.get("A")],
entry[mappedHeaders.get("B")],
entry[mappedHeaders.get("C")]);
detailsList.add(details);
I'm essentially reading in a CSV file as a list of string arrays where the first list item is the CSV file headers and all remaining elements correspond to the data rows. However, since different CSV files of the same features might have different feature column ordering I don't know the ordering in advance. For that, I have a mapHeaders method which maps the headers to indices so I can later properly put together the Details object (for example, if headers are ["B", "A", "C"], the mappedHeaders would correspond to {B: 0; A: 1; C: 2}.
I also have some test data files of different column orderings and all but one of them work as they should. However, the one that doesn't work gives me
java.lang.NullPointerException: cannot unbox null value
when trying to evaluate entry[mappedHeaders.get("A")]. Additionally, when running the code in debugging mode, the mappedHeaders contains the correct keys and values and the value for "A" isn't null.
I have also tried entry[mappedHeaders.getOrDefault("A", Arrays.asList(csv.get(0)).indexOf("A"))] which returns -1. The only thing that works is entry[mappedHeaders.getOrDefault("A", 0)] since A is the first column in the failing case, but that workaround don't seem very feasible as there might be more failing cases that I don't know about, but where the ordering is different. What might be the reason for such behavior? Might it be some weird encoding issue?
That's because you are trying to unbox a null value.
A method like intValue, longValue() or doubleValue() is being called on a null object.
Integer val = null;
if (val == 1) {
// NullPointerException
}
Integer val = null;
if (val == null) {
// This works
}
Integer val = 0;
if (val == 1) {
// This works
}

How to fetch large datasets into List of Strings with Spring?

I want to fetch large datasets from a MySql database, and return it as a List of comma separated Strings via a Webservice (not via a downloadable file, but directly as text).
Therefore I first need all selected rows in CSV format.
Question: What's the best way achieving this with Spring?
The following works with JdbcTemplate, but I don't know if this is the best approach (maybe optimize using Java 8 streams)?
Also if somehow feels wrong having to iterate the ResultSet and call rs.getString(i), concatenating each element of the ResultSet. Isn't there a more elegant way?
RowMapper<String> rowMapper = new RowMapper<String>() {
#Override
public String mapRow(ResultSet rs, int rowNum) throws SQLException {
StringBuilder sb = new StringBuilder();
for (int i = 1; i <= rs.getMetaData().getColumnCount(); i++) {
sb.append(rs.getString(i)).append(",");
}
return sb.toString();
}
};
String sql = "SELECT * from mypersons where age > 12";
List<String> list = new JdbcTemplate(dataSource).query(sql, params, rowMapper);
//...return the list via Webservice
Sidenote: I have to use native SQL for the select. They are much more complicated in my example above.
I recommend using Spring Data JPA to get a SET of persons. Once you have a set of persons, you can use streams to map the persons to the field you want to collect, and join that field with commas.
Assuming a Set, given a person has an attribute called name, this method will return a comma separated list of names.
public String joinName(Set<Person> persons) {
return persons.stream().map(Person::getName).collect(Collectors.joining(", "));
}
Your solution looks fine. I just have two possible improvements:
the indexed based access to the ResultSet already exists in the ColumnMapRowMapper. You could delegate to it and would get (pseudocode)
class CommaSeparatedStringRowMapper implements RowMapper<String> {
ColumnMapRowMapper delegate = new ColumnMapRowMapper();
#Override
public Map<String, Object> mapRow(ResultSet rs, int rowNum){
delegate.mapRow(rs, rowNum).valueSet().toStream.collect(Collectors)
}
Note: this will be less efficient, due to creating and accessing the intermediate map, but it looks nicer.
Note 2: The underlying map should preserve the order of columns, but you better double check.
Alternatively, you might consider using a RowCallbackHandler writing your results directly into a Webservice response thingy. If done right, part of your response might be on the way to your client while you are still processing the rest of the query result. So this might improve latency and memory consumption.

Why does my XML parser only returns one string, instead of multiple ones?

I got a problem regarding parsing XML data. I have divided my program into 3 different java files, each containing a class. One of them is rssparser.java. This file holds a function called iterateRSSFeed(String URL), this function returns a string containing the parsed description tag. In my main.java files where my main method is, I call this iterateRSSFeed function this way:
rssparser r = new rssparser();
String description = r.iterateRSSFeed();
And then I am planning to add this String to a JLabel, this way:
JLabel news = new JLabel(description);
which obviously works great, my program runs. BUT there are more description tags in my XML file, the JLabel only contains one(1) parsed description tag. I should say that my return statement in the iterateRSSFeed function is "packed" in a for-loop, which in my head should return all of the description tags. But no.
Please ask if something is uncleared or showing of the source code is a better way to provide a solution to my answer. Thanks in advance! :)
When Java executes a return statement, it will leave the method, and not continue running the loop.
If you want to return multiple values from a method, you have to put them in some object grouping them together. Normally one would use a List<String> as return type.
Then your loop will fill the list, and the return statement (after the loop) can return the whole list at once.
If you want to have one large string instead of multiple ones, you'll have to merge them into one.
The easiest would be to simply use the .toString() method on the list, this will give (if you are using the default list implementations) something like [element1, element2, element3].
If you don't like the [,], you could simply concatenate them:
List<String> list = r.iterateRSSFeed();
StringBuilder b = new StringBuilder();
for(String s : list) {
b.append(s);
}
String description = b.toString();
This will give element1element2element3.
As Java's JLabel has some rudimentary HTML support, you could also use this to format your list as a list:
List<String> list = r.iterateRSSFeed();
StringBuilder b = new StringBuilder();
b.append("<html><ul>");
for(String s : list) {
b.append("<li>");
b.append(s);
b.append("</li>");
}
b.append("</ul>");
String description = b.toString();
The result will be <html><ul><li>element1</li><li>element2</li><li>element3</li></ul>, which will be formatted by the JLabel as something like this:
element1
element2
element3

How to find duplicates in an ArrayList which is in the form of JSON object?

I am having an option in my website for the user i.e: "Settings" in that I given 3 options(TextBoxes) to enter details: 1.E-mail, 2.SMS, 3.MMS.. in this user can enter another mail id: its an optional thing but, if he enter the both or same which is neccesary e-mail and optional or same then, I have to tell that "given e-mail" alredy exist.
I am sending this data as ArrayList that to coverted as JSON object.
What is the best way to find the duplicate and notify that to user
Help me in this
Thanks in advance
Either parse it into Java collections with a JSON framework of your choice, then check for duplicates or use JavaScript to directly work on the JSON.
If you have the ArrayList anyway, why don't iterate over that?
Please do the following
HashSet hashSet = new HashSet(arrayList1);
ArrayList arrayList2 = new ArrayList(hashSet) ;
if(arrayList2.size()<arrayList1.size()){
//duplicates exits
}
You can do what Ammu posted, but this will not identify the duplicate entry. If you have the ArrayList as a Java object (if not, convert it into one), convert the ArrayList into a HashSet, compare the size to identify if there are duplicate entries. If so, you need to sort the ArrayList in order to find the duplicate entry.
Collections.sort(arrayList);
for(int i = 1; i < arrayList.size() - 1; i++){
if (arrayList.get(i).equals(arrayList.get(i - 1))){
// found duplicate
System.out.println("Duplicate!");
}
}
this works only if the entries of the ArrayList implement the sortable interface. But since your ArrayList is filled with strings this is the case.
Based on what you described
"... in this user can enter another
mail id: its an optional thing but, if
he enter the both or same which is
neccesary e-mail and optional or same
then, I have to tell that "given
e-mail" alredy exist."
I would alert the user using Javascript and avoid the HTTP Request/Response round-trip to the server:
...
// before submitting the form
if (document.getElementById('requiredEmail').value == document.getElementById('optionalEmail').value) {
alert("The optional email must be different than the required email");
}
...
As suggested before by other user, you can just create a Set based on the ArrayList if you are validating the input in the backend...
String[] parsedInput = new String[] { "SMS-Value", "MMS-Value", "email#domain.com", "email#domain.com" }
List<String> receivedList = Arrays.asList(parsedInput);
Set<String> validatedList = new HashSet<String>(receivedList);
if (validatedList.size() < receivedList.size()) {
throw new IllegalArgumentException("The email addresses provided are incorrect.");
}
If you want to find the duplicates then you can iterate over the list and find.
like:
Map<Object, Integer> map = new HashMap<Object, Integer>();
for(Object obj : list)
{
if(map.containsKey(obj))
{
map.put(obj, map.get(obj)+1);
}
else
{
map.put(obj, 1);
}
}
Objects in the map having value more than 1 are duplicate.
If you just want to get rid of duplicates (rather than knowing which are actually duplicates)
Ex:
Set set = new HashSet(list);
set can not have duplicate elements, so it will remove all duplicates.

java.util.Collections$UnmodifiableMap problem : code included

I am building a facebook platform web app using GWT and hosting it on App Engine.
I am adding validation code that uses supplied query string parameters in the callback url. GWT allows me to get these parameters by calling Window.Location.getParameterMap() and the returned Map is immutable.
I may be wrong however I think this problem has nothing to do with FB, GWT or App Engine specifically and is more down to my misunderstanding something about Map objects.
I don't think that my code attempts to modify the supplied Map but the error I get seems to suggest that my code is trying to modify an immutable Map.
Can someone please take a look and let me know where I am modifying an unmodifiable Map?
I would supply a stack trace but I can't find a way to get a stack trace for this to display in App Engine logs.
Thanks in advance for any and all help :-)
/**
* Validation Test
* To generate the signature for these arguments:
* 1. Remove the fb_sig key and value pair.
* 2. Remove the "fb_sig_" prefix from all of the keys.
* 3. Sort the array alphabetically by key.
* 4. Concatenate all key/value pairs together in the format "k=v".
* 5. Append your secret key.
* 6. Take the md5 hash of the whole string.
* #param fbQueryStringParams
* #return String
*/
public String test(Map<String,List<java.lang.String>> fbQueryStringParams) {
String appSecret = TinyFBClient.APP_SECRET;
String fbSig = fbQueryStringParams.get("fb_sig").get(0);
StringBuilder sb = new StringBuilder();
TreeMap<String,String> sortedMap = new TreeMap<String,String>();
// Get a Set view of the Map of query string parameters.
Set<Map.Entry<String,List<java.lang.String>>> mapEntries = fbQueryStringParams.entrySet();
// Iterate through the Set view, inserting into a SortedMap all Map.Entry's
// that do not have a Key value of "fb_sig".
Iterator<Map.Entry<String,List<java.lang.String>>> i = mapEntries.iterator();
while(i.hasNext()) {
Map.Entry<String,List<java.lang.String>> mapEntry = i.next();
if(!mapEntry.getKey().equals("fb_sig")) { // 1. Remove the fb_sig key and value pair.
sortedMap.put(mapEntry.getKey(),mapEntry.getValue().get(0)); // 3. Sort the array alphabetically by key.
}
}
// Get a Set view of the Map of alphabetically sorted Map.Entry objects.
Set<Map.Entry<String,String>> sortedMapEntries = sortedMap.entrySet();
// Iterate through the Set view, appending the concatenated key's and value's
// to a StringBuilder object.
Iterator<Map.Entry<String,String>> ii = sortedMapEntries.iterator();
while(ii.hasNext()) {
Map.Entry<String,String> mapEntry = ii.next();
// 4. Concatenate all key/value pairs together in the format "k=v".
sb.append(mapEntry.getKey().replaceAll("fb_sig_","")); // 2. Remove the "fb_sig_" prefix from all of the keys.
sb.append("=");
sb.append(mapEntry.getValue());
}
sb.append(appSecret); // 5. Append your secret key.
String md5 = DigestUtils.md5Hex(sb.toString()); // 6. Take the md5 hash of the whole string.
// Build and return an output String for display.
StringBuilder output = new StringBuilder();
output.append("fbSig = "+fbSig);
output.append("<br/>");
output.append("md5 = "+md5);
return output.toString();
}
copy the Windows.Location.getParameterMap() in a HashMap and it will work:
So you send new HashMap>( Windows.Location.getParameterMap()) over RPC that works.
The problem is that unmodifiableMap is not Serializable for GWT. I know that it has a Serializable marker, but in GWT it works a little bit different. Most collection classes have a custom GWT implementation and some are not 100% compatible.
I don't see any unmodifiable collections.
Your code is pretty complicated. If I understood it right, then this should be equivalent. I wouldn't use Map.Entry objects and the TreeMap has a handy constructor for your needs. And finally, I'd prefer the 'forall' loop over the iterator.
public String test(Map<String, List<java.lang.String>> fbQueryStringParams) {
String appSecret = TinyFBClient.APP_SECRET;
String fbSig = fbQueryStringParams.get("fb_sig").get(0);
StringBuilder sb = new StringBuilder();
TreeMap<String, List<String>> sortedMap = new TreeMap<String, List<String>>(fbQueryStringParams);
sortedMap.remove("fbSig"); // remove the unwanted entry
for (String key, sortedMap.keySet()) {
List<String> values = sortedMap.get(key);
String printableKey = key.replaceAll("fb_sig_", ""));
String value = "EMPTY LIST";
if (!values.isEmpty()) {
// This could have been your problem, you always
// assume, all lists in the map are not empty
value = values.get(0);
}
sb.append(String.format("%s=%s", printableKey, value);
}
sb.append(appSecret);
String md5 = DigestUtils.md5Hex(sb.toString());
// Build and return an output String for display.
StringBuilder output = new StringBuilder();
output.append("fbSig = " + fbSig);
output.append("<br/>");
output.append("md5 = " + md5);
return output.toString();
}
While refactoring I found one possible bug: when you create the sorted map in your code, you assume, all lists in the map are not empty. So the first empty list will cause a NPE in the first loop.
Do a System.out.println(fbQueryStringParams.getClass()); at the start of the message (or log it or whatever you need to be able to see what it is).
If that argument is passed to you from the system it is very likely wrapped as an unmodifiable collection since they don't want you altering it.
Did I understand it correctly that you are doing a Window.Location.getParameterMap in your client code and sending it to the server in a RPC call ? In that case ... the question is: is that ParameterMap serializable ? Not all implementations are in fact supported in GWT. So it might just be that your server code is not even called but that it crashes before it can send the request. Did you see any warning during GWT compilation ?
The code, although the implementation can be cleaned up and indeed you can have a NPE, is NOT modifying the supplied parameter Map or the List in the Map values. So the problem is probably somewhere else.
Why don't you run your application in hosted mode (or development mode as they call it in GWT 2.0) ?
David

Categories