NSNotFound equivalent in Java - java

I need to know if there is a way to say that int type is not found in Java Android.
I'm writing an android application,which is actually written first for Iphone, and have a little issue. At some point I have to check if the int type which returns a method is not found and if it's true do some calculations. The problem is that when I did that in Java as if(Id==0) it's throwing me an exception even if the Id is 0.
this is my method :
private static int localUserIdByServerUserId(int serverUserId, String serverName){
dbHelper = new DataBaseHelper(context, "stampii_sys_tpl.sqlite", null, 1);
dbHelper.getDatabase();
String query = "SELECT id FROM users WHERE objectId = "+serverUserId+" AND serverName = '"+serverName+"' LIMIT 1";
ArrayList<String> result = new ArrayList<String>();
cursor = dbHelper.executeSQLQuery(query);
cursor.moveToFirst();
while(!cursor.isAfterLast()) {
result.add(cursor.getString(cursor.getColumnIndex("id")));
cursor.moveToNext();
}
Log.i("result ","Result : "+result.toString());
Log.i("CURSOR ","Cursor Position : "+cursor.getPosition());
int uuid = Integer.parseInt(result.get(cursor.getColumnIndex("objectId")+1));
Log.w("localUSerByIdServerUserId","LocalUserByIdServerUserId result : "+uuid);
cursor.close();
return uuid;
and here is how I'm using it :
int uuId = rpc.lUserIdByServerUserId(userId,newServerName);
Log.w("uuId","uuId : "+uuId);
if(uuId==0){
// do some calculations
}
Any suggestions ?

lUserIdByServerUserId() could throw an exception when the user is not found.
e.g.
try {
int uuId = rpc.lUserIdByServerUserId(userId,newServerName);
Log.w("uuId","uuId : "+uuId);
}
catch (NotFoundException nfe) {
// do some calculations
}
You will need to modify lUserIdByServerUserId() to throw the exception. You may also need to define your own NotFoundException class if a suitable exception doesn't already exist in the Java libraries.
EDIT:
Alternatively, following on from #mthpvg's answer, you could change lUserIdByServerUserId() to return an Integer type, which can be set to null if not found and tested.
e.g.
Integer uuId = rpc.lUserIdByServerUserId(userId,newServerName);
if (uuId == null) {
// Do some calculations
}

Related

Rename file of the Mediastore which is created by app in android 10. Working on Android API 30 but shows error in API 29

Here, this renameFile(..) func is working in Android API 30. But, it is not working in Android API 29 and shows the error like :
java.lang.IllegalArgumentException: Movement of content://media/external/file/116 which isn't part of well-defined collection not allowed
Update-Note:
---Begins---
In-order to work with sdk-29 we have to use Uri as extUri = MediaStore.Downloads.getContentUri(MediaStore.VOLUME_EXTERNAL) like:
private static Uri extUri = MediaStore.Downloads.getContentUri(MediaStore.VOLUME_EXTERNAL);
in place of below code. And also update MediaStore.Files.FileColumns to MediaStore.Downloads
---Ends---
Uri extUri = MediaStore.Files.getContentUri(MediaStore.VOLUME_EXTERNAL);
String relativeLocation = Environment.DIRECTORY_DOWNLOADS + File.separator + "AppFolder";
function renameFile(...)
boolean renameFile(Context context, String newName, String displayName) {
try {
Long id = getIdFromDisplayName(displayName);
ContentResolver contentResolver = context.getContentResolver();
Uri mUri = ContentUris.withAppendedId(extUri, id);
ContentValues contentValues = new ContentValues();
contentValues.put(MediaStore.Files.FileColumns.IS_PENDING, 1);
contentResolver.update(mUri, contentValues, null, null);
contentValues.clear();
contentValues.put(MediaStore.Files.FileColumns.DISPLAY_NAME, newName);
// contentValues.put(MediaStore.Files.FileColumns.MIME_TYPE, "files/pdf");
// contentValues.put(MediaStore.Files.FileColumns.RELATIVE_PATH, relativeLocation);
// contentValues.put(MediaStore.Files.FileColumns.TITLE, "SomeName");
// contentValues.put(MediaStore.Files.FileColumns.DATE_ADDED, System.currentTimeMillis() / 1000);
// contentValues.put(MediaStore.Files.FileColumns.DATE_TAKEN, System.currentTimeMillis());
contentValues.put(MediaStore.Files.FileColumns.IS_PENDING, 0);
contentResolver.update(mUri, contentValues, null, null);
return true;
} catch (Exception ex) {
ex.printStackTrace();
}
return false;
}
function getIdFromDisplayName(...)
#RequiresApi(api = Build.VERSION_CODES.Q)
Long getIdFromDisplayName(String displayName) {
String[] projection;
projection = new String[]{MediaStore.Files.FileColumns._ID};
// TODO This will break if we have no matching item in the MediaStore.
Cursor cursor = getContentResolver().query(extUri, projection,
MediaStore.Files.FileColumns.DISPLAY_NAME + " LIKE ?", new String[]{displayName}, null);
assert cursor != null;
cursor.moveToFirst();
if (cursor.getCount() > 0) {
int columnIndex = cursor.getColumnIndex(projection[0]);
long fileId = cursor.getLong(columnIndex);
cursor.close();
return fileId;
}
return null;
}
java.lang.IllegalArgumentException: Movement of content://media/external/file/116 which isn't part of well-defined collection not allowed
So it is for Android Q not allowed if you use the collection;
Uri extUri = MediaStore.Files.getContentUri(MediaStore.VOLUME_EXTERNAL);
But is is allowed for a 'well-defined collection' like:
Uri extUri = MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL);
// Use "Pictures/MyFolder" for RELATIVE_PATH
I leave it to you to find other well-defined collections.
Why this is only for Android Q i dont know.
You can see the message in the java file: https://android.googlesource.com/platform/packages/providers/MediaProvider/+/refs/heads/master/src/com/android/providers/media/MediaProvider.java
Quote:
// We only support movement under well-defined collections
switch (match) {
case AUDIO_MEDIA_ID:
case VIDEO_MEDIA_ID:
case IMAGES_MEDIA_ID:
case DOWNLOADS_ID:
break;
default:
throw new IllegalArgumentException("Movement of " + uri
+ " which isn't part of well-defined collection not allowed");
}
If the rename fails use SAF (as mentioned before). How to rename a file in Android knowing only its media content Uri
I had to face the rename problem myself (Android 29) and the solution above did not suffice.
This was because I had a physical SD card on which were located the
files I wanted to rename.
Then, instruction:
extUri = MediaStore.Audio.Media.getContentUri(MediaStore.VOLUME_EXTERNAL);
did not work; instead,I had to:
list the "external volumes"(according to Android terms)
Set<String> lVls = MediaStore.getExternalVolumeNames(this);
..which gave me 2 volumes:
"external_primary" (the built-in external storage)
"bc21-eafa" (the SD card external storage)
Initialize 'extUri' with that second value, like that:
extUri = MediaStore.Audio.Media.getContentUri("bc21-eafa");
Apply the rest of the procedure as described in this article.
Thanks to all !

