Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JetBrains' @NotNull works only when project built from IDEA

I wrote a simple project to learn how to work with annotation validation. For that puspose I added maven dependency (also I tried javax.validation, that does not work for me):

<dependency>
    <groupId>org.jetbrains</groupId>
    <artifactId>annotations</artifactId>
    <version>15.0</version>
</dependency> 

and used it this way:

public boolean add(@NotNull T entry){ ...

When I build the project from IDEA, everything is fine, but it does not work when compiling the code with maven command. In decompiled class file I noticed that IDEA compiles my classes in different way. It adds this check:

if (entry == null) {
    $$$reportNull$$$0(0);
}

And maven does not.

I'm I doing something wrong? Please, tell me how it should be used (no matter jetbrains or javax validation).

like image 410
Grofight Avatar asked Oct 22 '25 06:10

Grofight


2 Answers

Partially guessing here: you see, it is not "IDEA" that puts that extra check into the byte code.

The thing is: annotations can also be used to generate code (see here for some further reading). And as you can see from that link; the core thing for code generation is: that annotation requires a javax.annotation.processing.Processor class. And that will be used by the compiler to turn the source code annotation into something reasonable within byte code.

If I get you right, you failed to get those javax parts setup for your maven compile. So probably the one part is missing there; so the solution is to fix your maven setup to provide all required dependencies.

like image 169
GhostCat Avatar answered Oct 23 '25 21:10

GhostCat


As noted by other answers, Intellij implemented a process to add the null checks to your code before it is compiled. There is one unofficial maven plugin (https://github.com/osundblad/intellij-annotations-instrumenter-maven-plugin) and some forks of it, but it is not longer maintained (last change was over a year ago) and I couldn't get it to work.

Thus, I recommend using another annotation instead. In my project, I switched to Lombok instead, which also has some nice additional features. To get it to work, you explicitly need to tell Lombok to throw another exception. See this working example:

Prequisites:

You need to add the lombok dependency to your maven pom.xml (find the latest version here):

<dependencies>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>${lombok.version}</version>
        <scope>provided</scope>
    </dependency>
</dependencies>

In your root directory (inside the folder, that contains 'src') create a lombok.config with the following content:

lombok.nonNull.exceptionType=IllegalArgumentException

1. Use case

Now you can use the @NonNull annotation for parameters and the null-checks will be generated automatically. You probably also need to add the maven-surefire-plugin to your pom.xml.

2. Use case

There is a neat possibility to let Lombok figure out itself, when the null check is necessary and when not for constructors. The following code will generate a constructor with to parameters (list1, list2). But it will only throw an IllegalArgmentException/NullPointerException, if the argument 'list1' is null, because list2 is not annotated with @NonNull.

import lombok.RequiredArgsConstructor;
import java.util.List;

@RequiredArgsConstructor
public class A {

    @NonNull
    private final List<String> list1;

    private final List<String> list2;
    
    ...
}
like image 43
Martin del Necesario Avatar answered Oct 23 '25 22:10

Martin del Necesario