Annotation applicable to specific data type - java

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.

Related

Java Annotations in narrow scope

If we have an annotation that is used to set certain Class-specific Constants, declared this way:
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
public #interface Tooltip {
String value();
}
Used like so:
package applicationroot
#Tooltip("createCubeTool.tipText")
public class CreateCubeTool extends EditingTool
{
}
with this in the supertype:
public abstract class EditingTool
{
public String getToolTipText()
{
//Don't worry about this, other than that it requires a custom value Per Concrete class.
return null == tooltip ? null : Translate.text(tooltip.value());
}
}
Where should the annotation be declared?
Leaving aside questions regarding the overall structure of the project, it occurred to me that this particular annotation is only useful in subclasses of the scope of the ModelingTool type. Does it make sense to declare it in an entirely separate package, package applicationroot.tool.annotations; as one contributor suggested, or would it be better declared as a member of the ModelingTool type that uses it?
All references that I have found so far talk about how to declare a custom annotation, but not where they fit into a project's overall structure.
In general, if the text is variable for some reasons, for example it needs to be formatted or transformed before output, declaring it as an instance member maybe the better idea.
On the contrary, a decided CONSTANT can be defined in the meta info of an annotation. Remarkably, you have to use reflection to get the meta info which may degrade performance. The reflection brings a deep call stack.
In this case, I don't think it's worth using annotation. You have little expected benefit from the refactor, except an ostensibly elegant code.

`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;

Is extending an annotation interface meaningless and discouraged?

Here's an example of it in the JavaDoc of AnnotationLiteral e.g.
"An instance of an annotation type may be obtained by subclassing AnnotationLiteral."
public abstract class PayByQualifier extends AnnotationLiteral<PayBy> implements PayBy {
}
PayBy paybyCheque = new PayByQualifier() {
public PaymentMethod value() {
return CHEQUE;
}
};
There is a more complete example in Section 5.6.3 in the CDI spec.
5.6.3. Using AnnotationLiteral and TypeLiteral
javax.enterprise.util.AnnotationLiteral makes it easier to specify qualifiers when calling select():
#Qualifier
#Retention(RUNTIME)
#Target({METHOD, FIELD, PARAMETER, TYPE})
public #interface Synchronous {}
#Qualifier
#Retention(RUNTIME)
#Target({METHOD, FIELD, PARAMETER, TYPE})
public #interface PayBy {
PaymentMethod value();
#Nonbinding String comment() default "";
}
public PaymentProcessor getSynchronousPaymentProcessor(PaymentMethod paymentMethod) {
class SynchronousQualifier extends AnnotationLiteral<Synchronous>
implements Synchronous {}
class PayByQualifier extends AnnotationLiteral<PayBy>
implements PayBy {
public PaymentMethod value() { return paymentMethod; }
}
return anyPaymentProcessor.select(new SynchronousQualifier(), new PayByQualifier()).get();
}
And finally according to section 9.6 of the Java annotation types spec.:
Unless explicitly modified herein, all of the rules that apply to normal interface declarations apply to annotation type declarations.
For example, annotation types share the same namespace as normal class and interface types; and annotation type declarations are legal wherever interface declarations are legal, and have the same scope and accessibility.
However, the Java compiler complains when I attempt to implement an annotation. In particular, Intellij warns:
"Reports any classes declared as implementing or extending an annotation interface. While it is legal to extend an annotation interfaces, IT IS NEARLY MEANINGLESS, AND DISCOURAGED." (emphasis mine).
Here is the error message as displayed from within Intellij:
The Intellij warning seems to contradict the official Java documentation. I presume the Intellij warning is based upon a warning that comes from the Java compiler. What is correct? The Intellij and/or compiler warning or the documentation?
Annotations types are used as meta data. The typical use case for annotations, at runtime, is with reflection. You annotate something, then you use reflection to retrieve the annotation, process it, and possibly enhance the target. The annotation instances are created and given to you by the JVM through calls to the reflection API.
In that regard, creating your own annotation type instances, which AnnotationLiteral makes easier to do, is kind of pointless since you have no target, since nothing was actually annotated.
It can be useful for cases where you need to mock an annotation type instance or you want to inject some functionality that only exists when processing annotations.
Intellij is simply warning you that it's uncommon.
From Intellij support:
"We can change warning text for example to: "While it is legal to extend an annotation interface it is often done by accident, and the result won't be usable as an annotation." Note that you can always suppress the warning for the statement."
My response:
The proposed solution... would require developers to always suppress the warning for the statement. This solution is poor because the code would be littered with #SuppressWarning or, worse, the developer would need to turn off the warning altogether. The best and most useful solution, would be to not display any warning whatsoever if the developer extends AnnotationLiteral or TypeLiteral and implements an #interface at the same time.
A YouTrack Issue was filed.

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

Creating Custom Annotation in Java to force UPPER or lower Case

Appreciate any help for creating custom annotation in JAVA by forcing Upper or Lower case for a pojo field. Like to get something like below
// CaseMode enum would be
public enum CaseMode {
UPPER, LOWER;
}
#Target({ ElementType.FIELD, ElementType.METHOD })
#Retention(RetentionPolicy.RUNTIME)
public #interface Case {
// NEED HELP HERE
}
public class Customer {
#Case(value=CaseMode.UPPER)
private String fName;
{ set; get; }
}
setter method in Customer Object by default should force data to be stored in UPPERCASE or LOWERCASE based on annotation. Appreciate any help to get this.
Thanks in advance
Annotations are passive elements in Java; they can not have any behavior. As #maba said, you can not write any code inside an annotation declaration.
In order to have something similar to what you are trying to do, you need something which detects the annotation and performs some work. You have a few choices.
Compile-time annotation processing
Aspect-oriented programming
Dynamic proxies / Code generation libraries
Writing a custom compile-time annotation processor allows you to preprocess the source code before compilation.
Aspect oriented programming can work both at compile and at run time. It's relatively easy to understand, needs however some tooling to be set up together with your project, depending where you deploy it.
Dynamic proxies are simple as well, but you need to change the way your code accesses the objects, probably by declaring some interfaces and using those instead of the classes, etc.
Code generation libraries fall on the complex side of the spectrum, giving lots of flexibility (they are for instance how Hibernate does its magic with your POJO objects).
Your statement // NEED HELP HERE should be according to the following:
#Target({ElementType.FIELD, ElementType.METHOD})
#Retention(RetentionPolicy.RUNTIME)
public #interface Case {
CaseMode value();
}
If you think that you can have some code in there then you are wrong.

Categories