A Java NullPointerException (NPE) is the exception the JVM throws when code uses a null reference as if it pointed to an object. For example, the code calls name.length() while name is null. Since Java 14 (JEP 358), the message names the exact variable, field or method result that was null, so the first step of every fix is to read that message.
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "String.length()" because "name" is null
at com.howtodoinjava.core.exceptions.SampleNPE.main(SampleNPE.java:12)
We meet NPEs in every app that reads data it does not control, such as a JSON field the client left out or a map lookup for a missing key. To fix an NPE, we either stop the null where it comes from, or we handle the null where we use the value.
The following example shows the common ways to do that in Java 21 and later, with the result of each line as a comment.
String name = null;
Map<String, Integer> ages = Map.of("Lokesh", 37);
int len = (name != null) ? name.length() : 0; // 0 (null check)
String checked = Objects.requireNonNull(name, "name must not be null"); // NPE: name must not be null (fail fast)
int optLen = Optional.ofNullable(name).map(String::length).orElse(0); // 0 (Optional)
boolean same = "Lokesh".equals(name); // false (no NPE)
String user = Objects.requireNonNullElse(name, "guest"); // "guest" (default value)
int age = ages.getOrDefault("Alex", 0); // 0 (no null from the Map)
Notice that only Objects.requireNonNull() still throws, on purpose, because it rejects the null at the first line that sees it.
Next, we look at the common causes with the message each one prints, and at when to check for null or reject it early. After that, we cover Optional, null-safe methods such as String.valueOf(), Java 21 case null, and annotations that find NPEs at build time.
1. What Is a Java NullPointerException?
A variable such as String name does not hold the text itself, because it holds a reference (a pointer to an object in memory). A null reference points to no object at all, so the JVM throws the NPE at the moment the code needs a real object behind the variable.
NullPointerException extends RuntimeException, which makes it an unchecked exception. So the compiler does not force us to catch it or declare it in a throws clause.
The JVM throws a NullPointerException for the following actions.
- Calling an instance method on a null reference.
- Reading or writing a field of a null reference.
- Reading the length of a null array, or reading or writing one of its slots.
- Throwing null as if it were an exception, for example throw error where error is null.
- Using null in a synchronized block.
- Assigning a null Integer to an int. Java converts the Integer to an int with a hidden method call (unboxing), and that call fails for null.
Some library methods also throw the NPE on purpose when they get a null argument that they do not accept, for example List.of(“Lokesh”, null) and Optional.of(null).
The smallest failing program declares a String, leaves it null and calls a method on it.
String name = null;
System.out.println(name.length()); // NullPointerException: Cannot invoke "String.length()" because "name" is null
2. Common Causes of NullPointerException
Most NPEs in real projects come from a short list of situations. Each row of the table shows a small snippet and the message that JDK 25 printed for it. The examples use a few music classes, namely a Playlist class with an owner field, and Song and Artist, which are records (short classes that only hold data).
| Cause | Code | Helpful message |
|---|---|---|
| Uninitialized field | playlist.owner.toUpperCase() | Cannot invoke “String.toUpperCase()” because “playlist.owner” is null |
| Uninitialized collection field | playlist.songs.add(song) | Cannot invoke “java.util.List.add(Object)” because “playlist.songs” is null |
| Map.get() miss, then unboxing | int age = ages.get(“Alex”); | Cannot invoke “java.lang.Integer.intValue()” because the return value of “java.util.Map.get(Object)” is null |
| Method returning null | genre = findGenre(“Yesterday”); genre.toUpperCase() | Cannot invoke “String.toUpperCase()” because “genre” is null |
| Array element is null | names[1].length() | Cannot invoke “String.length()” because “names[1]” is null |
| Array itself is null | scores.length | Cannot read the array length because “scores” is null |
| Chained calls | song.artist().name().length() | Cannot invoke “…Artist.name()” because the return value of “…Song.artist()” is null |
| synchronized on null | synchronized (lock) { } | Cannot enter synchronized block because “lock” is null |
| throw null | throw error; | Cannot throw exception because “error” is null |
In the chained-call row, we replaced the long class names with “…” to fit the table, whereas the real message contains com.howtodoinjava.core.exceptions.NpeCauses$Artist.name().
2.1. Uninitialized Fields and Collections
When nothing sets an object field, Java gives the field the default value null. A collection field is the most common trap, because the code creates the object first and calls add() on the field much later, when nobody remembers that the list was never created.
class Playlist {
String owner; // null
List<Song> songs; // null
}
Playlist playlist = new Playlist();
playlist.songs.add(song); // NPE: because "playlist.songs" is null
To fix an uninitialized collection field, we create the collection where we declare the field (List<Song> songs = new ArrayList<>();) and set required fields in the constructor.
Spring code can leave a field null in the same way, because Spring fills @Autowired fields only in objects that Spring itself creates. If we create a Spring bean with new instead of letting Spring autowire it, every @Autowired field stays null.
2.2. Unboxing a null Integer From a Map
In the example, the map has no key “Alex”, so ages.get(“Alex”) returns null, and the code assigns that null Integer to an int. To do that, Java calls intValue() on the Integer in hidden code, and that call fails on null. This line is hard to spot, because no method call is visible in the code.
Map<String, Integer> ages = new HashMap<>();
ages.put("Lokesh", 37);
int age = ages.get("Alex"); // NPE: Cannot invoke "java.lang.Integer.intValue()"
int safeAge = ages.getOrDefault("Alex", 0); // 0
Unboxing works the same way for all wrapper classes, and getOrDefault() is one of the HashMap methods that return a default value instead of null.
2.3. Chained Method Calls
A chain such as song.artist().name().length() has three places where a null can appear. Before Java 14, the stack trace showed only the line number, so we could not tell which call returned null. Since Java 14, the helpful message names the exact call that returned null, so chains are much simpler to debug.
Song song = new Song("Imagine", null);
int len = song.artist().name().length();
// NPE: Cannot invoke "...Artist.name()" because the return value of "...Song.artist()" is null
Long chains are still hard to protect against null. When a step in the chain can legitimately return nothing, like a song without an artist, the method can return an Optional (section 4.5), so the return type itself tells the caller that the value may be missing.
3. Reading the Helpful NullPointerException Message
The helpful message always has the same shape, namely “Cannot action because expression is null”. The action says what the JVM tried to do, and the expression says which value was null. The first “at” line of the stack trace adds the file name and line number.

