Customers are regularly asking me if there is some overview over the most important Spring annotations. Until now I always refused to create such an overview, too simplified it would be, I thought.
Finally, I did it and I thought, maybe it be might be useful for beginners using Spring framework and related APIs.
Hope it helps anybody. If, please share using the buttons on the top.
Implicit bean definition using stereotype annotations
@Component
public class MyComponent {
// Spring Bean with arbitrary role in application
}
@Service
public class MyService {
// Spring bean that acts as a service
// i.e. implements business logic
}
@RestController
@RequestMapping(„/api/myrestcontroller“)
public class MyRestController {
//spring bean that acts as a rest controller with base url „/api/myrestcontroller„
}
@Repository
public class MyRepository {
// Spring bean which acts as a repository
// all database (jdbc, jpa, …) exceptions are mapped to subclasses of DataAccessException
}
Spring configuration classes
@Configuration // denotes the class as a configuration class
// Configuration classes are called only by the spring container
// never by the programmers code
public class MyConfig {
//configuration classes define 1 to n Spring Beans
@Bean(„albert“) // Name of the bean
public String nameOfGenius(){
return „Albert Einstein“;
}
@Bean //name defaults to method name
public LocalDate birthDateOfGenius(){
return LocalDate.of(1879, 3 , 14);
}
@Bean // Parameter injection example
public HumanBeing albertEinstein(@Value(„#{albert}“)String name,
@Value(„#{birthDateOfGenius}“)LocalDate birthDate){
return new HumanBeing(name, birthDate);
}
}
Annotations for dependency injection
public class InjectionsUsingAutowired {
@Autowired // field dependency injection by type
private StudentRepo studentRepo;
private MyService myService;
private TrainingRepo trainingRepo;
@Autowired // constructor dependency injection by type
public InjectionsUsingAutowired(MyService myService) {
this.myService = myService;
}
@Autowired // setter dependency Injection by type
public void setTrainingRepo(TrainingRepo trainingRepo) {
this.trainingRepo = trainingRepo;
}
}
public class InjectionsUsingValue {
@Value(„#{studentRepo}“) // field dependency injection by bean name
private StudentRepo studentRepo;
private MyService myService;
private TrainingRepo trainingRepo;
@Autowired // constructor dependency injection by bean name
public InjectionsUsingValue(@Value(„#{myServiceImpl1}“) MyService myService) {
this.myService = myService;
}
@Autowired // setter dependency Injection by bean name
public void setTrainingRepo(@Value(„#{trainingRepo}“) TrainingRepo trainingRepo) {
this.trainingRepo = trainingRepo;
}
}
RestController annotations
@RestController
@RequestMapping(„/api/customers„)
public class CustomerRestController {
@Autowired
private CustomerRepo customerRepo;
//GET http://localhost:8080/api/customers
@GetMapping
public List<Customer> findAllCustomers(){
return customerRepo.findAll();
}
// GET http://localhost:8080/api/customers/search?name=Michael
@GetMapping(„search„)
public List<Customer> findCustomerByName(@RequestParam(„name„)String name){
return customerRepo.findByName(name);
}
//GET http://localhost:8080/api/customers/12
@GetMapping(„{id}„)
public ResponseEntity<Customer> findById(@PathVariable(„id„) Long id){
return ResponseEntity.of(customerRepo.findById(id));
}
//DELETE http://localhost:8080/api/customers/12
@DeleteMapping(„{id}„)
@PreAuthorize(„hasAnyRole(‚ADMIN‘)“)
public boolean deleteById(@PathVariable(„id„)Long id){
return customerRepo.delete(id);
}
}
/*
POST localhost:8080/api/customers
Content-Type: application/json
{
„name“: „Katarina“,
„email“: „katarina@javatraining.at“
}
*/
@PostMapping
public Customer save(@RequestBody Customer customer){
return customerRepo.save(customer);
}
}
@RestController
@RequestMapping(„/api/customers“)
public class CustomerController {
@Autowired
private CustomerRepo customerRepo;
@GetMapping(„{id}“)
public ResponseEntity findById(@PathVariable(„id“) Long id){
Optional<Customer> customerOpt = customerRepo.findById(id);
if (customerOpt.isPresent()){
return ResponseEntity.ok().body(customerOpt.get());
} else {
Error error = new Error(„Could not find customer“, „id=“ + id);
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(error);
}
}
}
REST Exception Handlers
@ControllerAdvice
public class MyExceptionHandler extends ResponseEntityExceptionHandler {
@ExceptionHandler({DataAccessException.class})
public ResponseEntity<Error> handleJpaException(DataAccessException ex, WebRequest request){
//returning your own error object
Error error = new Error(„Database operation not sucessful.“, ex.getMessage());
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(error);
}
@ExceptionHandler(NullPointerException.class)
public ResponseEntity<Object> handleNullpointerException(NullPointerException ex, WebRequest request){
//convenience method inherited from ResponseEntityExceptionHandler
return handleExceptionInternal(ex,
„Sorry, something went wrong.“,
new HttpHeaders(),HttpStatus.INTERNAL_SERVER_ERROR,
request);
}
}
Scope Annotations
@Component
@Scope(„singleton“)
/**
* Singleton Scope is the default scope for Spring beans.
* There is only one instance of this bean. It is created when application starts and lives until application terminates
*/
public class ScopedBean {
//…
}
@Component
@Scope(„prototype“)
/**
* everytime this bean is injected somewhere else
* a new instance will be created.
* It will live as long as the bean it is injected into.
*/
public class ScopedBean {
//…
}
@Component
@RequestScope
// alternatively @Scope(„request“)
/**
* for each user-session in the browser
* there will be one instance of this bean
*/
public class ScopedBean {
//…
}
@Component
@SessionScope
// alternatively @Scope(„session“)
/**
* for each user-session in the browser
* there will be one instance of this bean
*/
public class ScopedBean {
//…
}
JPA & Lombok Annotations
@Data // tell lombok to generate getters, setters, equals, hashCode, toString
@NoArgsConstructor //tell lombok to generate a noargs constructor
@RequiredArgsConstructor //tell lombok to generate a constructor for all NonNull fields
@Entity // required on every entity
@Table(name=„students“) // tell JPA to which table this entity should be stored
public class Student {
@Id // tell JPA that
// this is the primary key of the entity
@GeneratedValue(strategy = GenerationType.IDENTITY) // tell JPA that DB generates this value
@Column(name=„id“) // tell JPA in which column this field should be stored
private Long id;
@NonNull // tell lombok that this field will not be null / may not be null
@Column(name=„name“)
private String name;
@NonNull
@Column(name=„email“)
private String email;
}
@Data
@NoArgsConstructor
@RequiredArgsConstructor
@Entity
@Table(name=„trainings“)
public class Training {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name=„id“)
private Long id;
…
@EqualsAndHashCode.Exclude // tell lombok that this field should not be used for equals and hashCode
@ManyToOne(cascade = {CascadeType.MERGE, CascadeType.PERSIST}) // tell JPA about a foreign key (1:n) relationship to entity trainer
@JoinColumn(name=„id_trainer“) // name of the column in which the foreign key should be stored
private Trainer trainer;
@EqualsAndHashCode.Exclude
@ManyToMany(cascade = {CascadeType.MERGE, CascadeType.PERSIST}) // tell JPA about a foreign key (n:m) relationship to entity Student
@JoinTable(name = „trainings_to_students„, // tell JPA in which mapping table the foreign key relationship is mapped
joinColumns = @JoinColumn(name=„id_training“), // what is the column that relates to my own key
inverseJoinColumns = @JoinColumn(name=„id_student“)) // what is the column that relates to the key of entity student
private List students = new ArrayList<>();
}
Spring Data Annotations
// definition of a Spring Data JPA repository
public interface TrainingRepo extends JpaRepository, TrainingRepoCustom {
@Query(„select t from Training t left join fetch t.trainer„) // defining a query using the @Query annotation
public List findAllUsingFetchJoinTrainer();
@EntityGraph(attributePaths = {„trainer“,„students„}) // declaring an entityGraph that should be used along with this query
@Query(„select t from Training t“)
public List findAllUsingEntityGraph();
public List findTrainingByTitleLike(String title); // define a query using method name syntax
@Query(„select t from Training t where t.trainer.name = :trainername„) // using parameters in queries
public List findTrainingByTrainerName(@Param(„trainername“) String trainername);
// directly query into a Data Transfer Object
@Query(„select new at.javatraining.jpa.entities.dtos.TrainingSummaryDto(t.id, t.title, t.begin, t.students.size) from Training t“)
public List<TrainingSummaryDto> getTrainingSummaries();
}
public interface TrainingTitleSummaryView {
public Long getId();
public String getTitle();
@Value(„#{target.students.size()}“)
public int getNumberOfStudents();
}
// definition of a Spring Data JPA repository
public interface TrainingRepo extends JpaRepositoryLong>, TrainingRepoCustom {
…
// query into a Spring projection
@Query(„select t from Training t“)
public List<TrainingTitleSummaryView> getTrainingTitleSummaryView();
}
AOP Annotations
@Aspect // define an aspect
@Component // make it a spring component
@Slf4j // generate variable with SLF4J Logger
public class LoggingAspect {
@Around(„execution(* at.javatraining.trainings.service.*.*(..))“) // define where the aspect should be called
public Object log(ProceedingJoinPoint pjp) throws Throwable{
String methodName = pjp.getSignature().getName();
String params = Arrays.toString(pjp.getArgs());
log.info(„Method call: {} params: {}“, methodName, params);
Object result = pjp.proceed();
log.info(„Returning call: {} params: {}“, methodName, params);
return result;
}
}