Normally, you can't inherit or synthesize annotations in Java, but you can annotate Spring. You don't need to make complicated preparations, just write annotations.
Define an annotation and add the annotation you want to synthesize to that type. As for the parameter of the original annotation, if it is a constant, you can specify it as usual, or you can use @AliasFor
to pass the parameter of the new annotation to the synthesized annotation.
@Retention(RetentionPolicy.RUNTIME) //Make annotations visible at runtime
@Validated
@ModelAttribute(binding = true)
public @interface ValidModel {
@AliasFor(annotation = ModelAttribute.class, attribute = "name")
String value() default "";
}
Synthetic annotations are used everywhere, such as @ SpringBootApplication
and @GetMapping
, so if you follow the source, you can figure out how to use it.
By default, @Transactional
has a terrifying behavior of committing even if a checked exception is thrown, but by defining your own annotation, you don't have to add rollbackFor
every time.
@Retention(RetentionPolicy.RUNTIME)
@Transactional(rollbackFor = Exception.class)
public @interface OurTransactional {
@AliasFor(annotation = Transactional.class, attribute = "readOnly")
boolean readOnly() default false;
}
I don't think DAO will be a transaction boundary, but you can also check if it is inside a transaction with annotations as shown below.
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Component
@Transactional(propagation = Propagation.MANDATORY)
public @interface OurDao {
@AliasFor(annotation = Transactional.class, attribute = "readOnly")
boolean readOnly() default false;
}
Annotation that cuts a transaction with Controller like Play 1 system is like this.
@Retention(RetentionPolicy.RUNTIME)
@Controller
@RequestMapping
@Transactional
public @interface OurController {
@AliasFor(annotation = RequestMapping.class, attribute = "path")
String value() default "";
@AliasFor(annotation = Transactional.class, attribute = "readOnly")
boolean readOnly() default false;
}