GAE Query with Collection Parameter - java

I have verified that the entity I am looking for is in the datastore. I have verified that the list I pass as a method parameter contains this entity. I am trying to find all objects that have their 'userGmail' contained in the list of strings I pass.
Here is my code
#SuppressWarnings("unchecked")
#ApiMethod(name = "findFriendsByEmailList")
public CollectionResponse<ZeppaUser> findFriendsByEmailList(
#Named("emailsList") List<String> emailsList, User user)
throws OAuthRequestException {
if (user == null) {
throw new OAuthRequestException(
"Null User Authorization Exception, findFriendsByEmailList");
}
PersistenceManager mgr = null;
List<ZeppaUser> execute = null;
Query query = null;
try {
mgr = getPersistenceManager();
query = mgr.newQuery(ZeppaUser.class);
query.declareParameters("java.util.List emailListParam");
query.setFilter("emailListParam.contains( userGmail )");
execute = (List<ZeppaUser>) query.execute(emailsList);
query.closeAll();
} finally {
mgr.close();
}
return CollectionResponse.<ZeppaUser> builder().setItems(execute)
.build();
}
This is the stack trace I receive from it:
Something worth noting: I do not receive this error on lists I pass in that to not contain an element found in the datastore. Just when it does exist which leads me to believe that the Query has located the element but has not been closed or executed into a return parameter correctly. If it is preferable to return List that is more than ok. I have tried multiple variations of this with no success thus far. It is getting quite frustrating.

Ok so I found a way around it.
Lists cannot be passed into ApiEndpoints. That or I didn't figure out the correct way to do it and would LOVE an update on the proper way to do this.
Instead, in my client, I construct a String of emails seperated by a comma and send a string into the parameter as an 'encoded' string list then 'decode' it upon execution. Works well but seems hacky.
here are the methods I used. This is convenient though because it works with iOS as well.
public static String encodeListString(ArrayList<String> stringList){
StringBuilder stringbuilder = new StringBuilder();
stringbuilder.append(stringList.get(0));
if(stringList.size() > 1){
for( int i = 0; i < stringList.size(); i++){
stringbuilder.append(",");
stringbuilder.append(stringList.get(i));
}
}
return stringbuilder.toString();
}
public static List<String> decodeListString(String encodedString){
char[] characters = encodedString.toCharArray();
StringBuilder stringbuilder = new StringBuilder();
int position = 0;
ArrayList<String> stringList = new ArrayList<String>();
while(true){
try {
char character = characters[position];
if(character == ','){
String resultString = stringbuilder.toString();
stringList.add(resultString);
stringbuilder = new StringBuilder(); // clear it
} else {
stringbuilder.append(character);
}
position++;
} catch (ArrayIndexOutOfBoundsException aiex){
// List ended
String resultString = stringbuilder.toString();
if(!resultString.isEmpty())
stringList.add(resultString);
break;
}
}
return stringList;
}

Related

Java sanitizing Arraylist records suggestions

I am looking for an idea how to accomplish this task. So I'll start with how my program is working.
My program reads a CSV file. They are key value pairs separated by a comma.
L1234456,ygja-3bcb-iiiv-pppp-a8yr-c3d2-ct7v-giap-24yj-3gie
L6789101,zgna-3mcb-iiiv-pppp-a8yr-c3d2-ct7v-gggg-zz33-33ie
etc
Function takes a file and parses it into an arrayList of String[]. The function returns the ArrayList.
public ArrayList<String[]> parseFile(File csvFile) {
Scanner scan = null;
try {
scan = new Scanner(csvFile);
} catch (FileNotFoundException e) {
}
ArrayList<String[]> records = new ArrayList<String[]>();
String[] record = new String[2];
while (scan.hasNext()) {
record = scan.nextLine().trim().split(",");
records.add(record);
}
return records;
}
Here is the code, where I am calling parse file and passing in the CSVFile.
ArrayList<String[]> Records = parseFile(csvFile);
I then created another ArrayList for files that aren't parsed.
ArrayList<String> NotParsed = new ArrayList<String>();
So the program then continues to sanitize the key value pairs separated by a comma. So we first start with the first key in the record. E.g L1234456. If the record could not be sanitized it then it replaces the current key with "CouldNOtBeParsed" text.
for (int i = 0; i < Records.size(); i++) {
if(!validateRecord(Records.get(i)[0].toString())) {
Logging.info("Records could not be parsed " + Records.get(i)[0]);
NotParsed.add(srpRecords.get(i)[0].toString());
Records.get(i)[0] = "CouldNotBeParsed";
} else {
Logging.info(Records.get(i)[0] + " has been sanitized");
}
}
Next we do the 2nd key in the key value pair e.g ygja-3bcb-iiiv-pppp-a8yr-c3d2-ct7v-giap-24yj-3gie
for (int i = 0; i < Records.size(); i++) {
if(!validateRecordKey(Records.get(i)[1].toString())) {
Logging.info("Record Key could not be parsed " + Records.get(i)[0]);
NotParsed.add(Records.get(i)[1].toString());
Records.get(i)[1] = "CouldNotBeParsed";
} else {
Logging.info(Records.get(i)[1] + " has been sanitized");
}
}
The problem is that I need both keyvalue pairs to be sanitized, make a separate list of the keyValue pairs that could not be sanitized and a list of the ones there were sanitized so they can be inserted into a database. The ones that cannot will be printed out to the user.
I thought about looping thought the records and removing the records with the "CouldNotBeParsed" text so that would just leave the ones that could be parsed. I also tried removing the records from the during the for loop Records.remove((i)); However that messes up the For loop because if the first record could not be sanitized, then it's removed, the on the next iteration of the loop it's skipped because record 2 is now record 1. That's why i went with adding the text.
Atually I need two lists, one for the Records that were sanitized and another that wasn't.
So I was thinking there must be a better way to do this. Or a better method of sanitizing both keyValue pairs at the same time or something of that nature. Suggestions?
Start by changing the data structure: rather than using a list of two-element String[] arrays, define a class for your key-value pairs:
class KeyValuePair {
private final String key;
private final String value;
public KeyValuePair(String k, String v) { key = k; value = v; }
public String getKey() { return key; }
public String getValue() { return value; }
}
Note that the class is immutable.
Now make an object with three lists of KeyValuePair objects:
class ParseResult {
private final List<KeyValuePair> sanitized = new ArrayList<KeyValuePair>();
private final List<KeyValuePair> badKey = new ArrayList<KeyValuePair>();
private final List<KeyValuePair> badValue = new ArrayList<KeyValuePair>();
public ParseResult(List<KeyValuePair> s, List<KeyValuePair> bk, List<KeyValuePair> bv) {
sanitized = s;
badKey = bk;
badValue = bv;
}
public List<KeyValuePair> getSanitized() { return sanitized; }
public List<KeyValuePair> getBadKey() { return badKey; }
public List<KeyValuePair> getBadValue() { return badValue; }
}
Finally, populate these three lists in a single loop that reads from the file:
public static ParseResult parseFile(File csvFile) {
Scanner scan = null;
try {
scan = new Scanner(csvFile);
} catch (FileNotFoundException e) {
???
// Do something about this exception.
// Consider not catching it here, letting the caller deal with it.
}
final List<KeyValuePair> sanitized = new ArrayList<KeyValuePair>();
final List<KeyValuePair> badKey = new ArrayList<KeyValuePair>();
final List<KeyValuePair> badValue = new ArrayList<KeyValuePair>();
while (scan.hasNext()) {
String[] tokens = scan.nextLine().trim().split(",");
if (tokens.length != 2) {
???
// Do something about this - either throw an exception,
// or log a message and continue.
}
KeyValuePair kvp = new KeyValuePair(tokens[0], tokens[1]);
// Do the validation on the spot
if (!validateRecordKey(kvp.getKey())) {
badKey.add(kvp);
} else if (!validateRecord(kvp.getValue())) {
badValue.add(kvp);
} else {
sanitized.add(kvp);
}
}
return new ParseResult(sanitized, badKey, badValue);
}
Now you have a single function that produces a single result with all your records cleanly separated into three buckets - i.e. sanitized records, records with bad keys, and record with good keys but bad values.

BIRT: How to remove a dataset parameter programmatically

I want to modify an existing *.rptdesign file and save it under a new name.
The existing file contains a Data Set with a template SQL select statement and several DS parameters.
I'd like to use an actual SQL select statement which uses only part of the DS parameters.
However, the following code results in the exception:
Exception in thread "main" `java.lang.RuntimeException`: *The structure is floating, and its handle is invalid!*
at org.eclipse.birt.report.model.api.StructureHandle.getStringProperty(StructureHandle.java:207)
at org.eclipse.birt.report.model.api.DataSetParameterHandle.getName(DataSetParameterHandle.java:143)
at org.eclipse.birt.report.model.api.DataSetHandle$DataSetParametersPropertyHandle.removeParamBindingsFor(DataSetHandle.java:851)
at org.eclipse.birt.report.model.api.DataSetHandle$DataSetParametersPropertyHandle.removeItems(DataSetHandle.java:694)
--
OdaDataSetHandle dsMaster = (OdaDataSetHandle) report.findDataSet("Master");
HashSet<String> bindVarsUsed = new HashSet<String>();
...
// find out which DS parameters are actually used
HashSet<String> bindVarsUsed = new HashSet<String>();
...
ArrayList<OdaDataSetParameterHandle> toRemove = new ArrayList<OdaDataSetParameterHandle>();
for (Iterator iter = dsMaster.parametersIterator(); iter.hasNext(); ) {
OdaDataSetParameterHandle dsPara = (OdaDataSetParameterHandle)iter.next();
String name = dsPara.getName();
if (name.startsWith("param_")) {
String bindVarName = name.substring(6);
if (!bindVarsUsed.contains(bindVarName)) {
toRemove.add(dsPara);
}
}
}
PropertyHandle paramsHandle = dsMaster.getPropertyHandle( OdaDataSetHandle.PARAMETERS_PROP );
paramsHandle.removeItems(toRemove);
What is wrong here?
Has anyone used the DE API to remove parameters from an existing Data Set?
I had similar issue. Resolved it by calling 'removeItem' multiple times and also had to re-evaluate parametersIterator everytime.
protected void updateDataSetParameters(OdaDataSetHandle dataSetHandle) throws SemanticException {
int countMatches = StringUtils.countMatches(dataSetHandle.getQueryText(), "?");
int paramIndex = 0;
do {
paramIndex = 0;
PropertyHandle odaDataSetParameterProp = dataSetHandle.getPropertyHandle(OdaDataSetHandle.PARAMETERS_PROP);
Iterator parametersIterator = dataSetHandle.parametersIterator();
while(parametersIterator.hasNext()) {
Object next = parametersIterator.next();
paramIndex++;
if(paramIndex > countMatches) {
odaDataSetParameterProp.removeItem(next);
break;
}
}
if(paramIndex < countMatches) {
paramIndex++;
OdaDataSetParameter dataSetParameter = createDataSetParameter(paramIndex);
odaDataSetParameterProp.addItem(dataSetParameter);
}
} while(countMatches != paramIndex);
}
private OdaDataSetParameter createDataSetParameter(int paramIndex) {
OdaDataSetParameter dataSetParameter = StructureFactory.createOdaDataSetParameter();
dataSetParameter.setName("param_" + paramIndex);
dataSetParameter.setDataType(DesignChoiceConstants.PARAM_TYPE_INTEGER);
dataSetParameter.setNativeDataType(1);
dataSetParameter.setPosition(paramIndex);
dataSetParameter.setIsInput(true);
dataSetParameter.setIsOutput(false);
dataSetParameter.setExpressionProperty("defaultValue", new Expression("<evaluation script>", ExpressionType.JAVASCRIPT));
return dataSetParameter;
}

Strange issue with populating LinkedHashSet

Given the below code, is there some reason that when the final if-else statement steps into the else clause, if I un-comment the two lines of code and comment the "FOOZANAZABAR" and "TESTCAIRO" lines, that it would not add those lines into the LinkedHashSet? It appears to add
values.add(new BigDecimal(PEUNIT).multiply(new BigDecimal(1000)).toString());
correctly when the logic drops into the else clause, but will not add the BD.ZERO or the PEFAMT to that field DESPITE the fact they are strings.
As a note, the ZERO and PEFAMT are BigDecimal's that are converted to a string. These are the only two values that are giving me grief. Any direction would be greatly appreciated.
public static LinkedHashMap<String, LinkedHashSet<String>> convertTransactionTableData(ResultSet rs) {
LinkedHashMap<String, LinkedHashSet<String>> returnableMap = new LinkedHashMap<String, LinkedHashSet<String>> ();
try {
while (rs.next()){
String PEFAMT, PEPOLN, MCISST, PEBRCD, PEEFFY, PEPLAN;
String PEUNIT, PETRNC, PECO, PEITYP, ZERO;
PEPOLN = rs.getString("PEPOLN");
MCISST = rs.getString("MCISST");
PEBRCD = rs.getBigDecimal("PEBRCD").toString();
PEEFFY = rs.getBigDecimal("PEEFFY").toString();
PEPLAN = rs.getString("PEPLAN");
PEUNIT = rs.getBigDecimal("PEUNIT").toString();
PEFAMT = rs.getBigDecimal("PEFAMT").toString();
PETRNC = rs.getString("PETRNC");
PECO = rs.getString("PECO");
PEITYP = DataConverter.resetInsuranceType(rs.getString("PEITYP"));
ZERO = BigDecimal.ZERO.toPlainString();
String policyNumber = PEPOLN;
LinkedHashSet<String> values = new LinkedHashSet<String>();
values.add(MCISST);
values.add(PEBRCD);
values.add(PEEFFY);
values.add(PEPLAN);
values.add(PEUNIT);
if (PEPLAN.equalsIgnoreCase("HSRE")) {
values.add(new BigDecimal(PEUNIT).multiply(new BigDecimal(1000)).toString());
} else {
values.add(PEFAMT);
}
values.add(PETRNC);
values.add(PECO);
values.add(PEITYP);
if (DataConverter.testStringToInt(PETRNC)) {
if (Integer.valueOf(PETRNC) >= 20 && Integer.valueOf(PETRNC) <= 29) {
values.add(PEFAMT);
values.add(ZERO);
values.add(ZERO);
} else {
values.add("FOOZANZABAR");
values.add("TESTCAIRO");
// values.add(ZERO);
// values.add(PEFAMT);
values.add(new BigDecimal(PEUNIT).multiply(new BigDecimal(1000)).toString());
}
}
returnableMap.put(policyNumber, values);
}
} catch (SQLException sqlEx) {
logger.error("Problem converting the ResultSet. ", sqlEx);
}
return returnableMap;
}
Thank you in advance.
Josh
Please note that the underlying data structure you're using here is a SET which means it won't let you add duplicates. In all probability, the string values of BD.ZERO and PEFAMT must already be present in your values set and are hence getting ignored.
If this turns out to be the case simply switch to using LinkedList<String> that allows you to have duplicates.

Variable g may not have been initialized

I have many questions about this project that I'm working on. It's a virtual database for films. I have a small MovieEntry class (to process individual entries) and a large MovieDatabase class that keeps track of all 10k+ entries. In my second searchYear method as well as subsequent methods I get the error "variable g (or d or whatever) might not have been initialized."
I also get a pop-up error that says Warnings from last compilation: unreachable catch clause. thrown type java.io.FileNotFoundException has already been caught. I'm positively stumped on both. Here's the code:
public class MovieDatabase
{
private ArrayList<MovieEntry> Database = new ArrayList<MovieEntry>();
public MovieDatabase(){
ArrayList<MovieDatabase> Database = new ArrayList<MovieDatabase>(0);
}
public int countTitles() throws IOException{
Scanner fileScan;
fileScan = new Scanner (new File("movies.txt"));
int count = 0;
String movieCount;
while(fileScan.hasNext()){
movieCount = fileScan.nextLine();
count++;
}
return count;
}
public void addMovie(MovieEntry m){
Database.add(m);
}
public ArrayList<MovieEntry> searchTitle(String substring){
for (MovieEntry title : Database)
System.out.println(title);
return null;
}
public ArrayList<MovieEntry> searchGenre(String substring){
for (MovieEntry genre : Database)
System.out.println(genre);
return null;
}
public ArrayList<MovieEntry> searchDirector (String str){
for (MovieEntry director : Database)
System.out.println(director);
return null;
}
public ArrayList<String> searchYear (int yr){
ArrayList <String> yearMatches = new ArrayList<String>();
for (MovieEntry m : Database)
m.getYear(yr);
if(yearMatches.contains(yr) == false){
String sYr = Integer.toString(yr);
yearMatches.add(sYr);
}
return yearMatches;
}
public ArrayList<MovieEntry> searchYear(int from, int to){
ArrayList <String> Matches = new ArrayList<String>();
for(MovieEntry m : Database);
m.getYear();
Matches.add();
return Matches;
}
public void readMovieData(String movies){
String info;
try{
Scanner fileReader = new Scanner(new File("movies"));
Scanner lineReader;
while(fileReader.hasNext()){
info = fileReader.nextLine();
lineReader = new Scanner(info);
lineReader.useDelimiter(":");
String title = lineReader.next();
String director = lineReader.next();
String genre = lineReader.next();
int year = lineReader.nextInt();
}
}catch(FileNotFoundException error){
System.out.println("File not found.");
}catch(IOException error){
System.out.println("Oops! Something went wrong.");
}
}
public int countGenres(){
ArrayList <String> gList = new ArrayList<String>();
for(MovieEntry m : Database){
String g = m.getGenre(g);
if(gList.contains(g) == false){
gList.add(g);
}
return gList.size();
}
}
public int countDirectors(){
ArrayList <String> dList = new ArrayList<String>();
for(MovieEntry m : Database){
String d = m.getDirector(d);
if(dList.contains(d) == false){
dList.add(d);
}
return dList.size();
}
}
public String listGenres(){
ArrayList <String> genreList = new ArrayList<String>();
}
}
catch(IOException error){
System.out.println("Oops! Something went wrong.");
}
Its telling you that the FileNotFoundException will deal with what the IOException is catching, so the IOException becomes unreachable as in it will never catch an IO exceltion, why just not catch an Exception instead
As for the initialization
public int countDirectors(){
ArrayList <String> dList = new ArrayList<String>();
for(MovieEntry m : Database){
String d = m.getDirector(d); //THIS LINE
if(dList.contains(d) == false){
dList.add(d);
}
return dList.size();
}
The line String d = m.getDirector(d); might be the problem, d wont be initialised unless there is something in the MovieEntry and as far as i can see there will never be anything because you are initialising it to an empty array list
ArrayList<MovieDatabase> Database = new ArrayList<MovieDatabase>(0);
Maybe you should be passing a array of movies to the constructor and then add these movies to the Database variable ?
Seems like there are a number of issues with this code.
What parameter does MovieEntry.getGenre() expect? You may not use g in that case because it has not been defined yet.
The exception issue you mentioned means that the exception was already caught, or possibly never thrown. I believe that in this case the IOException is never thrown out from the code within the try block.
There are a number of methods that are supposed to return a value but do not, example:
public String listGenres(){
ArrayList <String> genreList = new ArrayList<String>();
}
Also, it is a java naming convention to use lower case first characters (camel case) for values:
private ArrayList<MovieEntry> database = new ArrayList<MovieEntry>();
Oh, and do you need to re-initialize the database variable in the constructor?:
public MovieDatabase(){
ArrayList<MovieDatabase> Database = new ArrayList<MovieDatabase>(0);
}
Hope this is helpful.

Simplest way to strip an int out of a URL in Java?

I have a String containing a URL. I want to get just one piece of data out of it: an int that should be showing up in the query string.
So if the url is:
http://domain.tld/page.html?iVar=123
I want to get "123" into an int.
What's the most elegant way you know to do this?
You could try matching just that parameter in the URL string:
public static Integer getIVarParamValue(String urlStr) {
Pattern p = Pattern.compile("iVar=(\\d+)");
Matcher m = p.matcher(urlStr);
if (m.find()) {
return Integer.parseInt(m.group(1));
}
return null;
}
It seems you want to obtain get parameters and parse them. I have this method here (got it from somewhere on SO, I guess):
public static Map<String, List<String>> getQueryParams(String url) {
try {
Map<String, List<String>> params = new HashMap<String, List<String>>();
String[] urlParts = url.split("\\?");
if (urlParts.length > 1) {
String query = urlParts[1];
for (String param : query.split("&")) {
String[] pair = param.split("=");
String key = URLDecoder.decode(pair[0], "UTF-8");
String value = "";
if (pair.length > 1) {
value = URLDecoder.decode(pair[1], "UTF-8");
}
List<String> values = params.get(key);
if (values == null) {
values = new ArrayList<String>();
params.put(key, values);
}
values.add(value);
}
}
return params;
} catch (UnsupportedEncodingException ex) {
throw new AssertionError(ex);
}
}
So:
String var = WebUtils.getQueryParams(url).get("iVar");
int intVar = Integer.parseInt(var);
You can use the URL class.
i.e.:
URL myUrl = new URL("http://domain.tld/page.html?iVar=123");
String query = myUrl.getQuery(); //this will return iVar=123
//at this point you can either parse it manually (i.e. use some of the regexp in the other suggestions, or use something like:
String[] parts = query.split();
String variable = parts[0];
String value = parts[1];
This will work only for this case though and won't work if you have additional params or no params.
There are a number of solution that will split it into a param map online, you can see some here.
If it's really as simple as you describe: There is only 1 int in your URL and all you want is that int, I'd go for a regular expression. If it is actually more complicated see the other answers.
Pattern p = Pattern.compile("[0-9]+");
Matcher m = p.matcher("http://domain.tld/page.html?iVar=123");
if (m.find())
System.out.println(m.group());
This also could do the work :
public static int getIntParam(HttpServletRequest request, String name, int defaultValue) {
String value = request.getParameter(name);
try {
if (value != null) {
return Integer.valueOf(value);
}
} catch (NumberFormatException e) {
}
return defaultValue;
}
Hope it helps!
If the query string part of the URL is always the same (so if it was always iVar) you could use urlAsString.indexOf("iVar=") to find iVar= and then knowing the number is after that, extract the number. That is admittedly not the least brittle approach.
But if you're looking for all the query strings then Bozho's answer is much better.

Categories