Want to create annotation which will contain multiple annotations but want to make it more configurable so that it can be more feasible to use in all scenarios
#SpringBootApplication
#ServletComponentScan(basepackages="com.example.commons.traceability")
#ComponentScan(basePackages={
"com.example.commons.security",
"com.example.commons.restTemplate",
"com.example.commons.logging",
})
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.TYPE)
public #interface Microservice{
String[] scanBasePackages() default {};
}
I want to use this application in Spring Application file but also want to make the componentScan more configurable so that apart from the default packages other package can also me included in the component scan
#Microservice(scanBasePackages={"com.example.myproject"})
public class MySpringApplciation{
public static void main (final String[] args){
// some code
}
}
so as in the above code if I pass value of scanBasePackages so those packages should also be included in the component scan.
Is there any way to include values of scanBasePackages inside componentScan in custom annotation ?
Annotations on (custom) annotations are called meta-annotations.
In short: you're lucky. While Java does not allow this out of the box, Spring has a special annotation for this sort of thing: #AliasFor.
I had a similar question, and I found the answer here.
And here is a good source.
Specifically in your case, try this:
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.core.annotation.AliasFor;
#SpringBootApplication
#ServletComponentScan(basePackages="com.example.commons.traceability")
#ComponentScan(basePackages={
"com.example.commons.security",
"com.example.commons.restTemplate",
"com.example.commons.logging",
})
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.TYPE)
public #interface Microservice{
// >>> TRY THIS <<<
#AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
String[] scanBasePackages() default {};
}
(I myself am less lucky, since I need this sort of thing for reducing my JUnit5 boilerplate annotations, and #AliasFor is only meaningful in Spring.)
Related
According to JSR 308 (Java Type Annotations) it is possible to annotate any type using ElementType.TYPE_USE:
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.*;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
#Target({ TYPE_USE })
#Retention(RUNTIME)
public #interface MyAnnotation {
String value();
}
How to get the annotated value from a function at runtime?
import java.util.function.Consumer;
import org.junit.Assert;
import org.junit.Test;
public class TestFunctionAnnotation {
#Test
public void test() {
Consumer<TestFunctionAnnotation> fun = #MyAnnotation("NoJoke") TestFunctionAnnotation::test;
Assert.assertEquals("NoJoke", fun.getClass().getAnnotatedSuperclass().getAnnotation(MyAnnotation.class));
// expected:<NoJoke> but was:<null>
}
}
Your #MyAnnotation doesn't appear on the class, or the method, but on the use of the type - something that you can't reflect on. Instead, you'd need a hypothetical "reflection" which could examine the code itself, not just the structure of the types.
Instead, you want to either build a compiler plugin which can read that, or add a task listener inside an annotation processor - see https://stackoverflow.com/a/55288602/860630 for some discussion on this. Once you've done that and can read the annotation, you can generate new code which you could then access at runtime, and do whatever it is you are after here.
I want to implement a custom validator in a Spring Boot v1.5.14.RELEASE app. First I create a custom constraint annotation:
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
#Retention(RetentionPolicy.RUNTIME)
public interface CreateBook {
}
However, I receive this compilation error:
#Retention not applicable to type
The problem is with how you define a new annotation. It should be like this:
#Retention(RetentionPolicy.RUNTIME)
public #interface CreateBook {
}
Note the # character in #interface
I'm working on my first project with Spring and Hibernate and I would like to create a validator for an IP address.
To create the project I use IntelliJ. When I enter the code like this I get an error on the #Target annotation Attribute value must be a class literal
I do understand what this annotation has to do, but if I keep getting this error, it won't work.
I have looked at the documentation about custom constraints here http://docs.jboss.org/hibernate/validator/5.0/reference/en-US/html_single/#validator-customconstraints-simple and I have looked at several Stackoverflow pages, but I can't get this error solved.
import org.hibernate.annotations.Target;
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import static java.lang.annotation.ElementType.FIELD;
/**
* Created by johan on 17-5-17.
*/
#Target({ FIELD })
#Retention(RetentionPolicy.RUNTIME)
#Documented
#Constraint(validatedBy = IpAddressValidator.class)
public #interface IpAddress{
String message() default "{ipAddress.invalid}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
What do I need to do to get this working?
You used the wrong #Target. You meant to use java.lang.annotation.Target but imported org.hibernate.annotations.Target. Change the first import to import java.lang.annotation.Target and it should work fine.
Some projects using of custom annotations as below. For example as below. Please explain me
when should I take decision to have custom annotations.
Role of #Target & #Retention annotation attributes
is it better to use import java.lang.annotation.Target and import java.lang.annotation.Retention or hibernate specific annotations as below
#Entity
#Table(name = "creditCard")
#CreditCardEntity
public class CreditCard implements java.io.Serializable {}
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.hibernate.validator.ValidatorClass;
#Target( { ElementType.TYPE })
#Retention(RetentionPolicy.RUNTIME)
public #interface CreditCardEntity {}
}
If you plan to use the same annotations together on more than one place in your code, it's a good idea to use custom annotations. For example, in your case, if you will use #Entity #Table(name = "creditCard") together in another place, it's a good idea to unite them under one annotation like the CreditCardEntity annotation, but if that's the only place you will use those two annotations together (which is more likely in this case), it's unnecessary to make a custom annotation for it.
If a class is annotated with an annotation, does the definition of that annotation have to be in the runtime classpath in order to use the class? For example, given the annotation
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Retention;
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
public #interface Component {}
can I execute the program
#Component
public class Test {
public static void main(String[] args) {
System.out.println("It worked!");
}
}
without having Component.class in the classpath? (In my test I could, but is this behavior defined by the spec?)
I ask because there are conflicting claims whether using an annotation from a library creates a dependency on that library.
Runtime annotations are meta information to be processed by annotation processor at the runtime. If there is an access to annotation at runtime, you definitely add annotations in the classpath. For example junit definitely need the annotations in the class path determine test methods.
If there is no processing of annotation is done, there is no need to have it the classpath.
Yes you can execute program without having Component.class in the classpath. More details here: Why doesn't a missing annotation cause a ClassNotFoundException at runtime?