JPlus: A Modern Java Superset Language
JPlus is a modern Java superset that introduces null-safety and boilerplate code-generation syntax while preserving Java compatibility.
Join the DZone community and get the full member experience.
Join For FreeJPlus is a Java superset language running on the JVM that enhances developer productivity while staying fully compatible with the Java ecosystem.
Why Support JPlus?
JPlus fills a unique gap in the Java ecosystem:
- Maintains 100% Java syntax compatibility
- Introduces null safety(?), null-safety operator(?.), boilerplate code generating syntax(apply), and Elvis Operator(?:) features
- Allows gradual adoption alongside existing Java code
- Compiles directly to plain Java code
Watch the demo video:
Currently, no other language extends Java in this way while keeping the syntax familiar to Java developers.
Key Features
- Strict null checking – prevents null reference errors at compile time
- Null-safety operator – use
?.operators to safely access nullable variables without riskingNullPointerException - Boilerplate code-generating syntax – replace common boilerplate like getters, setters, constructors, and builders without Lombok
- Elvis operator – Simplify null checks with
?:to provide default values when a variable is null
Example 1: Combining ?. and ?: Operators
JPlus supports combining the null-safe access operator (?.) and the Elvis operator (?:)
to simplify complex null-handling logic into clean and concise expressions.
Example: NullsafeWithElvisOperator.jplus
package jplus.example;
public class Main {
public static void main(String[] args) {
String? s1 = null;
String s2 = s1 ?: "jplus";
System.out.printf("the length of s1 : %d\n", s1?.length() ?: 0);
System.out.printf("the length of s2 : %d\n", s2.length());
}
}
s1is a nullable variable.s1 ?: "jplus"→ assigns"jplus"ifs1is null.s1?.length() ?: 0→ safely callslength()ons1, returns0ifs1is null.- By combining both operators, null handling becomes safe and concise.
Output (Java Code Generated by JPlus)
package jplus.example;
public class Main {
public static void main(String[] args) {
String s1 = null;
String s2 = (((s1) != null) ? (s1) : "jplus");
System.out.printf(
"the length of s1 : %d\n",
(((((s1 != null) ? s1.length() : null)) != null)
? (((s1 != null) ? s1.length() : null))
: 0));
System.out.printf("the length of s2 : %d\n", s2.length());
}
}
The expression s1?.length() ?: 0 is translated into a nested conditional check in Java: ((s1 != null) ? s1.length() : null) != null ? ... : 0, ensuring safe execution.
Example 2: Using Apply for Data Class and Nested Class Boilerplate Elimination
JPlus introduces the apply keyword to replace common Java boilerplate code, such as getters, setters, constructors, builders, and more. It serves as a language-level alternative to Lombok annotations, offering a clean and declarative syntax.
Example: ApplyStatement.jplus
package com.example;
apply data, constructor(required, all, no), builder;
apply {
User.Profile: getter, setter, equality, constructor(all);
}
public class User {
private String name;
private int age;
public class Profile {
String nickname;
}
}
data: Automatically generates getters, setters, equals(), hashCode(), and toString()builder: Generates a User.Builder class for fluent object creationconstructors(required, all, no): Generates a constructor with all/required fields and a no-argument constructorequality: Generates equals() and hashCode() methodsapply { User.Profile: ... }: Applies boilerplate generation specifically to the Profile inner class
Output (Java Code Generated by JPlus)
package com.example;
//apply data, constructor(required, all, no), builder;
//apply {
// User.Profile: getter, setter, equality, constructor(all);
//}
public class User {
private String name;
private int age;
public User(String name, int age) {
this.name = name;
this.age = age;
}
public User() {}
public class Profile {
String nickname;
public Profile(String nickname) {
this.nickname = nickname;
}
public String getNickname() {
return nickname;
}
public void setNickname(String nickname) {
this.nickname = nickname;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Profile profile = (Profile) o;
return java.util.Objects.equals(nickname, profile.nickname);
}
@Override
public int hashCode() {
return java.util.Objects.hash(nickname);
}
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "User{" + "name=" + name+ ", " + "age=" + age + "}";
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
User user = (User) o;
return age == user.age
&& java.util.Objects.equals(name, user.name);
}
@Override
public int hashCode() {
return java.util.Objects.hash(name, age);
}
public static class Builder {
private String name;
private int age;
public Builder name(String name) {
this.name = name;
return this;
}
public Builder age(int age) {
this.age = age;
return this;
}
public User build() {
return new User(name, age);
}
}
public static Builder builder() {
return new Builder();
}
}
This allows developers to keep code DRY and expressive, even with deeply nested structures.
Current Status
- MVP (Minimum Viable Product) stage
- IntelliJ Plugin 0.1 MVP Alpha released with:
- Syntax highlighting, code completion, and error checking
- Nullability checks
- Seamless integration with existing Java projects
Resources
Opinions expressed by DZone contributors are their own.
Comments