Java annotations: make #NotNull - java

I am learning Java annotations and I want to design a annotation like #NotNull which enforces compiler to throw an error on following:
#NotNull
private String myVar = null;
Now, I am not getting any lead in what to write in the body of the annotation:
#interface NotNull{
// what goes here
}
Can I design such a functionality using Annotations or I have read it all wrong? I am looking at the checker package and it contains one such annotation.

You can only define the "meta" properties themselves in annotations, no actual logic
For compile-time annotation logic you need to write an annotation-processor (regular java-code that gets executed during compilation and allows you to examine annotated elements using reflection), during runtime you can use the regular reflection API

Related

In what order are Java constraints being executed

I have a Java method in which the method itself is annotated with a constraint (cross-parameter) and the arguments are also annotated with constraints (#NotNull, #NotEmpty etc).
Is the method constraint validated after method argument validation or is the order of validation not specified?
Annotations don't inherently do anything. They just mark things. javac itself knows what #Deprecated and #Override and #FunctionalInterface mean, but the effects are always to either do nothing, or to generate a compiler error: These annotations do not cause the compiler to generate any code.
Aside from Project Lombok this is a general principle of annotations, and even Project Lombok is an annotation processor: You have to put lombok on your classpath during a compilation, or nothing happens.
In other words, it is not possible for the #NonNull annotation in your code to generate any null check all on its own. The constraints are applied elsewhere, or by a code generating annotation processor that you explicitly include by putting it on the classpath or passing it along as annotation processor. For example, it IS possible for code you invoke to introspect your method and notice things. Thus, you could for example have:
class Example {
#NotEmpty String name;
}
and then you can do:
new Example("");
and this won't cause an exception. But you could do:
Validator validator = SomeHypotheticalValidationLibrary.newValidator();
validator.validate(new Example(""));
and then this validator would produce an error stating that the instance you provided fails verification. This is an example of annotations being introspected.
And now to answer your question:
The order in which such constraints are validated depends entirely on the validation library you use to do the validation; out of the box, the annotation itself does not and cannot produce any validation code. You'd have to check the documentation of your validation library, and provide the context within which you are validating.
If you're talking specifically about lombok's #NonNull - lombok scans your code for null checks (either of the form if (x == null) throw new Something(); or of the form Objects.nullCheck or guava's nullcheck). If it finds a nullcheck for an #NonNull annotated parameter, lombok does nothing. If it doesn't, it generates a nullcheck after all your explicit null checks. Lombok stops scanning for nullchecks once it hits a line that is NOT a nullcheck (so, neither an if (x == null) nor a methodInvocation(x, "optional text");). #NonNull is currently the only annotation that causes lombok to generate validation code (there is no #lombok.NotEmpty).
We may be able to give more insights if you explain which annotation processors / validation frameworks you are using.

`ElementType.FIELD` vs `ElementType.TYPE_USE`

I not fully understand the difference between annotating variable and annotating its type.
Should I prefer type annotation over declaration annotation in this scenario?
#EmailField // can be used on String or Array/Collection of String-s
private String email;
private #EmailType String email2;
#EmailField
private List<#EmailType String> emails;
#Target(ElementType.TYPE_USE)
#interface EmailType {}
#Target(ElementType.FIELD)
#interface EmailField {}
Type annotations in Java 8 are mainly around to support stronger type checking.
From https://docs.oracle.com/javase/tutorial/java/annotations/type_annotations.html:
Type annotations were created to support improved analysis of Java
programs way of ensuring stronger type checking. The Java SE 8 release
does not provide a type checking framework, but it allows you to write
(or download) a type checking framework that is implemented as one or
more pluggable modules that are used in conjunction with the Java
compiler.
From your above example, you should use the #EmailField field annotation, and you should also add #Retention(RetentionPolicy.RUNTIME) so that you can use reflection to check for this annotation at runtime as follows:
#Target(ElementType.FIELD)
#Retention(RetentionPolicy.RUNTIME)
#interface EmailField {}
Here is the difference between declaration annotations and type annotations:
A declaration annotation on a field gives information about the variable, such as that the field is deprecated and clients should use a getter method instead.
A type annotation gives information about the value, such as that an integer value is greater than zero.
Your annotation gives information about the values: the string should be a legal email address. Therefore, you should use a type annotation, #EmailType (though I would just name it #Email).
You can validate a type annotation at compile time, run time, or both.
Simple example is still much easier to understand than many explanations.
TYPE_USE is use for this purpose :
private List<#ValidEmail String> emails;

Annotation applicable to specific data type

I don't know if the question I am asking is really stupid. But here it is:
I would like to write a custom annotation which should be applicable to a specific type. For example, if I have a class A, then I would like to have an annotation that can be applied on objects of A.
Something like this:
#Target({ElementType.FIELD, //WHAT_ELSE_HERE_?})
public #interface MyAnnotation {
String attribute1();
}
public class X {
#MyAnnotation (attribute1="...") //SHOULDN'T BE POSSIBLE
String str;
#MyAnnotation (attribute1="..") //PERFECTLY VALID
A aObj1;
#MyAnnotation (attribute1="...") //SHOULDN'T BE POSSIBLE
B bObj1;
}
Is that possible at all?
Not possible. #Target uses ElementType[], and ElementType is an enum, so you can't modify it. It does not contain a consideration for only specific field types.
You can, however, discard the annotation at runtime, or raise runtime exceptions about it.
That is not possible in Java.
But you have an option to write your own annotation processor if you want to check the correctness of the annotations before runtime.
Annotation processing is a hook in the compile process, to analyse the
source code for user defined annotations and handle then (by producing
compiler errors, compiler warning, emmiting source code, byte code
..).
A basic tutorial on Annotation Processing.

