I'm getting a NullPointerException in a Nokia S40.
I want to know what is causing this exception.
The device shows:
NullPointerException java/lang/NullPointerException
This error only occurs in the device, running in the emulator the application works fine.
I use microlog to debug my application. But the application works fine if the log is enabled.
Is there a way to get the stack trace when I get this NullPointerException? I don't need all details like the line number just which method cause this exception.
UPDATE: I installed the same application in another Nokia S40 and the same error didn't occur.
- Nokia 2660 - error
- Nokia 6131 - no error
UPDATE 2: Somehow I find what was causing the NullPointerException.
import javax.microedition.lcdui.Canvas;
import javax.microedition.lcdui.Graphics;
public class OuterClass extends Canvas {
private Config config;
public OuterClass() {
this.config = new Config();
}
public void paint(Graphics graphics) {
HelperClass helper = new HelperClass(this.config);
helper.doStuff();
}
public void dispose() {
this.config = null;
}
public class Config implements IConfig {
public int getSomething() {
// ...
}
}
}
public class HelperClass {
private IConfig config;
public HelperClass(IConfig) {
this.config = config;
}
public doStuff() {
config.getSomething(); // Here is thrown NullPointerException
}
}
In some situations a thread is started and call the OuterClass.dispose() before the helper.doStuff() causing the NPE. I think when I enabled the log it made the thread slower and helper.doStuff() was called when I expected it to be called.
You are not going to find any way to save a Throwable stack trace on a Nokia Series40 handset.
The usual brute force way of debugging JavaME application on Series40 is to modify your code to create a stack trace yourself in memory.
What I'm talking about is:
Each Thread that you can identify (including system callback threads) needs its own Stack object, containing strings. Obviously, this increases the memory footprint of your application somewhat but keeping it in memory should limit the impact on race conditions.
When your code enters a method, it adds the method signature to the current Thread Stack. When the method exits (and you better only have one exit point per method) it pops the top of the Stack.
You can add aditional debug info on the stack, like values of variables in different places of the code.
You don't necessarily need to add this to every single method in your code.
You can add try{}catch(Throwable){}
to the entry point of every thread you identified and either dump the stack in a file or on the screen (in a Form).
Obviously, this is not the kind of change you want to manually add in a lot of places in a large existing codebase. You can however make it part of your organisation coding standards for the future and write a source code parsing script to automatically add it to existing code.
I had some trouble in the past trying to print the stack trace to somewhere else than the standard output. The standard exception class doesn't provide the printStackTrace method that receives the output stream, therefore it only prints to the standard output stream.
It's possible, at least in Java SE, to redirect the java output stream to somewhere else by simply saying that System.out = . The PrintStream class receives an OutputStream, which means that you could create your own ByteArrayOutputStream, initialize a PrintStream, sets System.out to that stream, and then call ex.printStackTrace(). I don't have a J2ME environment here but I believe that, as long as it won't break when you try to set System.out to something else (nothing says that it's readonly in the docs), you should be able to do it.
After you do that, I would recommend writing it to a RecordStore that you have specifically for that, and then upload the records of that RecordStore to your server so you can get it.
I know it's not very easy but it may work. I would first test the System.out thing. If it works, everything else should work too.
My answer was wrong. As pointed out, the System.out and System.err fields are declared final. If you can't get the stack trace, and if you can't get the error when running the application on your emulator, try creating trace bullets on your code (alerts, logs, whatever you can) to isolate the piece of code where the problem is happening. It has to be something that could change between the emulator and the real device - for example, something related to retrieving/ saving records in a RecordStore, opening a Connection, etc... What did you try to do when you had the problem?
You could use Microlog to send an e-mail when the exception occurs.
Microlog
You could try catching the exception in some high-level try/catch block and then emailing the trace to yourself.