Two settings change what the message shows.
- Local variable names appear only when the class file contains debug information (extra data, such as variable names, that the compiler can store). Maven stores it by default, whereas plain javac without the -g flag does not, so the message shows a slot number instead of the name.
- The JVM option -XX:-ShowCodeDetailsInExceptionMessages turns the helpful message off. The feature was off by default in Java 14 and is on by default since Java 15.
javac -g: Cannot invoke "String.length()" because "name" is null
javac (no -g): Cannot invoke "String.length()" because "<local1>" is null
-XX:-ShowCodeDetailsInExceptionMessages: java.lang.NullPointerException (no message)
The JVM builds the message only when code calls getMessage() or prints the exception, so the feature costs nothing for NPEs that are caught and ignored.
3.1. Message Variants and NPEs Without a Message
The JVM builds the first part of the message from the operation that failed, so reading a field, writing an array slot and calling a method each print a different sentence. In the table, the words load and store mean reading and writing one slot of an array. Each message comes from JDK 25, with the classes compiled with -g.
| Code | Helpful message |
|---|---|
| String o = playlist.owner; | Cannot read field “owner” because “playlist” is null |
| playlist.owner = “Lokesh”; | Cannot assign field “owner” because “playlist” is null |
| int s = scores[0]; | Cannot load from int array because “scores” is null |
| scores[0] = 5; | Cannot store to int array because “scores” is null |
| grid[1][0] = “x”; | Cannot store to object array because “grid[1]” is null |
| int first = counts()[0]; | Cannot load from int array because the return value of “Stats.counts()” is null |
The part after “because” names a local variable, a field path such as playlist.owner, an array element such as grid[1], or the return value of a method. So in a nested array, the message tells us which level was null, which the line number alone cannot do.
Only NPEs that the JVM throws get a helpful message. When our code creates the exception with new NullPointerException(), the JVM does not analyze it, so the message is whatever we passed to the constructor. The same goes for Objects.requireNonNull(), which creates the NPE in library code.
String owner = null;
String noMessage = new NullPointerException().getMessage(); // null
String ownMessage = new NullPointerException("owner is required").getMessage(); // "owner is required"
String unchecked = Objects.requireNonNull(owner); // NullPointerException, getMessage() returns null
String checked = Objects.requireNonNull(owner, "owner must not be null"); // NullPointerException: owner must not be null
Say an order service writes only e.getMessage() to its error dashboard. NPEs from the JVM show a full sentence there, whereas an NPE from requireNonNull(order) shows the word null and nothing else. We always pass a message to requireNonNull() that names the parameter, so the log line points to the bad value.
The helpful message also contains names from our source code, such as local variables, fields and methods. That detail belongs in the server log and not in an API error response, so a REST error handler logs the exception and returns a generic text to the client.
4. How to Avoid NullPointerException
The fixes fall into two groups. The first group handles null where we use the value, for example with a null check or a default value. The second group stops the null from being created at all, for example with empty collections and Optional. The second group removes more NPEs, because every caller benefits.
4.1. Check for null Before Using the Value
An if statement or the ternary operator handles the null case at the place where we use the value. The ternary operator picks one of two values in a single expression, as in the len2 line.
String name = null;
int len = 0;
if (name != null) {
len = name.length();
} // len = 0
int len2 = (name != null) ? name.length() : 0; // 0
String label = (name == null) ? "NA" : name; // "NA"
A null check is the right choice when null is a normal value, such as a form field that the user may leave empty. But when the same null check repeats in every method, we stop the null earlier, where it enters the code.
4.2. Call equals() on the Known Non-null Value
The call name.equals(“Lokesh”) throws an NPE when name is null. When we turn the call around and write “Lokesh”.equals(name), the call returns false, because the string literal is never null. Objects.equals() goes one step further and accepts null on both sides.
String name = null;
boolean byName = name.equals("Lokesh"); // NPE
boolean byLiteral = "Lokesh".equals(name); // false
boolean byObjects = Objects.equals(name, "Lokesh"); // false
boolean bothNull = Objects.equals(name, null); // true
The method String equals() compares the characters of both strings, so swapping the two sides changes only the null handling.
4.3. Use a Default Value Instead of null
Sometimes a fixed value can replace null, such as “guest” for a missing name. Since Java 9, the java.util.Objects class has methods for default values, and Map.getOrDefault() does the same for a missing map key.
String user = Objects.requireNonNullElse(name, "guest"); // "guest"
String generated = Objects.requireNonNullElseGet(name, () -> "guest-" + ages.size()); // "guest-1" (supplier runs only for null)
String text = Objects.toString(name, "-"); // "-"
int alexAge = ages.getOrDefault("Alex", 0); // 0
int lokeshAge = ages.getOrDefault("Lokesh", 0); // 37
A default value is right only when the default is a correct answer. If we return 0 for a missing age, the caller can no longer tell “age 0” from “age unknown”, whereas Optional (section 4.5) keeps that difference.
4.4. Return Empty Collections, Not null
A method that returns a list should return an empty list when there is nothing to return, so callers can loop over the result without a null check.
static List<Song> songsBy(String artistName, List<Song> library) {
if (artistName == null) {
return List.of(); // empty, immutable list
}
return library.stream()
.filter(s -> s.artist() != null && artistName.equals(s.artist().name()))
.toList();
}
int none = songsBy(null, library).size(); // 0
int beatles = songsBy("The Beatles", library).size(); // 1
The same rule works for arrays (new String[0]), maps (Map.of()) and strings (“”), wherever an empty value means the same as “nothing”. When the whole codebase follows the rule, most null checks disappear from the calling code.
4.5. Return Optional When a Result May Be Missing
Optional is a container object that holds one value or nothing. In the example, findGenre() knows only the genre of “Hey Jude”, so for any other title it returns an empty Optional, and the return type Optional<String> warns every caller that the result can be missing.
static Optional<String> findGenre(String title) {
return "Hey Jude".equals(title) ? Optional.of("pop") : Optional.empty();
}
String genre = findGenre("Hey Jude").orElse("none"); // "pop"
String missing = findGenre("Imagine").orElse("none"); // "none"
String artist = imagine.findArtist().map(Artist::name).orElse("unknown artist"); // "unknown artist"
Optional is designed for return values. In other places, it adds code but does not remove NPEs.
| Do | Do not |
|---|---|
| Return Optional<T> from a search method that may find nothing | Use Optional as a field, a method parameter or a collection element |
| Create the box with Optional.ofNullable(value) when the value may be null | Call Optional.of(null). The call throws NullPointerException. |
| Read the value with orElse(), orElseGet(), map() or ifPresent() | Call get() without a check. The call throws NoSuchElementException: No value present. |
| Return Optional.empty() for “no result” | Return null from a method declared to return Optional |
| Return an empty list for “no results” | Return Optional<List<T>> |
4.6. Prefer Primitives Where null Has No Meaning
A primitive variable (int, long, boolean) can never be null, because each primitive type has a default value, such as 0 or false. A wrapper type (Integer, Boolean) is the object version of a primitive, so it can be null, and unboxing then throws an NPE.
We use primitives for counters, sizes and flags, and wrappers only where “no value” is a real state, such as a database column that allows NULL. A primitive’s default value can hide a bug too, because an int field that was never set reads as 0.
4.7. Use String.valueOf() Instead of toString()
The call obj.toString() throws an NPE when obj is null, whereas String.valueOf(obj) returns the text “null”. Joining strings with + also turns null into the text “null”.
Object data = null;
String text = data.toString(); // NPE
String valueText = String.valueOf(data); // "null"
String greeting = "Hi " + name; // "Hi null"
String trap = String.valueOf(null); // NPE: Cannot read the array length because "value" is null
The last line is a trap. String.valueOf() has several overloads (versions with different parameter types), and a bare null makes the compiler pick the String.valueOf(char[]) overload, which reads the array length and throws. A variable of type Object picks the Object overload, which returns “null”, and so does a cast, as in String.valueOf((Object) null).
4.8. Use Apache Commons StringUtils for String Checks
Apache Commons Lang has versions of the common String checks that accept null. Projects that already use the library can call these methods instead of writing null checks.
boolean empty = StringUtils.isEmpty(null); // true
boolean notEmpty = StringUtils.isNotEmpty(null); // false
int length = StringUtils.length(null); // 0
boolean equal = StringUtils.equals(null, "a"); // false
Each method of StringUtils documents its result for null input.
5. Defensive Coding vs Fail-Fast
There are two ways to deal with a null argument. In defensive coding, each method checks for null and continues with a fallback value. In fail-fast code, the method rejects a null right away with a clear message, so the error shows up where the bad value enters the code. Both styles are right in different places, and the chart shows which one fits.

