[JAVA] Synthesize Spring annotations to create project-specific stereotypes

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.

Basic

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.

Roll back transaction when check exception occurs

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

Throw an exception if DAO or Repository is called outside the transaction

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

Make Controller a transaction boundary

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

Recommended Posts

Synthesize Spring annotations to create project-specific stereotypes
How to create a Spring Boot project in IntelliJ
[Spring Boot] How to create a project (for beginners)
How to create docker-compose
Create API to send and receive Json data in Spring