0

This code snippet is reading camera picture Exif metadata using ExifInterface: Apparently, one particular picture has no or invalid datetime and .getDateTime() is returning null. In the code I assign it to a long, dt, and that results in the exception that is shown below. Of course, if I un-comment the null-check just prior to the assignment, all is well.

So, I have 1 question and 1 lesson:

  1. I'm assuming getDateTime() is really the culprit. Can an assignment cause such a exception?

  2. As you see, the offending line is within try/catch but it wasn't catching it because I was catching only IOException. When it was changed to Exception, it caught.

             String latlong = "";
             long dt = 0;
             ExifInterface exifInterface;
             try {
                 exifInterface = new ExifInterface(pf.getAbsolutePath());
                 if (exifInterface != null)
                 {
                     float[] latLng = new float[2];
                     if (exifInterface.getLatLong(latLng)) { //file has exif latlong info
                         //etc, latLng[0] is your latitute value and latLng[1] your longitude value
                         latlong = latLng[0] + "," + latLng[1];
                     }
                     //if (exifInterface.getDateTime() != null)
                       dt = exifInterface.getDateTime();
                     picInfo.comments = exifInterface.getAttribute(ExifInterface.TAG_USER_COMMENT);
                 }
                 else
                 {
                     System.out.println(">>>>>>>>>>>>>ERROR: cameraPicTask.doInBackground");
                     System.out.println(">>>>>>>>>>>>>-----: null exifInterface for: " + pf.getAbsolutePath());
                 }
             } catch (IOException e) {
                 e.printStackTrace();
             }
    
    E/AndroidRuntime: FATAL EXCEPTION: AsyncTask #2
    Process: com.example.mypics, PID: 7912
    java.lang.RuntimeException: An error occurred while executing doInBackground()
        at android.os.AsyncTask$4.done(AsyncTask.java:415)
        at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:383)
        at java.util.concurrent.FutureTask.setException(FutureTask.java:252)
        at java.util.concurrent.FutureTask.run(FutureTask.java:271)
        at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:305)
        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:920)
     Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'long java.lang.Long.longValue()' on a null object reference
        at com.example.mypics.PicsActivity$cameraPicTask.doInBackground(PicsActivity.java:211)
        at com.example.mypics.PicsActivity$cameraPicTask.doInBackground(PicsActivity.java:185)
        at android.os.AsyncTask$3.call(AsyncTask.java:394)
        at java.util.concurrent.FutureTask.run(FutureTask.java:266)
        at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:305) 
        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:920) 
Hong Son
  • 21
  • 2

1 Answers1

3

It seems exifInterface.getDateTime() returns a Long, and in this case, it returns null. You assign it to long dt which involves an unboxing operation. The compiler emits code to convert the Long to a long by calling longValue() on it, which throws the NPE. You can see it in your stack trace:

Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'long java.lang.Long.longValue()' on a null object reference

Even if you were to assign it to a Long first:

Long dateTime = exifInterface.getDateTime();
long dt = dateTime;

it would still have to unbox it, and thus, yes, an assignment can throw a NullPointerException.

David Conrad
  • 15,432
  • 2
  • 42
  • 54
  • 1
    Another lesson learned: Long is not long and a good coder must think like a compiler. Thanks David... – Hong Son Mar 11 '22 at 09:47
  • @HongSon Yes, among other things, Java generics can (currently) only use reference types, so for instance you can't have a list of primitive types like `List` or `List`. Thus, `Long` and "boxing" is needed. There is a plan for a future version of Java that would allow generics with primitive types (Project Valhalla), although when that will become available is yet to be seen. – David Conrad Mar 11 '22 at 18:36