0

I wrote a small Java application that I compiled into an executable jar file. The program makes use of a .txt file that is compiled inside the jar file. In order to access the .txt file within the jar, you need to use ClassLoader.getSystemResourceAsSteam("");

Here is the method in the jar file:

 private ArrayList<String> loadChainRestaurantsList() throws IOException {
        ArrayList chains = new ArrayList();
        InputStream in = ClassLoader.getSystemResourceAsStream("chains.txt");
        BufferedReader reader = new BufferedReader(new InputStreamReader(in));

        String name;
        while((name = reader.readLine()) != null) {
            chains.add(name);
        }

        return chains;
    }

This code works if I run the jar from cmd-line as a standalone Java program, or from Eclipse. It even works if I export as a jar and then throw it into another Java program and use it, it works as expected. The problem is when I throw the jar into an Android project. I get this error:

FATAL EXCEPTION: AsyncTask #1
10-01 10:40:59.650 8821-8879/? E/AndroidRuntime: Process: com.jasonjohn.unchainedandroid, PID: 8821
10-01 10:40:59.650 8821-8879/? E/AndroidRuntime: java.lang.RuntimeException: An error occured while executing doInBackground()
10-01 10:40:59.650 8821-8879/? E/AndroidRuntime:     at android.os.AsyncTask$3.done(AsyncTask.java)
10-01 10:40:59.650 8821-8879/? E/AndroidRuntime:     at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:355)
10-01 10:40:59.650 8821-8879/? E/AndroidRuntime:     at java.util.concurrent.FutureTask.setException(FutureTask.java:222)
10-01 10:40:59.650 8821-8879/? E/AndroidRuntime:     at java.util.concurrent.FutureTask.run(FutureTask.java:242)
10-01 10:40:59.650 8821-8879/? E/AndroidRuntime:     at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java)
10-01 10:40:59.650 8821-8879/? E/AndroidRuntime:     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
10-01 10:40:59.650 8821-8879/? E/AndroidRuntime:     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
10-01 10:40:59.650 8821-8879/? E/AndroidRuntime:     at java.lang.Thread.run(Thread.java:818)
10-01 10:40:59.650 8821-8879/? E/AndroidRuntime:  Caused by: java.lang.NullPointerException: lock == null
10-01 10:40:59.650 8821-8879/? E/AndroidRuntime:     at java.io.Reader.<init>(Reader.java:64)
10-01 10:40:59.650 8821-8879/? E/AndroidRuntime:     at java.io.InputStreamReader.<init>(InputStreamReader.java:120)
10-01 10:40:59.650 8821-8879/? E/AndroidRuntime:     at java.io.InputStreamReader.<init>(InputStreamReader.java:57)
10-01 10:40:59.650 8821-8879/? E/AndroidRuntime:     at com.jasonjohn.unchainedapi.UnchainedAPI.loadChainRestaurantsList(UnchainedAPI.java:123)
10-01 10:40:59.650 8821-8879/? E/AndroidRuntime:     at com.jasonjohn.unchainedapi.UnchainedAPI.getUnchainedRestaurants(UnchainedAPI.java:71)
10-01 10:40:59.650 8821-8879/? E/AndroidRuntime:     at com.jasonjohn.unchainedandroid.MainActivity$UnchainedAsync.doInBackground(MainActivity.java:69)
10-01 10:40:59.650 8821-8879/? E/AndroidRuntime:     at com.jasonjohn.unchainedandroid.MainActivity$UnchainedAsync.doInBackground(MainActivity.java:62)
10-01 10:40:59.650 8821-8879/? E/AndroidRuntime:     at android.os.AsyncTask$2.call(AsyncTask.java)
10-01 10:40:59.650 8821-8879/? E/AndroidRuntime:     at java.util.concurrent.FutureTask.run(FutureTask.java:237)
10-01 10:40:59.650 8821-8879/? E/AndroidRuntime:     at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java) 
10-01 10:40:59.650 8821-8879/? E/AndroidRuntime:     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112) 
10-01 10:40:59.650 8821-8879/? E/AndroidRuntime:     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587) 
10-01 10:40:59.650 8821-8879/? E/AndroidRuntime:     at java.lang.Thread.run(Thread.java:818) 

I've never seen this error before. Can anyone explain what's going on? I'm assuming the InputStream/InputStreamReader is null, but I don't know how I'd fix this issue.

Jason John
  • 934
  • 2
  • 12
  • 23
  • 1
    What? Why don't you just take that text file out of the jar? Or you and unzip the jar and use the text file using http://stackoverflow.com/questions/1529611/how-to-write-a-java-program-which-can-extract-a-jar-file-and-store-its-data-in-s – Ya Wang Oct 01 '15 at 15:16
  • The txt in the jar is integral to the jar. If I take it out then I have to carry it around everywhere I put the jar. I'd rather package everything into the jar and only have to deal with one file – Jason John Oct 01 '15 at 15:22
  • 1
    Consider repackaging the jar as aar file so that you know where the text file will be: http://stackoverflow.com/questions/24309950/create-aar-file-in-android-studio – Morrison Chang Oct 01 '15 at 15:46
  • It is not an Android library, just a regular java program repurposed as a lib. Is it still possible to make an aar out of it? – Jason John Oct 01 '15 at 17:08
  • 1
    Out of curiosity, why are you using getSystemResourceAsStream instead of plain old getResourceAsStream("/chains.txt")? – Jamie Oct 01 '15 at 17:14
  • @Jamie it seems that when i tried this method before, I never had the '/' character. It seems to work great now. Could you make this into a real answer so I can accept it? – Jason John Oct 01 '15 at 17:38
  • @jaytj95, done and thanks! – Jamie Oct 01 '15 at 22:21

1 Answers1

1

You should probably use

getResourceAsStream("/chains.txt")

instead of using

getSystemResourceAsStream(...).

The / at the front of the path means to look in the root of the jar. Otherwise, it would look for chains.txt in the same package as the class that you got the classloader from. EG., if you do:

package com.potter.harry;
...
InputStream is = this.getClass().getResourceAsStream("chains.txt");

the referenced file would have to be placed at "/com/potter/harry/chains.txt" in the zip file.

Jamie
  • 1,888
  • 1
  • 18
  • 21