Inherit from field/method targeted annotation

I'm annotating my classes here and there and I find myself repeating the following:
public class Example
{
#Basic
#Convert("converter")
private AnotherExample ae;
}
To save me some hassle and to ensure correct usage I came up with the idea to create an annotation that inherits from both #Basic and #Convert("converter"). The problem is that both annotations have #Target(value={FIELD, METHOD}) and thus I cannot annotate my custom annotation with them.
Is there any other way to achieve my goal or is this a limitation of Java's annotations?
This is literally the diamond problem from multiple inheritance.
I would argue against trying to merge these annotations together. The point of inheritance is not to save typing. These two annotations are separate for a reason.
Most IDEs can create code from macros which will cut down on your typing. Otherwise, a search and replace regex would definitely work as well.

Java Annotation Processing Tool #NoNull

I want to create an annotation that restricts a developer from specifying null as a parameter, which has been annotated with #NoNull
For example, if I create this method:
public void printLine(#NoNull String line) {
System.out.println(line);
}
On a method call, I want an error to appear if the user specifies null for line: printLine(null);
I have been using APT for only a little bit of time, and am wondering how to do this (if possible)?
This is the annotation I have created so far:
#Target(ElementType.PARAMETER)
#Retention(RetentionPolicy.SOURCE)
public #interface NoNull {}
Compile time will be tough to check, since you're really dealing with runtime values. If you want to create annotations to automatically add code to check this stuff, you should look at project lombok:
http://projectlombok.org/
It uses an annotation processor to add code to your beans to do various things.
For example:
#Getter #Setter
private int id;
The annotation processor would automatically add get/set methods to your bean.
I don't think it has null checks, but you should be able to add this in and contribute it.
Another option is to use the validation jsr, though this requires you to explicitly validate at runtime, but you could accomplish this with proxies or AOP.
#NotNull #Min(1)
public void setId(Integer id)
The point isn't to use the annotation only for readability, but to enforce the annotation at compile-time with APT
Considering that null is a runtime artifact, I don't see how you will enforce a null check at "compile time."
Instead, you'll have to modify your classes, and apt is not the tool to do this, at least not by itself. It exists to extract information about annotated elements from source files. But to enforce your #Null restriction, you need to modify the running class.
One thing that you could do is use apt to extract information about annotated parameters, then use a tool like aspectj to modify those classes at runtime to check the parameter value.
But that's a topic that's way too broad for a single SO question.
#Nullable, #Nonnull are locating in package: javax.annotation
Checkout guava, its got some nice things are type safety:
http://code.google.com/p/guava-libraries/wiki/GuavaExplained

Categories