Making Java Code Null-Safe With JPlus
Null-pointer exceptions are a common error in Java, causing inconvenience for many developers. Preventing null pointer exceptions in advance is important, but for developers who want to focus solely on logic, handling them can be tedious. Moreover, it’s not always easy to account for every scenario. Typically, static analysis tools are used to detect potential null pointer issues, but developers still have to find and fix the code themselves. JPlus reduces that burden. Let’s write null-safe Java code with JPlus.
1. Access the JPlus GitHub repository and download the IntelliJ plugin
https://github.com/nieuwmijnleven/JPlus
2. nstall the JPlus IntelliJ plugin
- Open IntelliJ
- Go to
File > Settings > Plugin > ⚙️ > Install Plugin from Disk - Select the downloaded intellij-plugin-0.1-mvp-alpha.zip
- Restart IntelliJ
3. Open the example project in IntelliJ
- Go to
File > New > Project from Version Control - Enter
https://github.com/nieuwmijnleven/JPlusExample - Click the
Clonebutton
4. Create a JPlus file for User.java in the Project View
- Right-click User.java in the Project View
- Select Convert Java File to JPlus File from the menu
5. Making Java code null-safe with JPlus
User.jplus
package jplus.example;
class User {
// Name is required
String name;
// Address can be null
Address address;
User(String name, Address address) {
this.name = name;
this.address = address;
}
//remain codes
}
Opening the generated User.jplus file, you can see error messages in the Problems tab.
By default, JPlus assumes all reference types are non-nullable, which causes these errors. The problematic parts are where the constructors of the User and Address classes are called.
User(String name, Address address) {
this.name = name;
this.address = address;
}
Address(String city) {
this.city = city;
}
User user1 = new User("Jeroen", new Address("New Amsterdam"));
User user2 = new User("Jane Smith", null);
User user3 = new User(null, new Address(null));
- The constructor parameters for User and Address are all non-nullable. Passing null violates the null-safety rules.
- Therefore, errors occur for user2 and user3.
Making Java code null-safe with JPlus
(1) Assume the name field is required
- Add final to the name field
- Use apply constructor(required) to auto-generate the required constructor
- Press Ctrl + S to save, so changes reflect in User.java.
User.jplus
package jplus.example;
apply constructor(required);
class User {
// Name is required
final String name;
// Address can be null
Address address;
User(String name, Address address) {
this.name = name;
this.address = address;
}
//remain codes
}
- At the end, the generated User.java includes a constructor for the final name field.
(2) Assume the address field is nullable
- Add ? to the Address type
- Also mark the constructor parameter as nullable
package jplus.example;
apply constructor(required);
class User {
// Name is required
final String name;
// Address can be null
Address? address;
User(String name, Address? address) {
this.name = name;
this.address = address;
}
The Problems tab shows:
- address is a nullable variable. But it directly accesses city. Consider using null-safe operator(?.)
- Use the null-safe operator ?.:
// Safely get the city name of the address
String getCity() {
return address?.city;
}
Then only the constructor-related error for name remains.
Replace null with “No Name” because name field is required.
User user3 = new User("No Name", new Address(null));
Now only one error remains:
- The 1st argument of the Address constructor is a non-nullable variable, but a null value is assigned to it.
(3) Assume city in Address is nullable
- Add ? to String type and constructor parameter
static class Address {
// City can be null
String? city;
Address(String? city) {
this.city = city;
}
}
All nullability errors disappear. Save the file (Ctrl + S) to generate new User.java.
User.java made null-safe by JPlus
package jplus.example;
//apply constructor(required);
class User {
// Name is required
final String name;
// Address can be null
Address address;
public User(String name) {
this.name = name;
}
User(String name, Address address) {
this.name = name;
this.address = address;
}
// Safely get the city name of the address
String getCity() {
return (((address)!=null)?(address.city):null);
}
// Get the display name of the user
String getDisplayName() {
return name;
}
// Address class
static class Address {
// City can be null
String city;
Address(String city) {
this.city = city;
}
}
public static void main(String[] args) {
// Null-safe object creation
User user1 = new User("Jeroen", new Address("New Amsterdam"));
User user2 = new User("Jane Smith", null);
User user3 = new User("No Name", new Address(null));
// Null-safe access
System.out.println(user1.getDisplayName() + "'s city: " + user1.getCity()); // Jeroen's city: New Amsterdam
System.out.println(user2.getDisplayName() + "'s city: " + user2.getCity()); // Jane Smith's city: No Address
System.out.println(user3.getDisplayName() + "'s city: " + user3.getCity()); // No Name's city: No Address
}
}
Run the program:
- Go to User.java
- Select Run > ‘Run User.java’
No NullPointerException occurs, but some outputs are null. Use the Elvis operator ?: to provide default values.
Edit getCity() in User.jplus:
class User {
//...
// Safely get the city name of the address
String getCity() {
return address?.city ?: "No City";
}
//...
}
Also, be sure to press Ctrl + S to save. This ensures that the new Java code is saved in User.java.
User.java made null-safe by JPlus
package jplus.example;
//apply constructor(required);
class User {
// Name is required
final String name;
// Address can be null
Address address;
public User(String name) {
this.name = name;
}
User(String name, Address address) {
this.name = name;
this.address = address;
}
// Safely get the city name of the address
String getCity() {
return ((((((address)!=null)?(address.city):null))!=null)?((((address)!=null)?(address.city):null)):("No City"));
}
// Get the display name of the user
String getDisplayName() {
return name;
}
// Address class
static class Address {
// City can be null
String city;
Address(String city) {
this.city = city;
}
}
public static void main(String[] args) {
// Null-safe object creation
User user1 = new User("Jeroen", new Address("New Amsterdam"));
User user2 = new User("Jane Smith", null);
User user3 = new User("No Name", new Address(null));
// Null-safe access
System.out.println(user1.getDisplayName() + "'s city: " + user1.getCity()); // Jeroen's city: New Amsterdam
System.out.println(user2.getDisplayName() + "'s city: " + user2.getCity()); // Jane Smith's city: No Address
System.out.println(user3.getDisplayName() + "'s city: " + user3.getCity()); // No Name's city: No Address
}
}
Run the program:
- Go to User.java
- Select Run > ‘Run User.java’
All null values are replaced with “No City”
Summary
With JPlus, you can easily enforce null-safety in Java code. JPlus fully supports Java syntax, making it accessible for Java developers. The final code is converted to Java, allowing developers to review it. JPlus is still in its early stages and needs support from the Java community. Even small, regular contributions will help complete this project. Your support can make a real impact.








