I need to create Custom annotation in java to check null value *i.e
#NonNull
public void test(String [] input , String str){
}
How to add the annoation to input and str fields
When creating your Annotation class, you have to add the #Target annotation to mark where this Annotation is valid. For parameters this would be ElementType.PARAMETER.
This minimal example will compile. (The Interface is a private nested class here, but you will want to define it in its own .java file)
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.PARAMETER)
private static #interface NonNull {
}
public void test(#NonNull String[] input, #NonNull String str) {
}
Note that this does not provide any null-checking, but tells the caller that this parameters may not be null in the function.
I'm pretty sure you can implement some kind of null-checking in the annotation class, but I'm not sure, so that has to be answered by someone else or you can probably look at some existing implementations of #NonNull interfaces.
Related
I have a method
public static void injectConfiguration(#Configurable Object bean) {}
And I have a class which holds field
public class LauncherComponentsHolder {
#Configurable
public RoomDao roomDao;
And I have main class, where I call that method and pass him that:
LauncherComponentsHolder root = new LauncherComponentsHolder();
root.roomDao = new RoomDaoImpl();
root.guestDao = new GuestDaoImpl();
root.maintenanceDao = new MaintenanceDaoImpl();
ConfigInjector.injectConfiguration(root.roomDao);
ConfigInjector.injectConfiguration(root.guestDao);
ConfigInjector.injectConfiguration(root.maintenanceDao);
Problem is that the method accepts all the 3 parameters, (no warnings, errors, nothing) however only roomDao is annotated. Annotation itself:
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.PARAMETER, ElementType.FIELD})
public #interface Configurable {
}
How to make the restriction, so that injectConfiguration(#Configurable Object bean) would accept only field (or class instance) annotated with Configurable ?
You can accomplish this by using an annotation processor.
An example of such a tool is the Checker Framework.
It enables you to write type annotations in your program, then it type-checks the type annotations at compile time. It issues a warning if the type annotations in your program are not consistent with one another.
The easiest way for you to implement the checking would be to use the Subtyping Checker.
Here is an example from its manual:
import myPackage.qual.Encrypted;
...
public #Encrypted String encrypt(String text) {
// ...
}
// Only send encrypted data!
public void sendOverInternet(#Encrypted String msg) {
// ...
}
void sendText() {
// ...
#Encrypted String ciphertext = encrypt(plaintext);
sendOverInternet(ciphertext);
// ...
}
void sendPassword() {
String password = getUserPassword();
sendOverInternet(password);
}
When you invoke javac using a couple extra command-line arguments, javac issues an error for the second invocation of sendOverInternet but not the first one:
YourProgram.java:42: incompatible types.
found : #PossiblyUnencrypted java.lang.String
required: #Encrypted java.lang.String
sendOverInternet(password);
^
My question is related to Java: Annotated Annotations (and passing values), but not entirely the same, so I thought I'd ask anyway. Especially since there were so few answers to that question.
Say I have written an annotation like this:
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.TYPE})
public #interface NestedAnnotation {
public String value();
public Class<?> impl() default Void.class;
}
So if I want to use this, I have to do something like #NestedAnnotation("somevalue"). Now, what if I want to put that annotation inside another one:
#Target({ElementType.TYPE})
#Retention(RetentionPolicy.RUNTIME)
#NestedAnnotation("need value here!")
public #interface OuterAnnotation {
public String value();
public Class<?> impl() default Void.class;
}
The NestedAnnotation needs a value, and adding a String (like above) works. But what if I wanted to pass on a value that was received by the OuterAnnotation? Is that possible?
I have an annotation like this:
#Inherited
#Documented
#Target(value={ElementType.TYPE})
#Retention(RetentionPolicy.RUNTIME)
public #interface Restful {
}
I annotated this class like this:
#Restful
public class TestAspect {
public String yes;
}
I have a pointcut like this:
#Pointcut("#annotation(com.rest.config.Restful)")
public void pointCutMethod() {
}
I tried:
#Before("pointCutMethod()")
public void beforeClass(JoinPoint joinPoint) {
System.out.println("#Restful DONE");
System.out.println(joinPoint.getThis());
}
But getThis() returns null.
Basically I am trying to get that Object instance of TestAspect. How do I do it? Any clue? any help would be really appreciated.
Thanks in advance
With your annotation placed on the type only and the pointcut #annotation(com.rest.config.Restful) you are only going to match the static initialization join point for your type. As we can see if you use -showWeaveInfo when you compile (I slapped your code samples into a file called Demo.java):
Join point 'staticinitialization(void TestAspect.<clinit>())' in
Type 'TestAspect' (Demo.java:9) advised by before advice from 'X' (Demo.java:19)
When the static initializer runs there is no this, hence you get null when you retrieve it from thisJoinPoint. You haven't said what you actually want to advise but let me assume it is creation of a new instance of TestAspect. Your pointcut needs to match on execution of the constructor for this annotated type:
// Execution of a constructor on a type annotated by #Restful
#Pointcut("execution((#Restful *).new(..))")
public void pointcutMethod() { }
If you wanted to match methods in that type, it would be something like:
#Pointcut("execution(* (#Restful *).*(..))")
We have an annotation #Accepts:
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.FIELD)
public #interface Accepts {
Class[] value();
}
It takes a list of Classes. These are later used to validate in a DSL that a field was passed an instance of the classes listed as acceptable.
Some examples of this annotation in use:
public enum PropertyName {
#Accepts({Integer.class})
xCoordinate,
#Accepts({Integer.class})
yCoordinate,
#Accepts({Boolean.class})
showPermission
#Accepts({String.class, FieldScript.class, List.class})
onClick
/* And So On*/
}
I am adding a new item to this enum called 'value' and it can accept a String or a PropertyResolver. PropertyResolver is an interface defined as below:
public interface PropertyResolver<T> {
public T getValue(TagContext tagContext);
}
I don't know how to do a .class on PropertyResolver to pass on to #Accepts. Is it possible to do so?
Thanks.
You will have to do PropertyResolver.class. There will only one Class instance that represents the the class (raw-version).
No such things as PropertyResolver<T>.class or PropertyResolver<Integer>.class exist.
Always, keep in mind that in Java, generics is compile time only feature.
I want to create a custom annotation (using Java) which would accept other annotations as parameter, something like:
public #interface ExclusiveOr {
Annotation[] value();
}
But this causes compiler error "invalid type for annotation member".
Object[] also doesn't work.
Is there a way to do what I want?
The error is produced because you can't use interfaces as annotation values (change it to Comparable and you'll get the same error). From the JLS:
It is a compile-time error if the return type of a method declared in an annotation type is any type other than one of the following: one of the primitive types, String, Class and any invocation of Class, an enum type, an annotation type, or an array of one of the preceding types. It is also a compile-time error if any method declared in an annotation type has a signature that is override-equivalent to that of any public or protected method declared in class Object or in the interface annotation.Annotation.
I'm afraid I don't know of a good workaround, but now at least you know why you get the error.
Depending on the reason why you would want to specify other annotations there are multiple solutions:
An array of instances of a single annotation type
Probably not what you meant in your question, but if you want to specify multiple instances of a single annotation type it's certainly possible:
public #interface Test {
SomeAnnotation[] value();
}
An array of annotation types instead of instances
If you do not need to specify any parameters on the individual annotations you can just user their class objects instead of instances.
public #interface Test {
Class<? extends Annotation>[] value();
}
But an enum would of course also do the trick in most situations.
Use multiple arrays
If the set of possible annotation types you want to use is limited, you can create a separate parameter for each one.
public #interface Test {
SomeAnnotation[] somes() default { };
ThisAnnotation[] thiss() default { };
ThatAnnotation[] thats() default { };
}
Giving a default value to each member makes it possible to only specify arrays for the types you need.
You can do:
Class<? extends Annotation>[] value();
Not sure if that helps, but . . .
I myself hereby propose a workaround for the given problem:
Well, what I wanted to make possible was something like that:
#Contract({
#ExclusiveOr({
#IsType(IAtomicType.class),
#Or({
#IsType(IListType.class),
#IsType(ISetType.class)
})
})
})
Proposed workaround:
Define a class with parameter-less constructor (which will be called by your own annotation processor later) in following way:
final class MyContract extends Contract{
// parameter-less ctor will be handeled by annotation processor
public MyContract(){
super(
new ExclusiveOr(
new IsType(IAtomicType.class),
new Or(
new IsType(IListType.class),
new IsType(ISetType.class)
)
)
);
}
}
usage:
#Contract(MyContract.class)
class MyClass{
// ...
}
I just ran into this exact problem, but (inspired by #ivan_ivanovich_ivanoff) I have discovered a way to specify a bundle of any combination of Annotations as an annotation member: use a prototype / template class.
In this example I define a WhereOr (i.e. a "where clause" for my model annotation) which I need to contain arbitrary Spring meta-annotations (like #Qualifier meta-annotations).
The minor (?) defect in this is the forced dereferencing that separates the implementation of the where clause with the concrete type that it describes.
#Target({})
#Retention(RetentionPolicy.RUNTIME)
public #interface WhereOr {
Class<?>[] value() default {};
}
#Target({ElementType.TYPE, ElementType.ANNOTATION_TYPE})
#Retention(RetentionPolicy.RUNTIME)
public #interface JsonModel {
Class<?> value();
WhereOr where() default #WhereOr;
}
public class Prototypes {
#Qualifier("myContext")
#PreAuthorize("hasRole('ROLE_ADMINISTRATOR')")
public static class ExampleAnd {
}
}
#JsonModel(
value = MusicLibrary.class,
where = #WhereOr(Prototypes.ExampleAnd.class)
)
public interface JsonMusicLibrary {
#JsonIgnore
int getMajorVersion();
// ...
}
I will programmatically extract the possible valid configurations from the "where clause" annotation. In this case I also use the prototypes class as a logical AND grouping and the array of classes as the logical OR.