IllegalArgumentException: Invalid column DISTINCT bucket_display_name

I'm retrieving list of distinct folders list having video files with number of videos in each folder, and this is working fine in devices having Android P and below, but when I run on devices having Android Q the app crashes.
How can I make it work for devices running Android Q
java.lang.IllegalArgumentException: Invalid column DISTINCT
bucket_display_name
Logcat:
java.lang.IllegalArgumentException: Invalid column DISTINCT bucket_display_name
at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:170)
at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:140)
at android.content.ContentProviderProxy.query(ContentProviderNative.java:423)
at android.content.ContentResolver.query(ContentResolver.java:944)
at android.content.ContentResolver.query(ContentResolver.java:880)
at android.content.ContentResolver.query(ContentResolver.java:836)
at com.aisar.mediaplayer.fragments.VideoFolderFragment$MediaQuery.getAllVideo(VideoFolderFragment.java:364)
at com.aisar.mediaplayer.fragments.VideoFolderFragment$VideosLoader.loadVideos(VideoFolderFragment.java:434)
at com.aisar.mediaplayer.fragments.VideoFolderFragment$VideosLoader.access$1100(VideoFolderFragment.java:413)
at com.aisar.mediaplayer.fragments.VideoFolderFragment$5.run(VideoFolderFragment.java:189)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:289)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:919)
My Code:
public class MediaQuery {
private Context context;
private int count = 0;
private Cursor cursor;
List<ModelVideoFolder> videoItems;
public MediaQuery(Context context) {
this.context = context;
}
public List<ModelVideoFolder> getAllVideo(String query) {
String selection = null;
String[] projection = {
"DISTINCT " + MediaStore.Video.Media.BUCKET_DISPLAY_NAME,
MediaStore.Video.Media.BUCKET_ID
};
cursor = context.getContentResolver().query(
MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
projection,
selection,
null,
query);
videoItems = new ArrayList<>();
ModelVideoFolder videoItem;
while (cursor.moveToNext()) {
videoItem = new ModelVideoFolder(
"" + cursor.getString(1),
"" + cursor.getString(0),
"",
"",
"" + getVideosCount(cursor.getString(1))
);
videoItems.add(videoItem);
}
return videoItems;
}
public int getVideosCount(String BUCKET_ID) {
int count = 0;
String selection = null;
String[] projection = {
MediaStore.Video.Media.BUCKET_ID,
};
Cursor cursor = getActivity().getContentResolver().query(
MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
projection,
selection,
null,
null);
while (cursor.moveToNext()) {
if (BUCKET_ID.equals(cursor.getString(0))) {
//add only those videos that are in selected/chosen folder
count++;
}
}
return count;
}
}
This is due to the restrictions in Android Q.
In Android Q the projection must contain only valid column names without additional statements. Is not possible anymore to embed any type of SQL statement in the projection.
So, projections such as "DISTINCT " + YourColumName, or even trying to make a column alias such as "ExistingColumnName AS AnotherName" will always fail.
The workaround is to perform multiple queries (cursors) to get your required metrics, and construct with the results a CursorWrapper or MatrixCursor.
See the next issue link, where is stated this behavior as expected, since is part of the improved storage security model in Q:
https://issuetracker.google.com/issues/130965914
For your specific problem, a solution could be as next:
First query for a cursor to obtain the list of the BUCKET_ID values where all the videos are located. In the selection you can filter to target only video files by using MediaStore.Files.FileColumns.MEDIA_TYPE = MediaStore.Files.FileColumns.MEDIA_TYPE_VIDEO
With the retrieved cursor, iterate all the BUCKET_ID values to perform individual queries per bucket and retrieve the video records, from which you can resolve the count. While iterating keep track of each BUCKET_ID and skip any already queried. And don't forget to also perform the same MEDIA_TYPE filter selection, to avoid querying none-video files that may reside in the same bucket.
Try the next snippet based in your question code, I haven't test it but you may get an idea about how to proceed:
public static class MediaQuery
{
#NonNull
public static HashMap<String, ModelVideoFolder> get(#NonNull final Context context)
{
final HashMap<String, ModelVideoFolder> output = new HashMap<>();
final Uri contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
final String[] projection = {MediaStore.Video.Media.BUCKET_DISPLAY_NAME,
MediaStore.Video.Media.BUCKET_ID};
try (final Cursor cursor = context.getContentResolver().query(contentUri,
projection, null, null, null))
{
if ((cursor != null) && (cursor.moveToFirst() == true))
{
final int columnBucketName = cursor.getColumnIndexOrThrow(MediaStore.Video.Media.BUCKET_DISPLAY_NAME);
final int columnBucketId = cursor.getColumnIndexOrThrow(MediaStore.Video.Media.BUCKET_ID);
do
{
final String bucketName = cursor.getString(columnBucketName);
final String bucketId = cursor.getString(columnBucketId);
if (output.containsKey(bucketId) == false)
{
final int count = MediaQuery.getCount(context, contentUri, bucketId);
final ModelVideoFolder item = new ModelVideoFolder(
bucketName, bucketId, null, null, count);
output.put(bucketId, item);
}
} while (cursor.moveToNext());
}
}
return output;
}
private static int getCount(#NonNull final Context context, #NonNull final Uri contentUri,
#NonNull final String bucketId)
{
try (final Cursor cursor = context.getContentResolver().query(contentUri,
null, MediaStore.Video.Media.BUCKET_ID + "=?", new String[]{bucketId}, null))
{
return ((cursor == null) || (cursor.moveToFirst() == false)) ? 0 : cursor.getCount();
}
}
}
The DISTINCT keyword actually belongs to the SELECT statement, not to a column. For example SELECT DISTINCT Country, Name FROM CountriesTable. Therefore adding DISTINCT to a column projection is a hack which randomly worked in the previous Android versions and probably stopped working in Android 10 due to some changes. Since the ContentResolver doesn't allow raw queries, you just have to filter unique folders inside your code, e. g. by using a HashSet.
I was facing the same problem. DISTINCT keyword doesn't work in Android 10, use hashset for distinct.

Setting Parameters through url javaplay

so as part of some work I've been doing I was given a file with WebServices that are being used in a Swift application. I have zero familiarity with WebServices and only know Java through syntax understanding. I need to call one of these gets with a parameter from the swift application. What I'm trying to figure out first and foremost is how I can call one of these webservices with a parameter from the URL it's associated with. For example down below I want to call the method
http://localhost:9000/ListVehicleByPlateNumber
and I want to specify the parameter through the URL say something like
http://localhost:9000/ListVehicleByPlateNumber?para="123"
But this doesn't assign any value to the parameter and I'm not getting results. If I hardcode so that the string used in the function is = "123" it gives me the results I'm looking for. I just need to know how I can pass this parameter through the url, syntax-wise.
Routes file
GET /ListVehicleByPlateNumber controllers.NewVehicle.listVehicleByPlateNumber(para: String ?="")
Controller
public Result listVehicleByPlateNumber(String para){
NewVehicleModel v = new NewVehicleModel();
List<NewVehicleModel> vehiclesC = v.searchByPlateVehicle(para);
ObjectNode wrapper = Json.newObject();
ObjectNode msg = Json.newObject();
if(vehiclesC != null) {
msg.set("VehicleList", toJson(vehiclesC));
wrapper.set("success", msg);
return ok(wrapper);
}else{
msg.put("error", "There are no vehicles with the plate number");
wrapper.set("error", msg);
return badRequest(wrapper);
}
}
Where it's called
public List<NewVehicleModel> searchByPlateVehicle(String plateNumber){
Transaction t = Ebean.beginTransaction();
List<NewVehicleModel> vehicles = new ArrayList<>();
try {
String sql = "SELECT V.idNewVehicle, V.VehicleType,V.PlateNumber,V.VehicleJurisdiction,V.State,V.Vin,V.Year, " +
"V.Make,V.modelos,V.RegistrationNumber,V.InsuranceCompany,V.PurchaseDate,V.ExpirationDate,V.idPersonaFK " +
"FROM NewVehicle V " +
"WHERE V.PlateNumber = :plateNumber";
RawSql rawSql = RawSqlBuilder.parse(sql)
.columnMapping("V.idNewVehicle", "idNewVehicle")
.columnMapping("V.State", "state")
.columnMapping("V.VehicleType", "vehicleType")
.columnMapping("V.PlateNumber", "plateNumber")
.columnMapping("V.VehicleJurisdiction", "vehicleJurisdiction")
.columnMapping("V.Vin", "vin")
.columnMapping("V.Year", "year")
.columnMapping("V.Make", "make")
.columnMapping("V.modelos", "modelos")
.columnMapping("V.RegistrationNumber", "registrationNumber")
.columnMapping("V.InsuranceCompany", "insuranceCompany")
.columnMapping("V.PurchaseDate", "purchaseDate")
.columnMapping("V.ExpirationDate", "expirationDate")
.columnMapping("V.idPersonaFK", "idPersonaFK")
.create();
Query<NewVehicleModel> query = Ebean.find(NewVehicleModel.class);
query.setRawSql(rawSql)
.setParameter("plateNumber", plateNumber);
vehicles = query.findList();
t.commit();
}
catch (Exception e){
System.out.println(e.getMessage());
}finally {
t.end();
}
return vehicles;
}
Found my own answer. I ended up casting from Integer to String here's how it looks in routes
GET /ListVehicleByPlateNumber/:para controllers.NewVehicle.listVehicleByPlateNumber(para: Integer )
Controller
public Result listVehicleByPlateNumber(int para){
String p = String.valueOf(para);
URI Format for value 123 example.
http://localhost:9000/ListVehicleByPlateNumber/123

Compare field from previous row in JDBC ResultSet

I've researched can't find any relevant info. I have a result set that give me back distinct tagId's their can be multiple tagIds for same accountId's.
while(result_set.next()){
String tagId = result_set.getString("tagId");
String accountId = result_set.getString("accoundId");
// plenty of other fields being store locally
}
I need to store first accoundId(which is being done) & every subsequent iteration compare it with the previous Id to check for equality or not(if so same account).
I tried this and it failed horribly, after first iteration they'll continually be equal & I must be DUMB bc i though as long as I compare them before assignment global guy(previousId) should be holding the prior value.
String previousId = null;
while(result_set.next()){
String tagId = result_set.getString("tagId");
String accountId = result_set.getString("accoundId");
previousId = accountId;
}
Anyway I wanted my workflow to go something as follows:
while(result_set.next()){
if (previousId = null) {
// this would be the first iteration
}
else if (previousId.equals(accountId) {
// go here
} else {
// go here
}
}
If I've understood you well, this should work..
String previousId = null;
while(result_set.next()){
String tagId = result_set.getString("tagId");
String accountId = result_set.getString("accoundId");
if (previousId == null) {
// this would be the first iteration
} else if (previousId.equals(accountId) {
// go here
} else {
// go here
}
previousId = accountId;
}

Correct way to initialize wrapper Integer

I have a drop down field in application which displays numbers.
When user doesn't select any value from drop down, I would want to insert as null to database.
How can I initialize an Integer wrapper class to null?
I have tried as
Integer days = new Integer(null);
if (request.getParameter("days").equals("")) {
} else {
days =
Integer.parseInt(request.getParameter("days"));
}
However I am getting the following error, so what is the correct method in declaring Integer variable?
NumberFormatException at test.doPost(Controller.java:23);
How to initialize an Integer variable so that if no values are selected by user then null should get inserted.
You should initialize with null:
Integer days = null;
if (request.getParameter("days") != null && !request.getParameter("days").isEmpty()) {
days = Integer.parseInt(request.getParameter("days"));
}
UPDATE: Better to validate its an integer first:
Integer days = null;
if(request.getParameter("days")!=null && request.getParameter("days").matches("^\\d+$"))
{
days = Integer.parseInt(request.getParameter("days"));
}
UPDATE 2: To be able to insert null in DB:
if (project.getDays() != null)
callablestatement.setInt(2, project.getDays());
else
callablestatement.setNull(2, java.sql.Types.INTEGER);
What about setting the days object to null and then checking to see if the days object is null or is empty:
Integer days = null;
if (request.getParameter("days") != null && !request.getParameter("days").isEmpty()) {
// rest of code.
Apart from the declaration on which others have commented.
You are getting NumberFormatException because request.getParameter("days") is returning a non integer value text or null. parseInt method throws NumberFormatException when it gets a string input which is not a valid integer value.
You cannot trust the value of the days parameter in the request.
What if some client will pass an invalid value? (a non-number string).
For this reason you should catch NumberFormatException when you try to parse the parameter value.
Integer days = null;
String parameterValue = request.getParameter("days");
if (parameterValue != null && !parameterValue.isEmpty()) {
try {
days = Integer.parseInt(parameterValue);
} catch (NumberFormatException e) {
// log or something
}
}
With a try/catch:
Integer days = null;
try {
days = Integer.parseInt(request.getParameter("days"));
} catch (final NumberFormatException ex) {
// ignore
}
or with guava Ints
Integer days = null;
final String param = request.getParameter("days");
if (param != null) {
days = Ints.tryParse(param);
}
This way, you avoid the NumberFormatException if "days" is not parsable.
How about :
Integer days = null;
String param = request.getParameter("days");
if (param != null && !"".equals(param)) {
days = Integer.parseInt(request.getParameter("days"));
}

Categories

Resources