Spring Boot 120 Annotations
Spring Boot 120 Annotations
// Constructor injection
@Autowired
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
• Explanation: Here, @Autowired injects the UserRepository bean. Constructor injection is generally
preferred over field injection as it makes the class easier to test.
@Qualifier
• Purpose: Used when there are multiple beans of the same type and you want to specify which one
should be injected.
• Example:
@Component
public class NotificationService {
@Autowired
@Qualifier("emailService")
private MessageService messageService;
@Component("emailService")
public class EmailService implements MessageService {
@Override
public void sendMessage(String message) {
// Logic to send an email
}
}
@Component("smsService")
public class SmsService implements MessageService {
@Override
public void sendMessage(String message) {
// Logic to send an SMS
}
}
@Component
public class AlternativeNotificationService implements MessageService {
@Override
public void sendMessage(String message) {
// Alternative notification logic
}
}
@Inject
private UserRepository userRepository;
• Explanation: Functionally similar to @Autowired, but @Inject is part of the standard Java framework
rather than being specific to Spring.
2. Configuration Annotations
@Configuration
• Purpose: Indicates that the class can be used by the Spring IoC container as a source of bean
definitions.
• Example:
@Configuration
public class AppConfig {
@Bean
public UserService userService() {
return new UserService(userRepository());
}
@Bean
public UserRepository userRepository() {
return new UserRepository();
}
}
• Explanation: The AppConfig class defines beans using @Bean methods, which Spring manages.
@Bean
• Purpose: Marks a method as a Spring bean producer.
• Example:
@Configuration
public class AppConfig {
@Bean
public UserService userService() {
return new UserService();
}
}
• Explanation: The method annotated with @Bean returns an object that is registered as a bean in the
Spring context.
@Import
• Purpose: Allows importing additional @Configuration classes.
• Example:
@Configuration
@Import(DatabaseConfig.class)
public class AppConfig {
// Additional beans and configuration
}
• Explanation: Here, DatabaseConfig.class is imported, allowing its bean definitions to be included in the
Spring context.
@PropertySource
• Purpose: Used to specify a properties file to load.
• Example:
@Configuration
@PropertySource("classpath:application.properties")
public class AppConfig {
@Value("${app.name}")
private String appName;
@Bean
public String getAppName() {
return appName;
}
}
• Explanation: The properties file is loaded, and its values can be injected using @Value.
@Order
• Purpose: Defines the order in which components should be processed.
• Example:
@Component
@Order(1)
public class FirstComponent {
// Component logic
}
@Component
@Order(2)
public class SecondComponent {
// Component logic
}
• Explanation: The components are processed in the order specified by the @Order annotation.
3. Component Scanning Annotations
@ComponentScan
• Purpose: Specifies the base packages to scan for Spring components.
• Example:
@Configuration
@ComponentScan(basePackages = "com.example.services")
public class AppConfig {
// Additional configuration
}
• Explanation: This tells Spring to scan the specified packages for components like @Component,
@Service, @Repository, and @Controller.
@Component
• Purpose: Generic stereotype for any Spring-managed component.
• Example:
@Component
public class EmailService {
// Email sending logic
}
• Explanation: The class is registered as a Spring bean and can be injected into other components.
@Service
• Purpose: Specialization of @Component for service classes.
• Example:
@Service
public class UserService {
// Business logic
}
• Explanation: Indicates that the class is responsible for interacting with the database.
@Controller
• Purpose: Specialization of @Component for web controllers.
• Example:
@Controller
public class UserController {
@GetMapping("/users")
public String getUsers(Model model) {
model.addAttribute("users", userService.getAllUsers());
return "users";
}
}
@PostConstruct
public void init() {
// Initialization logic
}
}
• Explanation: The init method is called after the bean is fully initialized by Spring.
@PreDestroy
• Purpose: Indicates a method that should be run just before the bean is destroyed.
• Example:
@Component
public class MyBean {
@PreDestroy
public void cleanup() {
// Cleanup logic
}
}
• Explanation: The cleanup method is called before the bean is removed from the Spring context.
5. Aspect-Oriented Programming (AOP) Annotations
@Aspect
• Purpose: Indicates that the class contains AOP-related advice (code that runs before, after, or around
method executions).
• Example:
@Aspect
@Component
public class LoggingAspect {
@Before("execution(* com.example.service.*.*(..))")
public void logBefore(JoinPoint joinPoint) {
System.out.println("Before method: " + joinPoint.getSignature().getName());
}
}
• Explanation: The class is an aspect containing advice that runs before the execution of methods in the
specified package.
@Pointcut
• Purpose: Defines reusable expressions for where advice should be applied.
• Example:
@Aspect
@Component
public class LoggingAspect {
@Pointcut("execution(* com.example.service.*.*(..))")
public void serviceLayer() {
// Pointcut expression
}
@Before("serviceLayer()")
public void logBefore(JoinPoint joinPoint) {
System.out.println("Before method: " + joinPoint.getSignature().getName());
}
}
• Explanation: The serviceLayer() method is a reusable pointcut that can be used in multiple advice
methods.
@Before
• Purpose: Advice that runs before the method execution.
• Example:
@Before("execution(* com.example.service.*.*(..))")
public void logBefore(JoinPoint joinPoint) {
System.out.println("Before method: " + joinPoint.getSignature().getName());
}
• Explanation: This
advice is executed before any method in the specified package runs.
@After
• Purpose: Advice that runs after the method execution, regardless of its outcome.
• Example:
@After("execution(* com.example.service.*.*(..))")
public void logAfter(JoinPoint joinPoint) {
System.out.println("After method: " + joinPoint.getSignature().getName());
}
• Explanation: This advice runs after the target method finishes execution.
@Around
• Purpose: Advice that surrounds the method execution, allowing you to control whether the method
executes.
• Example:
@Around("execution(* com.example.service.*.*(..))")
public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("Before method: " + joinPoint.getSignature().getName());
Object result = joinPoint.proceed();
System.out.println("After method: " + joinPoint.getSignature().getName());
return result;
}
• Explanation: @Around advice can modify the flow by deciding whether or not to call joinPoint.proceed()
6. REST Controllers
@RestController
• Purpose: A specialization of @Controller that automatically adds @ResponseBody to all methods,
making it easier to create RESTful web services.
• Example:
@RestController
@RequestMapping("/api/users")
public class UserController {
@GetMapping
public List<User> getAllUsers() {
// Logic to fetch all users
return userService.getAllUsers();
}
}
• Explanation: @RestController makes it easy to create RESTful APIs by ensuring that the response is
automatically serialized to JSON or XML.
@RequestMapping
• Purpose: Used to map HTTP requests to handler methods of MVC and REST controllers. It can be
applied at both the class and method levels.
• Example:
@RestController
@RequestMapping("/api/users")
public class UserController {
• Explanation: @RequestMapping is versatile and can handle multiple HTTP methods (GET, POST, etc.).
It’s more generic than the specialized annotations like @GetMapping.
@GetMapping
• Purpose: A shortcut for @RequestMapping specifically for GET requests.
• Example:
@GetMapping("/{id}")
public User getUserById(@PathVariable Long id) {
// Logic to fetch a user by ID
return userService.getUserById(id);
}
• Explanation: @PostMapping is used for creating resources, typically handling form submissions or
JSON input.
@PutMapping
• Purpose: A shortcut for @RequestMapping specifically for PUT requests.
• Example:
@PutMapping("/{id}")
public User updateUser(@PathVariable Long id, @RequestBody User user) {
// Logic to update an existing user
return userService.updateUser(id, user);
}
• Explanation: @PutMapping is used to update an existing resource, replacing its current state with the
new state provided.
@DeleteMapping
• Purpose: A shortcut for @RequestMapping specifically for DELETE requests.
• Example:
@DeleteMapping("/{id}")
public void deleteUser(@PathVariable Long id) {
// Logic to delete a user by ID
userService.deleteUser(id);
}
• Explanation: @PatchMapping is used when you need to update a subset of a resource’s fields, rather
than the entire object.
@RequestBody
• Purpose: Used to bind the body of a POST/PUT request to a Java object.
• Example:
@PostMapping
public User createUser(@RequestBody User user) {
// Logic to create a new user
return userService.createUser(user);
}
• Explanation: @RequestBody automatically deserializes the incoming JSON payload into a Java object.
@ResponseBody
• Purpose: Used to indicate that the return value of a method should be serialized directly to the HTTP
response body.
• Example:
@GetMapping("/{id}")
@ResponseBody
public User getUserById(@PathVariable Long id) {
// Logic to fetch a user by ID
return userService.getUserById(id);
}
• Explanation: @ResponseBody is automatically included when using @RestController, but you can use
it in @Controller classes when needed.
@PathVariable
• Purpose: Used to extract values from the URI and bind them to method parameters.
• Example:
@GetMapping("/{id}")
public User getUserById(@PathVariable Long id) {
// Logic to fetch a user by ID
return userService.getUserById(id);
}
• Explanation: The {id} part of the URI is captured and passed to the method as a parameter.
@RequestParam
• Purpose: Used to extract query parameters from the URL and bind them to method parameters.
• Example:
@GetMapping
public List<User> getUsers(@RequestParam(defaultValue = "0") int page, @RequestParam(defaultValue
= "10") int size) {
// Logic to fetch paginated users
return userService.getUsers(page, size);
}
• Explanation: @RequestParam is used for query parameters like ?page=0&size=10. You can also set
default values.
7. Exception Handling Annotations
@ExceptionHandler
• Purpose: Used to define methods that handle specific exceptions.
• Example:
@RestController
@RequestMapping("/api/users")
public class UserController {
@GetMapping("/{id}")
public User getUserById(@PathVariable Long id) {
return userService.getUserById(id);
}
@ExceptionHandler(UserNotFoundException.class)
@ResponseStatus(HttpStatus.NOT_FOUND)
public String handleUserNotFoundException(UserNotFoundException ex) {
return ex.getMessage();
}
}
@ExceptionHandler(UserNotFoundException.class)
@ResponseStatus(HttpStatus.NOT_FOUND)
public String handleUserNotFoundException(UserNotFoundException ex) {
return ex.getMessage();
}
@ExceptionHandler(Exception.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public String handleGeneralException(Exception ex) {
return "An error occurred: " + ex.getMessage();
}
}
• Explanation: @ControllerAdvice allows you to define a global exception handler that applies to all
controllers.
8. Data Binding Annotations
@ModelAttribute
• Purpose: Used to bind request parameters to a model object and add it to the model, often used in form
submissions.
• Example:
@Controller
@RequestMapping("/users")
public class UserController {
@GetMapping("/register")
public String showRegistrationForm(Model model) {
model.addAttribute("user", new User());
return "register";
}
@PostMapping("/register")
public String registerUser(@ModelAttribute User user) {
userService.saveUser(user);
return "redirect:/users";
}
}
• Explanation: @ModelAttribute binds form data to the User object. It’s also used to populate the model
with a default object before the view is rendered.
@InitBinder
• Purpose: Used to customize the data binding process, such as formatting dates or validating input.
• Example:
@Controller
@RequestMapping("/users")
public class UserController {
@InitBinder
public void initBinder(WebDataBinder binder) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false));
}
@PostMapping("/register")
public String registerUser(@ModelAttribute User user) {
userService.saveUser(user);
return "redirect:/users";
}
}
• Explanation: @InitBinder allows you to configure data binding, like converting strings to date objects in
the above example.
9. Entity Mapping Annotations
@Entity
• Purpose: Indicates that a class is a JPA entity, meaning it maps to a database table.
• Example:
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
• Explanation: The @Entity annotation marks this class as an entity, which Spring Data JPA will manage
and persist in the database.
@Table
• Purpose: Specifies the name of the database table that the entity maps to.
• Example:
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
• Explanation: The @Table(name = "users") annotation explicitly specifies that the User entity maps to
the "users" table in the database.
@Column
• Purpose: Defines the mapping for a specific database column.
• Example:
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(unique = true)
private String email;
// getters and setters
}
• Explanation: @Column lets you specify details like the column name, whether it’s nullable, or whether
it’s unique.
@Id
• Purpose: Specifies the primary key of the entity.
• Example:
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
// Other fields
}
• Explanation: @Id marks the field as the primary key, which uniquely identifies each entity instance in
the table.
@GeneratedValue
• Purpose: Specifies how the primary key should be generated (e.g., auto-increment).
• Example:
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
// Other fields
}
@EmbeddedId
private OrderId id;
@Embeddable
public class OrderId implements Serializable {
private Long customerId;
private Long orderId;
// getters and setters
}
• Explanation: @EmbeddedId allows you to define a composite key using another class (like OrderId in
this example).
@OneToOne
• Purpose: Defines a one-to-one relationship between two entities.
• Example:
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "profile_id")
private Profile profile;
// Other fields
}
• Explanation: @OneToOne is used when one entity is associated with exactly one instance of another
entity (e.g., a User has one Profile).
@OneToMany
• Purpose: Defines a one-to-many relationship between two entities.
• Example:
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
• Explanation: @OneToMany is used when one entity is associated with multiple instances of another
entity (e.g., a User has many Orders).
@ManyToOne
• Purpose: Defines a many-to-one relationship between two entities.
• Example:
@Entity
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne
@JoinColumn(name = "user_id")
private User user;
// Other fields
}
• Explanation: @ManyToOne is used when multiple instances of one entity are associated with a single
instance of another entity (e.g., many Orders belong to one User).
@ManyToMany
• Purpose: Defines a many-to-many relationship between two entities.
• Example:
@Entity
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToMany
@JoinTable(
name = "student_course",
joinColumns = @JoinColumn(name = "student_id"),
inverseJoinColumns = @JoinColumn(name = "course_id")
)
private List<Course> courses;
// Other fields
}
• Explanation: @ManyToMany is used when multiple instances of one entity are associated with multiple
instances of another entity (e.g., many Students enrolled in many Courses).
@JoinColumn
• Purpose: Specifies the foreign key column in a relationship.
• Example:
@Entity
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne
@JoinColumn(name = "user_id")
private User user;
// Other fields
}
• Explanation: @JoinColumn(name = "user_id") specifies the column that will hold the foreign key linking
the Order to the User.
@JoinTable
• Purpose: Specifies the join table used in many-to-many relationships.
• Example:
@Entity
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToMany
@JoinTable(
name = "student_course",
joinColumns = @JoinColumn(name = "student_id"),
inverseJoinColumns = @JoinColumn(name = "course_id")
)
private List<Course> courses;
// Other fields
}
• Explanation: @JoinTable is used to create the intermediate join table in a many-to-many relationship.
@Transient
• Purpose: Indicates that a field should not be persisted in the database.
• Example:
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Transient
private int age; // This field will not be saved in the database
}
• Explanation: @Transient is used when you have fields that are calculated or only used temporarily and
shouldn’t be persisted in the database.
10. Repositories
@Repository
• Purpose: Indicates that a class is a Spring Data repository, which encapsulates the logic to interact with
the database.
• Example:
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
// Custom query methods can be added here
}
• Explanation: @Repository is used to define a repository interface that extends JPA repositories like
JpaRepository or CrudRepository.
@Query
• Purpose: Used to define custom JPQL or native SQL queries.
• Example:
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
• Explanation: @Query allows you to write custom queries using JPQL or native SQL. It’s useful when
the default query methods are not sufficient.
11. Authentication Annotations
@EnableWebSecurity
• Purpose: Enables Spring Security’s web security support and provides the configuration needed to
secure a web application.
• Example:
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin()
.permitAll();
}
}
• Explanation: @EnableWebSecurity activates the Spring Security features and allows you to configure
them using the WebSecurityConfigurerAdapter class. This example secures all endpoints and enables a
default login form.
@CrossOrigin
• Purpose: Allows cross-origin requests on the annotated controller or method, enabling communication
between different domains.
• Example:
@RestController
@RequestMapping("/api")
@CrossOrigin(origins = "<http://example.com>")
public class UserController {
@GetMapping("/users")
public List<User> getAllUsers() {
return userService.getAllUsers();
}
}
@PreAuthorize("hasRole(’ADMIN’)")
@DeleteMapping("/users/{id}")
public void deleteUser(@PathVariable Long id) {
userService.deleteUser(id);
}
}
• Explanation: @PreAuthorize("hasRole(’ADMIN’)") ensures that only users with the "ADMIN" role can
access this method. You can also use complex expressions for more detailed access control.
@PostAuthorize
• Purpose: Performs an authorization check after the method has been executed, typically used for
validating the result.
• Example:
@RestController
@RequestMapping("/api")
public class UserController {
@PostAuthorize("returnObject.username == authentication.name")
@GetMapping("/users/{id}")
public User getUserById(@PathVariable Long id) {
return userService.getUserById(id);
}
}
@Secured("ROLE_ADMIN")
@PostMapping("/users")
public User createUser(@RequestBody User user) {
return userService.createUser(user);
}
}
• Explanation: While you can use @SpringBootConfiguration to define configurations, it’s usually implied
through @SpringBootApplication.
@ConfigurationProperties
• Purpose: Binds external properties (like from application.properties or application.yml) to a configuration
class.
• Example:
@ConfigurationProperties(prefix = "app")
public class AppProperties {
@Resource(name = "userRepository")
private UserRepository userRepository;
}
• Explanation: @Resource(name = "userRepository") injects the bean with the specified name. This is an
alternative to @Autowired, which primarily focuses on type.
14. Testing Annotations
@SpringBootTest
• Purpose: Used to load the full Spring application context for integration tests.
• Example:
@SpringBootTest
public class UserServiceTests {
@Autowired
private UserService userService;
@Test
public void testCreateUser() {
// Test logic
}
}
• Explanation: @SpringBootTest initializes the Spring context, allowing you to test components like
services and repositories in an integrated environment.
@MockBean
• Purpose: Replaces a bean in the Spring context with a Mockito mock for testing.
• Example:
@SpringBootTest
public class UserServiceTests {
@MockBean
private UserRepository userRepository;
@Autowired
private UserService userService;
@Test
public void testCreateUser() {
// Mocked behavior and test logic
}
}
• Explanation: @MockBean is used to mock dependencies within the Spring context, making it easier to
test components in isolation.
@SpyBean
• Purpose: Spies on a real Spring bean, allowing you to override certain methods while retaining the
original behavior.
• Example:
@SpringBootTest
public class UserServiceTests {
@SpyBean
private UserService userService;
@Test
public void testCreateUser() {
// Spy on real behavior while modifying certain methods
}
}
• Explanation: @SpyBean allows you to test real objects while spying on some methods to control their
behavior during tests.
@TestPropertySource
• Purpose: Specifies additional properties or a different configuration file for testing purposes.
• Example:
@SpringBootTest
@TestPropertySource(locations = "classpath:test-application.properties")
public class UserServiceTests {
@Test
public void testCreateUser() {
// Test logic using properties from test-application.properties
}
}
• Explanation: @TestPropertySource lets you override configuration properties specifically for testing
environments.
15. Validation Annotations
@Valid
• Purpose: Triggers validation on a nested object or collection when applied in a controller or service
layer.
• Example:
@RestController
@RequestMapping("/api/users")
public class UserController {
@PostMapping
public ResponseEntity<String> createUser(@Valid @RequestBody UserDTO user) {
// If validation passes, proceed with saving the user
return ResponseEntity.ok("User created successfully!");
}
}
• Explanation: The @Valid annotation ensures that the UserDTO object is validated according to its field
constraints before proceeding with the method logic. If validation fails, an exception is thrown
automatically.
@NotNull
• Purpose: Ensures that the annotated field is not null.
• Example:
public class UserDTO {
• Explanation: The @NotNull annotation checks that the username field is not null. If it’s null, validation
fails and the specified error message is returned.
@NotEmpty
• Purpose: Ensures that the annotated field is not null or empty (e.g., an empty collection or string).
• Example:
public class UserDTO {
• Explanation: @NotEmpty ensures that email is neither null nor an empty string. It’s typically used for
fields where an empty value is considered invalid.
@NotBlank
• Purpose: Ensures that the annotated string is not null, empty, or consists only of whitespace.
• Example:
public class UserDTO {
• Explanation: @NotBlank ensures that password is not null, empty, or just whitespace, making it more
stringent than @NotEmpty.
@Min and @Max
• Purpose: Specify the minimum and maximum allowable values for a numeric field.
• Example:
public class UserDTO {
• Explanation: @Min ensures that age is at least 18, while @Max ensures it does not exceed 100. Both
annotations are commonly used for numeric constraints.
@Size
• Purpose: Specifies the size constraints for a collection, array, or string.
• Example:
public class UserDTO {
• Explanation: @Size ensures that username has a length between 3 and 20 characters. It’s useful for
defining constraints on string lengths, list sizes, etc.
@Email
• Purpose: Validates that a string is a well-formed email address.
• Example:
public class UserDTO {
• Explanation: @Email checks that the email field is a valid email address format. It’s often combined with
@NotEmpty to ensure both format and presence.
@Pattern
• Purpose: Validates that a string matches a specified regular expression.
• Example:
public class UserDTO {
• Explanation: @Pattern ensures that password matches the given regular expression, enforcing rules
like length and allowed characters.
@AssertTrue and @AssertFalse
• Purpose: Validates that a boolean field is either true or false.
• Example:
public class UserDTO {
• Explanation: @AssertTrue checks that acceptTerms is true, while @AssertFalse ensures that isActive
is false.
@Transactional
public void registerUser(UserDTO userDTO) {
userRepository.save(userDTO.toEntity());
emailService.sendWelcomeEmail(userDTO.getEmail());
}
}
• Explanation: The @Transactional annotation ensures that either all operations within the method
complete successfully, or none of them do (rollback). In this example, if saving the user or sending the
email fails, the entire transaction is rolled back.
@Propagation
• Purpose: Specifies the transaction propagation behavior for methods (e.g., how nested transactions
should behave).
• Example:
@Transactional(propagation = Propagation.REQUIRED)
public void createUser(UserDTO userDTO) {
// Transactional code here
}
• Explanation: The Propagation.REQUIRED strategy means that if a transaction already exists, the
method will join it; otherwise, a new transaction will be created. There are other propagation strategies
like REQUIRES_NEW, SUPPORTS, etc., that determine how transactions should propagate.
@Isolation
• Purpose: Specifies the transaction isolation level (e.g., to prevent issues like dirty reads, phantom
reads).
• Example:
@Transactional(isolation = Isolation.SERIALIZABLE)
public void updateAccountBalance(Long accountId, BigDecimal amount) {
// Transactional code here
}
• Explanation: The Isolation.SERIALIZABLE level is the strictest, ensuring that transactions are fully
isolated from each other. Other levels like READ_COMMITTED and REPEATABLE_READ can also be
used based on your requirements.
@ReadOnly
• Purpose: Marks a transaction as read-only, optimizing performance by avoiding unnecessary write
locks.
• Example:
@Transactional(readOnly = true)
public List<User> getAllUsers() {
return userRepository.findAll();
}
• Explanation: The readOnly = true flag optimizes performance for read operations by reducing overhead,
as no write locks are needed.
@TransactionalEventListener
• Purpose: Listens for transactional events, triggered after a transaction is completed.
• Example:
@Component
public class UserEventListener {
@TransactionalEventListener
public void handleUserCreatedEvent(UserCreatedEvent event) {
// Handle the event after the transaction commits
}
}
• Explanation: @TransactionalEventListener ensures that the event handler only runs after the
transaction is successfully committed. This is useful for triggering post-transaction actions, like sending
notifications.
17. JSON Annotations
@JsonProperty
• Purpose: Specifies the JSON field name to map to a Java property. It can also be used to customize
the behavior of getters and setters.
• Example:
public class User {
@JsonProperty("user_name")
private String username;
@JsonProperty("age")
private int age;
• Explanation: The @JsonProperty("user_name") annotation maps the JSON field user_name to the
usernameproperty in the Java class. This is useful when the JSON field names don’t match your Java
property names.
@JsonIgnore
• Purpose: Excludes a property from being serialized or deserialized.
• Example:
public class User {
@JsonIgnore
private String password;
• Explanation: The @JsonIgnore annotation prevents the password field from being included in the JSON
output. It’s often used for sensitive data that shouldn’t be exposed in API responses.
@JsonInclude
• Purpose: Controls when a property is included in the JSON output. It’s commonly used to skip null or
empty values.
• Example:
public class User {
@JsonInclude(JsonInclude.Include.NON_NULL)
private String email;
• Explanation: The @JsonFormat annotation ensures that the eventDate field is serialized and
deserialized in the dd-MM-yyyy format. This is particularly useful for handling date and time formats in
JSON.
@JsonIgnoreProperties
• Purpose: Ignores specified properties during serialization and deserialization for all instances of a class.
• Example:
@JsonIgnoreProperties({"password", "ssn"})
public class User {
@JsonAlias({"name", "user_name"})
private String username;
• Explanation: The @JsonAlias({"name", "user_name"}) annotation ensures that the username property
can be mapped from JSON fields named name or user_name. It’s useful when your application needs to
handle different JSON formats.
@JsonTypeInfo and @JsonSubTypes
• Purpose: Used together to handle polymorphic deserialization when you have a parent class and
multiple subclasses.
• Example:
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type")
@JsonSubTypes({
@JsonSubTypes.Type(value = Dog.class, name = "dog"),
@JsonSubTypes.Type(value = Cat.class, name = "cat")
})
public abstract class Animal {
private String name;
// Common fields
}
• Explanation: @JsonTypeInfo and @JsonSubTypes together enable deserialization based on the type
property in the JSON. Depending on the value (dog or cat), the appropriate subclass is instantiated. This
is essential for handling inheritance in JSON structures.
@JsonCreator
• Purpose: Used to define a constructor or factory method for deserialization.
• Example:
public class User {
@JsonCreator
public User(@JsonProperty("username") String username, @JsonProperty("age") int age) {
this.username = username;
this.age = age;
}
• Explanation: The @JsonCreator annotation tells Jackson which constructor to use during
deserialization. In this example, the constructor is used to map the username and age fields from the
JSON input.
@JsonDeserialize and @JsonSerialize
• Purpose: Customize the deserialization and serialization process by specifying custom serializers and
deserializers.
• Example:
public class User {
@JsonDeserialize(using = CustomDateDeserializer.class)
@JsonSerialize(using = CustomDateSerializer.class)
private LocalDate birthdate;
// Custom Deserializer
public class CustomDateDeserializer extends JsonDeserializer<LocalDate> {
@Override
public LocalDate deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
return LocalDate.parse(p.getText(), DateTimeFormatter.ofPattern("dd-MM-yyyy"));
}
}
// Custom Serializer
public class CustomDateSerializer extends JsonSerializer<LocalDate> {
@Override
public void serialize(LocalDate value, JsonGenerator gen, SerializerProvider serializers) throws
IOException {
gen.writeString(value.format(DateTimeFormatter.ofPattern("dd-MM-yyyy")));
}
}
• Explanation: The @JsonDeserialize and @JsonSerialize annotations allow you to specify custom logic
for parsing and formatting JSON data. This is particularly useful when working with non-standard formats
or complex types.
18. Lombok Annotations
Lombok is a library that helps reduce boilerplate code by automatically generating commonly used
methods like getters, setters, constructors, toString, etc.
@Data
• Purpose: Generates all boilerplate code for getters, setters, toString, equals, hashCode, and required
constructors.
• Example:
import lombok.Data;
@Data
public class User {
private String username;
private String email;
}
@Getter
@Setter
public class User {
private String username;
private String email;
}
• Explanation: The @Getter and @Setter annotations generate getter and setter methods for the
specified fields, reducing the need to manually write these methods.
@ToString
• Purpose: Generates a toString() method that includes all fields of the class.
• Example:
import lombok.ToString;
@ToString
public class User {
private String username;
private String email;
}
• Explanation: The @ToString annotation creates a toString() method that represents the object’s field
values in a readable format. You can customize it to exclude specific fields or include only certain fields.
@EqualsAndHashCode
• Purpose: Generates equals() and hashCode() methods for the class.
• Example:
import lombok.EqualsAndHashCode;
@EqualsAndHashCode
public class User {
private String username;
private String email;
}
@NoArgsConstructor
public class User {
private String username;
private String email;
}
• Explanation: The @NoArgsConstructor annotation creates a constructor with no arguments. It’s useful
when working with frameworks that require a default constructor.
@AllArgsConstructor
• Purpose: Generates a constructor with arguments for all fields.
• Example:
import lombok.AllArgsConstructor;
@AllArgsConstructor
public class User {
private String username;
private String email;
}
• Explanation: The @AllArgsConstructor annotation creates a constructor that takes all fields as
parameters. This is helpful for creating fully initialized objects in one step.
@RequiredArgsConstructor
• Purpose: Generates a constructor with arguments for all final fields and fields marked with @NonNull.
• Example:
import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor
public class User {
private final String username;
private String email;
}
• Explanation: The @RequiredArgsConstructor annotation creates a constructor for fields that are final or
marked as @NonNull. This is useful for immutable objects or enforcing mandatory fields.
• Explanation: The @ApiOperation annotation describes the endpoint’s purpose, helping to generate
clear and detailed API documentation.
@ApiResponse
• Purpose: Describes the response of an operation, including status codes and messages.
• Example:
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class UserController {
@ApiResponses({
@ApiResponse(code = 200, message = "Successfully retrieved user"),
@ApiResponse(code = 404, message = "User not found")
})
@GetMapping("/user")
public User getUser(String username) {
// Method implementation
return new User();
}
}
• Explanation: The @ApiResponses annotation lists possible responses for an endpoint, including HTTP
status codes and corresponding messages.
@ApiModel and @ApiModelProperty
• Purpose: Annotate model classes and properties for API documentation.
• Example:
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
@Configuration
@EnableSwagger2
public class SwaggerConfig {
@Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.basePackage("com.example"))
.paths(PathSelectors.any())
.build();
}
}
• Explanation: The @EnableSwagger2 annotation is used to activate Swagger 2 for API documentation.
It’s typically placed in a configuration class.
20. OpenAPI Annotations
@OpenAPIDefinition
• Purpose: Defines the global configuration for the OpenAPI documentation.
• Example:
import io.swagger.v3.oas.annotations.OpenAPIDefinition;
import io.swagger.v3.oas.annotations.info.Info;
import io.swagger.v3.oas.annotations.info.Contact;
import org.springframework.context.annotation.Configuration;
@Configuration
@OpenAPIDefinition(
info = @Info(
title = "User API",
version = "1.0",
description = "API for managing users",
contact = @Contact(name = "Support Team", email = "support@example.com")
)
)
public class OpenApiConfig {
// Configuration class for OpenAPI documentation
}
• Explanation: The @OpenAPIDefinition annotation provides global settings for OpenAPI documentation,
including metadata like the title, version, description, and contact information.
@Tag
• Purpose: Organizes operations under a specific tag (group).
• Example:
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@Tag(name = "User Management", description = "Operations related to user management")
public class UserController {
@GetMapping("/user")
public User getUser(String username) {
// Method implementation
return new User();
}
}
• Explanation: The @Tag annotation groups operations (endpoints) under a specific category, making the
documentation more organized.
@Operation
• Purpose: Describes a single API operation.
• Example:
import io.swagger.v3.oas.annotations.Operation;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class UserController {
@Operation(summary = "Get user by username", description = "Fetches user details based on the
provided username")
@GetMapping("/user")
public User getUser(String username) {
// Method implementation
return new User();
}
}
• Explanation: The @Operation annotation provides a summary and detailed description of the API
endpoint
21. Conditional Annotations
@Conditional
• Purpose: Allows conditional bean registration based on custom conditions implemented via a Condition
interface.
• Example:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AppConfig {
@Bean
@Conditional(OnMyCondition.class)
public MyBean myBean() {
return new MyBean();
}
}
• Explanation: The @Conditional annotation takes a class implementing Condition as a parameter. The
bean (myBean) will only be created if the condition specified in OnMyCondition is met.
@ConditionalOnBean
• Purpose: The bean is created only if a specific bean (or beans) is already present in the application
context.
• Example:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ConditionalOnBean;
@Configuration
public class AppConfig {
@Bean
public SomeService someService() {
return new SomeService();
}
@Bean
@ConditionalOnBean(SomeService.class)
public AnotherService anotherService() {
return new AnotherService();
}
}
@Configuration
public class AppConfig {
@Bean
@ConditionalOnMissingBean(SomeService.class)
public DefaultService defaultService() {
return new DefaultService();
}
}
@Configuration
public class AppConfig {
@Bean
@ConditionalOnClass(name = "com.example.SomeLibrary")
public LibraryBean libraryBean() {
return new LibraryBean();
}
}
@Configuration
public class AppConfig {
@Bean
@ConditionalOnMissingClass("com.example.SomeLibrary")
public MissingLibraryBean missingLibraryBean() {
return new MissingLibraryBean();
}
}
@Configuration
public class AppConfig {
@Bean
@ConditionalOnProperty(name = "app.feature.enabled", havingValue = "true")
public FeatureBean featureBean() {
return new FeatureBean();
}
}
@Configuration
public class AppConfig {
@Bean
@ConditionalOnExpression("#{systemProperties[’app.mode’] == ’production’}")
public ProductionBean productionBean() {
return new ProductionBean();
}
}
@Configuration
public class AppConfig {
@Bean
@ConditionalOnResource(resources = "classpath:config.properties")
public ResourceBean resourceBean() {
return new ResourceBean();
}
}