5.1. Fail Fast With Objects.requireNonNull()
Joshua Bloch gives the rule in Effective Java, “If a caller passes null in some parameter for which null values are prohibited, convention dictates that NullPointerException be thrown rather than IllegalArgumentException.” Objects.requireNonNull() does that in one line, and we pass our own message as the second argument.
static int lengthOf(String name) {
return name.length(); // fails deep inside the method
}
static String greet(String name) {
Objects.requireNonNull(name, "name must not be null"); // fails at the first line
return "Hello " + name;
}
int len = lengthOf(null); // NPE: Cannot invoke "String.length()" because "name" is null
String greeting = greet(null); // NPE: name must not be null
In a two-line method, both messages are clear. In a 50-line method that stores the argument in a field and uses the field much later, the NPE happens far from the bad call, and only the fail-fast check points to the caller that passed the null. We check required arguments at the start of public methods and constructors, so the rest of the code never deals with null.
5.2. Validate Record Components in the Compact Constructor
A record can have a compact constructor (a constructor without a parameter list), which runs before the fields are assigned. That makes the compact constructor the right place for fail-fast checks.
record Song(String title, Artist artist) {
Song {
Objects.requireNonNull(title, "title must not be null");
}
}
Song song = new Song(null, new Artist("Queen")); // NPE: title must not be null
After this check, no Song object with a null title can exist, so code that reads song.title() needs no null check.
5.3. Do Not Use null as a Mode Switch
Some methods behave differently when a parameter is null. For example, findSongs(artist, null) returns all songs, and findSongs(artist, “rock”) filters by genre, so every caller must know what null means here. A better design uses two methods with clear names, findSongs(artist) and findSongs(artist, genre), so the genre parameter becomes required and both methods can fail fast on null.
6. Operators and Methods That Are Safe With null
Some Java operators and statements accept null without throwing, and knowing them saves us from writing null checks we do not need.
6.1. instanceof Returns false for null
The instanceof operator returns false when the value is null, so a separate null check before instanceof adds nothing.
Object data = null;
if (data != null && data instanceof String s) { } // redundant null check
if (data instanceof String s) { } // same result, false for null
6.2. Static Members Through a null Reference
Static fields and methods belong to the class, not to an object. In fixes.maxSongs, the compiler uses only the declared type of fixes, which is NpeFixes, and never touches the object, so a null variable does not throw.
NpeFixes fixes = null;
int max = fixes.maxSongs; // 100 (no NPE; maxSongs is static)
The compiler warns about this code, and in real code we write NpeFixes.maxSongs, which shows at once that the field uses the static keyword.
6.3. switch With case null (Java 21)
A classic switch on a null String or enum throws an NPE before any case runs. Java 21 added pattern matching for switch (JEP 441), so a switch can have a case null branch that handles null like any other value.
String day = null;
switch (day) { // NPE: Cannot invoke "String.hashCode()" because "s0$" is null
case "SAT", "SUN" -> System.out.println("weekend");
default -> System.out.println("weekday");
}
static String dayType(String day) {
return switch (day) {
case null -> "unknown";
case "SAT", "SUN" -> "weekend";
default -> "weekday";
};
}
String unknown = dayType(null); // "unknown"
String weekend = dayType("SUN"); // "weekend"
The s0$ in the first message is a synthetic variable that the compiler created for the switch, so the helpful message cannot show a name from our source code. The case null label also works in a switch over Object values, and with it, describe(null) returns “no value”. Without case null, a switch still throws an NPE for null, even when it has a default branch. Pattern matching for switch is one of the Java 21 features.
7. Null-Safety Annotations and NullAway
In Java, a String parameter can always receive null, because the language has no way to say “this parameter is never null“. Annotations fill that gap. A static analysis tool (a tool that checks the code at build time without running it) reads them, so it finds possible NPEs during compilation.
JSpecify 1.0 is the common standard for these annotations, agreed on by Google, JetBrains, Oracle, Uber, Broadcom (the company behind Spring) and other members. Spring Framework 7, the version used by Spring Boot 4, marks its own API with JSpecify and checks it with NullAway. JSpecify has four annotations, and two of them cover most code.
- @NullMarked on a package or class makes every type inside non-null unless marked otherwise.
- @Nullable on a type means that the value can be null.
<dependency>
<groupId>org.jspecify</groupId>
<artifactId>jspecify</artifactId>
<version>1.0.1</version>
</dependency>
// package-info.java
@NullMarked
package com.example;
// SongService.java
public @Nullable String findGenre(String title) { // may return null
return genres.get(title);
}
public int genreLength(String title) {
String genre = findGenre(title);
return genre.length(); // NullAway: compile error
}
public void start() {
play(null); // NullAway: compile error, title is non-null
}
The annotations alone change nothing at run time, so a tool must read them. Error Prone is a Google tool that adds extra checks to the Java compiler, and NullAway, an open-source Error Prone plugin from Uber, fails the build at every place where code may dereference a null value. With Error Prone 2.50.0 and NullAway 0.14.2 on JDK 25, mvn compile reports both mistakes.
[ERROR] SongService.java:[17,17] [NullAway] dereferenced expression 'genre' is @Nullable
[ERROR] SongService.java:[25,10] [NullAway] passing @Nullable parameter 'null' where @NonNull is required
We fix both lines. The first becomes return genre == null ? 0 : genre.length();, and the second passes a real title, so the build passes. IntelliJ IDEA also reads JSpecify annotations and highlights the same lines in the editor. Older projects may use @Nullable and @NonNull from other packages, such as JetBrains, javax.annotation, Lombok or Checker Framework, but new code should use JSpecify.
8. NullPointerException FAQs
8.1. Should We Catch NullPointerException?
No, in almost every case. An NPE is a bug in the code, and a catch (NullPointerException e) block hides the bug and leaves the program in an unknown state, so we fix the cause with one of the techniques from section 4. The common exception is a top-level handler, such as the error handler of a web framework, which may log any RuntimeException and return an error response. Following the exception handling best practices, we use a try-catch block only where we can handle the error.
8.2. Should a Method Throw NullPointerException or IllegalArgumentException for a null Argument?
NullPointerException, because the JDK does the same. Objects.requireNonNull(), List.of(), Map.of() and Optional.of() all throw an NPE for null. We use IllegalArgumentException for arguments that are not null but have a wrong value, such as a negative quantity.
8.3. Does Java Have a Safe Navigation Operator Like ?. in Kotlin?
No. Java 25 has no ?. or ?? operator, but for a chain of getters, a chain of Optional.map() calls gives the same result.
String artistName = Optional.ofNullable(song).map(Song::artist).map(Artist::name).orElse("unknown"); // "unknown"
8.4. Why Does List.of() Throw NullPointerException?
The methods List.of(), Set.of() and Map.of() create unmodifiable collections, and by design these collections reject null elements, keys and values. List.of(“Lokesh”, null) throws an NPE without a helpful message, because the check sits inside the library code. When we need null entries, we use an ArrayList or HashMap, which accept them.
9. Conclusion
A NullPointerException means the code used a null reference as if it pointed to an object. Since Java 14, the message names the value that was null, which shows us where to start the fix.
To avoid NPEs, we fail fast with Objects.requireNonNull() where null is a bug, and we return empty collections and Optional where a result may be missing. We use defaults such as requireNonNullElse() and getOrDefault() where a default is correct, and we prefer forms that accept null, such as “literal”.equals(var) and Java 21 case null. Finally, JSpecify annotations with NullAway catch the remaining cases at build time instead of at run time.
10. References
- NullPointerException JavaDoc (Java 25)
- Objects JavaDoc (Java 25)
- Optional JavaDoc (Java 25)
- JEP 358: Helpful NullPointerExceptions
- JEP 441: Pattern Matching for switch
- JSpecify User Guide
Happy Learning !!
Using java’s feature Optional can be effectively avoid NPE and also can write maintainable code
Yes, you are right.
Thanks ;)
Very Nice Article as I many times faced NPE in code.
Unable to create service java.lang.NullPointerException
this is my error
7306-7306/org.pearlcom E/AndroidRuntime﹕ FATAL EXCEPTION: main
Process: org.pearlcom, PID: 7306
java.lang.RuntimeException: Unable to create service org.pearlcom.PearlcomService: java.lang.NullPointerException
at android.app.ActivityThread.handleCreateService(ActivityThread.java:2582)
at android.app.ActivityThread.access$1800(ActivityThread.java:135)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1278)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5021)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:827)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:643)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.NullPointerException
at org.pearlcom.PearlcomService.onCreate(PearlcomService.java:110)
at android.app.ActivityThread.handleCreateService(ActivityThread.java:2572)
at android.app.ActivityThread.access$1800(ActivityThread.java:135)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1278)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5021)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:827)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:643)
at dalvik.system.NativeStart.main(Native Method)
MY PEARLCOM SERVICE
package org.pearlcom;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import org.linphone.compatibility.Compatibility;
import org.linphone.core.LinphoneAddress;
import org.linphone.core.LinphoneCall;
import org.linphone.core.LinphoneCall.State;
import org.linphone.core.LinphoneCore;
import org.linphone.core.LinphoneCore.GlobalState;
import org.linphone.core.LinphoneCore.RegistrationState;
import org.linphone.core.LinphoneCoreException;
import org.linphone.core.LinphoneCoreFactory;
import org.linphone.core.LinphoneCoreListenerBase;
import org.linphone.core.LinphoneProxyConfig;
import org.linphone.mediastream.Log;
import org.linphone.mediastream.Version;
import android.app.Activity;
import android.app.AlarmManager;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.os.SystemClock;
import android.provider.MediaStore;
/**
*
*
* @Created by REVO-WISSE on 4/22/2015
*
*/
public final class PearlcomService extends Service {
/* Listener needs to be implemented in the Service as it calls
* setLatestEventInfo and startActivity() which needs a context.
*/
public static final String START_PEARLCOM_LOGS = ” ==== Phone information dump ====”;
public static final int IC_LEVEL_ORANGE=0;
/*private static final int IC_LEVEL_GREEN=1;
private static final int IC_LEVEL_RED=2;*/
public static final int IC_LEVEL_OFFLINE=3;
private static PearlcomService instance;
private final static int NOTIF_ID=1;
private final static int INCALL_NOTIF_ID=2;
private final static int MESSAGE_NOTIF_ID=3;
private final static int CUSTOM_NOTIF_ID=4;
public static boolean isReady() {
return instance != null && instance.mTestDelayElapsed;
}
/**
* @throws RuntimeException service not instantiated
*/
public static PearlcomService instance() {
if (isReady()) return instance;
throw new RuntimeException(“PearlcomService not instantiated yet”);
}
public Handler mHandler = new Handler();
// private boolean mTestDelayElapsed; // add a timer for testing
private boolean mTestDelayElapsed = true; // no timer
private NotificationManager mNM;
private Notification mNotif;
private Notification mIncallNotif;
private Notification mMsgNotif;
private Notification mCustomNotif;
private int mMsgNotifCount;
private PendingIntent mNotifContentIntent;
private PendingIntent mkeepAlivePendingIntent;
private String mNotificationTitle;
private boolean mDisableRegistrationStatus;
private LinphoneCoreListenerBase mListener;
public int getMessageNotifCount() {
return mMsgNotifCount;
}
public void resetMessageNotifCount() {
mMsgNotifCount = 0;
}
@Override
public void onCreate() {
super.onCreate();
// In case restart after a crash. Main in MainPearlcom
mNotificationTitle = getString(R.string.service_name);
// Needed in order for the two next calls to succeed, libraries must have been loaded first
LinphoneCoreFactory.instance().setLogCollectionPath(getFilesDir().getAbsolutePath());
LinphoneCoreFactory.instance().enableLogCollection(!(getResources().getBoolean(R.bool.disable_every_log)));
// Dump some debugging information to the logs
Log.i(START_PEARLCOM_LOGS);
dumpDeviceInformation();
dumpInstalledPearlcomInformation();
mNM = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
mNM.cancel(INCALL_NOTIF_ID); // in case of crash the icon is not removed
Intent notifIntent = new Intent(this, incomingReceivedActivity);
notifIntent.putExtra(“Notification”, true);
mNotifContentIntent = PendingIntent.getActivity(this, 0, notifIntent, PendingIntent.FLAG_UPDATE_CURRENT);
Bitmap bm = null;
try {
bm = BitmapFactory.decodeResource(getResources(), R.drawable.log);
} catch (Exception e) {
}
mNotif = Compatibility.createNotification(this, mNotificationTitle, “”, R.drawable.status_level, IC_LEVEL_OFFLINE, bm, mNotifContentIntent, true);
PearlcomManager.createAndStart(PearlcomService.this);
instance = this; // instance is ready once pearlcom manager has been created
PearlcomManager.getLc().addListener(mListener = new LinphoneCoreListenerBase(){
@Override
public void callState(LinphoneCore lc, LinphoneCall call, State state, String message) {
if (instance == null) {
Log.i(“Service not ready, discarding call state change to “,state.toString());
return;
}
if (state == State.IncomingReceived) {
onIncomingReceived();
}
if (state == State.CallUpdatedByRemote) {
// If the correspondent proposes video while audio call
boolean remoteVideo = call.getRemoteParams().getVideoEnabled();
boolean localVideo = call.getCurrentParamsCopy().getVideoEnabled();
boolean autoAcceptCameraPolicy = Preferences.instance().shouldAutomaticallyAcceptVideoRequests();
if (remoteVideo && !localVideo && !autoAcceptCameraPolicy && !PearlcomManager.getLc().isInConference()) {
try {
PearlcomManager.getLc().deferCallUpdate(call);
} catch (LinphoneCoreException e) {
e.printStackTrace();
}
}
}
if (state == State.StreamsRunning) {
// Workaround bug current call seems to be updated after state changed to streams running
if (getResources().getBoolean(R.bool.enable_call_notification))
refreshIncallIcon(call);
} else {
if (getResources().getBoolean(R.bool.enable_call_notification))
refreshIncallIcon(PearlcomManager.getLc().getCurrentCall());
}
}
@Override
public void globalState(LinphoneCore lc,GlobalState state, String message) {
if (state == GlobalState.GlobalOn) {
sendNotification(IC_LEVEL_OFFLINE, R.string.notification_started);
}
}
@Override
public void registrationState(LinphoneCore lc, LinphoneProxyConfig cfg, RegistrationState state, String smessage) {
// if (instance == null) {
// Log.i(“Service not ready, discarding registration state change to “,state.toString());
// return;
// }
if (!mDisableRegistrationStatus) {
if (state == RegistrationState.RegistrationOk && PearlcomManager.getLc().getDefaultProxyConfig() != null && PearlcomManager.getLc().getDefaultProxyConfig().isRegistered()) {
sendNotification(IC_LEVEL_ORANGE, R.string.notification_registered);
}
if ((state == RegistrationState.RegistrationFailed || state == RegistrationState.RegistrationCleared) && (PearlcomManager.getLc().getDefaultProxyConfig() == null || !PearlcomManager.getLc().getDefaultProxyConfig().isRegistered())) {
sendNotification(IC_LEVEL_OFFLINE, R.string.notification_register_failure);
}
if (state == RegistrationState.RegistrationNone) {
sendNotification(IC_LEVEL_OFFLINE, R.string.notification_started);
}
}
}
});
// Retrieve methods to publish notification and keep Android
// from killing us and keep the audio quality high.
if (Version.sdkStrictlyBelow(Version.API05_ECLAIR_20)) {
try {
mSetForeground = getClass().getMethod(“setForeground”, mSetFgSign);
} catch (NoSuchMethodException e) {
Log.e(e, “Couldn’t find foreground method”);
}
} else {
try {
mStartForeground = getClass().getMethod(“startForeground”, mStartFgSign);
mStopForeground = getClass().getMethod(“stopForeground”, mStopFgSign);
} catch (NoSuchMethodException e) {
Log.e(e, “Couldn’t find startGoreground or stopForeground”);
}
}
startForegroundCompat(NOTIF_ID, mNotif);
if (!mTestDelayElapsed) {
// Only used when testing. Simulates a 5 seconds delay for launching service
mHandler.postDelayed(new Runnable() {
@Override public void run() {
mTestDelayElapsed = true;
}
}, 5000);
}
//make sure the application will at least wakes up every 10 mn
Intent intent = new Intent(this, KeepAliveHandler.class);
mkeepAlivePendingIntent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_ONE_SHOT);
((AlarmManager) this.getSystemService(Context.ALARM_SERVICE)).setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP
, SystemClock.elapsedRealtime()+600000
, 600000
, mkeepAlivePendingIntent);
}
private enum IncallIconState {INCALL, PAUSE, VIDEO, IDLE}
private IncallIconState mCurrentIncallIconState = IncallIconState.IDLE;
private synchronized void setIncallIcon(IncallIconState state) {
if (state == mCurrentIncallIconState) return;
mCurrentIncallIconState = state;
int notificationTextId = 0;
int inconId = 0;
switch (state) {
case IDLE:
mNM.cancel(INCALL_NOTIF_ID);
return;
case INCALL:
inconId = R.drawable.phone_call_on;
notificationTextId = R.string.incall_notif_active;
break;
case PAUSE:
inconId = R.drawable.pause_on;
notificationTextId = R.string.incall_notif_paused;
break;
case VIDEO:
inconId = R.drawable.conf_video;
notificationTextId = R.string.incall_notif_video;
break;
default:
throw new IllegalArgumentException(“Unknown state ” + state);
}
if (PearlcomManager.getLc().getCallsNb() == 0) {
return;
}
LinphoneCall call = PearlcomManager.getLc().getCalls()[0];
String userName = call.getRemoteAddress().getUserName();
String domain = call.getRemoteAddress().getDomain();
String displayName = call.getRemoteAddress().getDisplayName();
LinphoneAddress address = LinphoneCoreFactory.instance().createLinphoneAddress(userName,domain,null);
address.setDisplayName(displayName);
Uri pictureUri = PearlcomUtils.findUriPictureOfContactAndSetDisplayName(address, getContentResolver());
Bitmap bm = null;
try {
bm = MediaStore.Images.Media.getBitmap(getContentResolver(), pictureUri);
} catch (Exception e) {
bm = BitmapFactory.decodeResource(getResources(), R.drawable.friends_on);
}
String name = address.getDisplayName() == null ? address.getUserName() : address.getDisplayName();
mIncallNotif = Compatibility.createInCallNotification(getApplicationContext(), mNotificationTitle, getString(notificationTextId), inconId, bm, name, mNotifContentIntent);
notifyWrapper(INCALL_NOTIF_ID, mIncallNotif);
}
public void refreshIncallIcon(LinphoneCall currentCall) {
LinphoneCore lc = PearlcomManager.getLc();
if (currentCall != null) {
if (currentCall.getCurrentParamsCopy().getVideoEnabled() && currentCall.cameraEnabled()) {
// checking first current params is mandatory
setIncallIcon(IncallIconState.VIDEO);
} else {
setIncallIcon(IncallIconState.INCALL);
}
} else if (lc.getCallsNb() == 0) {
setIncallIcon(IncallIconState.IDLE);
} else if (lc.isInConference()) {
setIncallIcon(IncallIconState.INCALL);
} else {
setIncallIcon(IncallIconState.PAUSE);
}
}
@Deprecated
public void addNotification(Intent onClickIntent, int iconResourceID, String title, String message) {
addCustomNotification(onClickIntent, iconResourceID, title, message, true);
}
public void addCustomNotification(Intent onClickIntent, int iconResourceID, String title, String message, boolean isOngoingEvent) {
PendingIntent notifContentIntent = PendingIntent.getActivity(this, 0, onClickIntent, PendingIntent.FLAG_UPDATE_CURRENT);
Bitmap bm = null;
try {
bm = BitmapFactory.decodeResource(getResources(), R.drawable.log);
} catch (Exception e) {
}
mCustomNotif = Compatibility.createNotification(this, title, message, iconResourceID, 0, bm, notifContentIntent, isOngoingEvent);
mCustomNotif.defaults |= Notification.DEFAULT_VIBRATE;
mCustomNotif.defaults |= Notification.DEFAULT_SOUND;
mCustomNotif.defaults |= Notification.DEFAULT_LIGHTS;
notifyWrapper(CUSTOM_NOTIF_ID, mCustomNotif);
}
public void removeCustomNotification() {
mNM.cancel(CUSTOM_NOTIF_ID);
resetIntentLaunchedOnNotificationClick();
}
public void displayMessageNotification(String fromSipUri, String fromName, String message) {
Intent notifIntent = new Intent(this, MainPearlcom.class);
notifIntent.putExtra(“GoToChat”, true);
notifIntent.putExtra(“ChatContactSipUri”, fromSipUri);
PendingIntent notifContentIntent = PendingIntent.getActivity(this, 0, notifIntent, PendingIntent.FLAG_UPDATE_CURRENT);
if (fromName == null) {
fromName = fromSipUri;
}
if (mMsgNotif == null) {
mMsgNotifCount = 1;
} else {
mMsgNotifCount++;
}
Uri pictureUri;
try {
pictureUri = PearlcomUtils.findUriPictureOfContactAndSetDisplayName(LinphoneCoreFactory.instance().createLinphoneAddress(fromSipUri), getContentResolver());
} catch (LinphoneCoreException e1) {
Log.e(“Cannot parse from address”,e1);
pictureUri=null;
}
Bitmap bm = null;
try {
bm = MediaStore.Images.Media.getBitmap(getContentResolver(), pictureUri);
} catch (Exception e) {
bm = BitmapFactory.decodeResource(getResources(), R.drawable.friends_on);
}
mMsgNotif = Compatibility.createMessageNotification(getApplicationContext(), mMsgNotifCount, fromName, message, bm, notifContentIntent);
notifyWrapper(MESSAGE_NOTIF_ID, mMsgNotif);
}
public void removeMessageNotification() {
mNM.cancel(MESSAGE_NOTIF_ID);
resetIntentLaunchedOnNotificationClick();
}
private static final Class[] mSetFgSign = new Class[] {boolean.class};
private static final Class[] mStartFgSign = new Class[] {
int.class, Notification.class};
private static final Class[] mStopFgSign = new Class[] {boolean.class};
private Method mSetForeground;
private Method mStartForeground;
private Method mStopForeground;
private Object[] mSetForegroundArgs = new Object[1];
private Object[] mStartForegroundArgs = new Object[2];
private Object[] mStopForegroundArgs = new Object[1];
private Class incomingReceivedActivity = MainPearlcom.class;
void invokeMethod(Method method, Object[] args) {
try {
method.invoke(this, args);
} catch (InvocationTargetException e) {
// Should not happen.
Log.w(e, “Unable to invoke method”);
} catch (IllegalAccessException e) {
// Should not happen.
Log.w(e, “Unable to invoke method”);
}
}
/**
* This is a wrapper around the new startForeground method, using the older
* APIs if it is not available.
*/
void startForegroundCompat(int id, Notification notification) {
// If we have the new startForeground API, then use it.
if (mStartForeground != null) {
mStartForegroundArgs[0] = Integer.valueOf(id);
mStartForegroundArgs[1] = notification;
invokeMethod(mStartForeground, mStartForegroundArgs);
return;
}
// Fall back on the old API.
if (mSetForeground != null) {
mSetForegroundArgs[0] = Boolean.TRUE;
invokeMethod(mSetForeground, mSetForegroundArgs);
// continue
}
notifyWrapper(id, notification);
}
/**
* This is a wrapper around the new stopForeground method, using the older
* APIs if it is not available.
*/
void stopForegroundCompat(int id) {
// If we have the new stopForeground API, then use it.
if (mStopForeground != null) {
mStopForegroundArgs[0] = Boolean.TRUE;
invokeMethod(mStopForeground, mStopForegroundArgs);
return;
}
// Fall back on the old API. Note to cancel BEFORE changing the
// foreground state, since we could be killed at that point.
mNM.cancel(id);
if (mSetForeground != null) {
mSetForegroundArgs[0] = Boolean.FALSE;
invokeMethod(mSetForeground, mSetForegroundArgs);
}
}
@SuppressWarnings(“deprecation”)
private void dumpDeviceInformation() {
StringBuilder sb = new StringBuilder();
sb.append(“DEVICE=”).append(Build.DEVICE).append(“\n”);
sb.append(“MODEL=”).append(Build.MODEL).append(“\n”);
//MANUFACTURER doesn’t exist in android 1.5.
//sb.append(“MANUFACTURER=”).append(Build.MANUFACTURER).append(“\n”);
sb.append(“SDK=”).append(Build.VERSION.SDK_INT).append(“\n”);
sb.append(“EABI=”).append(Build.CPU_ABI).append(“\n”);
Log.i(sb.toString());
}
private void dumpInstalledPearlcomInformation() {
PackageInfo info = null;
try {
info = getPackageManager().getPackageInfo(getPackageName(),0);
} catch (NameNotFoundException nnfe) {}
if (info != null) {
Log.i(“Pearlcom version is “, info.versionName + ” (” + info.versionCode + “)”);
} else {
Log.i(“Pearlcom version is unknown”);
}
}
public void disableNotificationsAutomaticRegistrationStatusContent() {
mDisableRegistrationStatus = true;
}
public synchronized void sendNotification(int level, int textId) {
String text = getString(textId);
if (text.contains(“%s”) && PearlcomManager.getLc() != null) {
// Test for null lc is to avoid a NPE when Android mess up badly with the String resources.
LinphoneProxyConfig lpc = PearlcomManager.getLc().getDefaultProxyConfig();
String id = lpc != null ? lpc.getIdentity() : “”;
text = String.format(text, id);
}
Bitmap bm = null;
try {
bm = BitmapFactory.decodeResource(getResources(), R.drawable.log);
} catch (Exception e) {
}
mNotif = Compatibility.createNotification(this, mNotificationTitle, text, R.drawable.status_level, level, bm, mNotifContentIntent, true);
notifyWrapper(NOTIF_ID, mNotif);
}
/**
* Wrap notifier to avoid setting the pearlcom icons while the service
* is stopping. When the (rare) bug is triggered, the pearlcom icon is
* present despite the service is not running. To trigger it one could
* stop pearlcom as soon as it is started. Transport configured with TLS.
*/
private synchronized void notifyWrapper(int id, Notification notification) {
if (instance != null && notification != null) {
mNM.notify(id, notification);
} else {
Log.i(“Service not ready, discarding notification”);
}
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public synchronized void onDestroy() {
LinphoneCore lc = PearlcomManager.getLcIfManagerNotDestroyedOrNull();
if (lc != null) {
lc.removeListener(mListener);
}
instance = null;
PearlcomManager.destroy();
// Make sure our notification is gone.
stopForegroundCompat(NOTIF_ID);
mNM.cancel(INCALL_NOTIF_ID);
mNM.cancel(MESSAGE_NOTIF_ID);
((AlarmManager) this.getSystemService(Context.ALARM_SERVICE)).cancel(mkeepAlivePendingIntent);
super.onDestroy();
}
public void setActivityToLaunchOnIncomingReceived(Class activity) {
incomingReceivedActivity = activity;
resetIntentLaunchedOnNotificationClick();
}
private void resetIntentLaunchedOnNotificationClick() {
Intent notifIntent = new Intent(this, incomingReceivedActivity);
mNotifContentIntent = PendingIntent.getActivity(this, 0, notifIntent, PendingIntent.FLAG_UPDATE_CURRENT);
if (mNotif != null) {
mNotif.contentIntent = mNotifContentIntent;
}
notifyWrapper(NOTIF_ID, mNotif);
}
protected void onIncomingReceived() {
//wakeup pearlcom
startActivity(new Intent()
.setClass(this, incomingReceivedActivity)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
}
public void tryingNewOutgoingCallButAlreadyInCall() {
}
public void tryingNewOutgoingCallButCannotGetCallParameters() {
}
public void tryingNewOutgoingCallButWrongDestinationAddress() {
}
public void onCallEncryptionChanged(final LinphoneCall call, final boolean encrypted,
final String authenticationToken) {
}
}
please help me
I am reverse geocoding in a class that extends intentservice. However, when I send the converted address to the main activity it throws the pesky npe besides having a result receive with the appropriate onreceived method. Here is the code
private void deliverResultToReceiver(int resultCode, String message) {
//mReceiver = new ResultReceiver(new Handler());
Bundle bundle = new Bundle();
try {
if (message != null || !””.equals(message))
bundle.putString(Constants.RESULT_DATA_KEY, message);
mReceiver.send(resultCode, bundle);
} catch (NullPointerException npe) {
// TODO Auto-generated catch block
npe.printStackTrace();
}
}
Is it android specific issue?? If yes, then please post your problem in any android forum. If it’s NPE problem, then please elaborate your problem, it’s not clear with existing description.
Another common source of NPE is iterating (especially with for-each loop where it is not so obvious) over a collection that is null, because
for (T t : collection) { … }
id expanded into
for (Iterator i = collection.iterator(); i.hasNext(); ) { … }
Most likely it happens when someone returns null from a method that is supposed to return a collection. But you have covered this already.
You are right. That’s why below initializations are often best approach to avoid NPE in such cases.
Lokesh,Isnt writing System.out.println(s)(where s is a String initialized as null) equivalent to System.out.println(s.toString()) ?
but its weird that first doesnt give NullPointerException and second will give NullPointerException.
I do not find it weird. It’s expected for me. Invoking a method on any uninitialized reference will always result into NullPointerException.
Good One Sir !!! Very Useful !!
Very useful my problem solved after applying what I have read here.
Thnx
nice blog..
point#6:
NPE in case calling String,valueOf(null)
java.lang.NullPointerException
at java.lang.String.(String.java:177)
at java.lang.String.valueOf(String.java:2840)
at exceptionTypes.Test.main(Test.java:12)
Correct. Because valueOf(….) is overloaded method. Here method calling finds closest match which turns out to be “String valueOf(char data[])” and it internally throws NPE.
If you use it with object reference (which is suggested in post) then everything will work fine:
public static String valueOf(Object obj) {
return (obj == null) ? "null" : obj.toString();
}
Good article
Good information.
very nice blog
I don’t totally agree with the instanceof part
if(object instanceof MyClass) will also be true if object = (MyClass) null, which may not be expected, just as a warning ;-) or am I wrong?
I created two classes Account.java and TestNPE.java
Below is testing code:
public class TestNPE
{
public static void main(String[] args)
{
Account object = new Account(1);
System.out.println(object instanceof Account);
object = null;
System.out.println(object instanceof Account);
object = (Account) null;
System.out.println(object instanceof Account);
}
}
Output is:
true
false
false
So “object = (Account) null;” actually does not make instanceof comparison true.
Am i missing anything???