Commonly Used Annotations in Java

@Target({ElementType.METHOD, ElementType.TYPE})

Defines the scope of an annotation (where it can be applied). If used outside this scope, a compilation error occurs.

Value Description
ElementType.METHOD Applies to methods
ElementType.TYPE Applies to classes, interfaces (including annotation types), or enum declarations
ElementType.LOCAL_VARIABLE Applies to local variables
ElementType.PARAMETER Applies to parameters
ElementType.CONSTRUCTOR Applies to constructors
ElementType.FIELD Applies to fields
ElementType.PACKAGE Applies to packages

@Retention(RetentionPolicy.SOURCE)

Specifies the lifecycle of an annotation.

Value Description Scope Use Case
RetentionPolicy.SOURCE Retained only in source file, discarded during compilation Source file Check-like operations (e.g., @Override, @SuppressWarnings)
RetentionPolicy.CLASS Retained in .class file but discarded at runtime (default) Class file Preprocessing at compile time (e.g., generate helper code like ButterKnife)
RetentionPolicy.RUNTIME Retained in .class file and available at runtime Runtime Need to dynamically retrieve annotation information at runtime

For example, Lombok's @AllArgsConstructor has SOURCE retention. As shown in the image, after compilation, the annotation disappears and a full-argument constructor is added.

Validation Annotations

Add Dependency

<!-- Spring Boot Starter Validation -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-validation</artifactId>
</dependency>

Code Example

  1. DTO
import javax.validation.constraints.*;

public class UserDTO {

    @NotBlank(message = "Username cannot be empty")
    private String username;

    @Min(value = 18, message = "Age must be at least 18")
    @Max(value = 60, message = "Age cannot exceed 60")
    private Integer age;

    @Email(message = "Invalid email format")
    private String email;

    // getters/setters omitted
}
  1. Controller
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import javax.validation.constraints.*;

@RestController
@RequestMapping("/users")
@Validated
public class UserController {

    @PostMapping("/create")
    public String createUser(@RequestBody @Valid UserDTO dto) {
        return "User created: " + dto.getUsername();
    }

    @GetMapping("/byId")
    public String getUserById(@RequestParam("id") @Min(1) Long id) {
        return "User ID: " + id;
    }

    @GetMapping("/search")
    public String searchUsers(
            @RequestParam("keyword") @NotBlank String keyword,
            @RequestParam("limit") @Max(100) int limit) {
        return "Search: " + keyword + ", limit: " + limit;
    }

    @DeleteMapping("/{id}")
    public String deleteUser(@PathVariable @Positive Long id) {
        return "Deleted user: " + id;
    }
}

@Valid and @Validated

  • Primitive-type parameters (e.g., Long, int, String) require @Validated on the class level to trigger validation.
  • Object-type parameters (e.g., UserDTO) only need @Valid; class-level @Validated is optional.
  • Group validation can be performed with @Validated(Group.class).

Origin:

Annotation Package
@Valid javax.validation.Valid (JSR 303)
@Validated org.springframework.validation.annotation.Validated (Spring)

Other Common Validation Annotations

Annotation Applicable Types Description
@Null Any Must be null
@NotNull Any Must not be null
@NotBlank String Must not be null and contain atleast one non-whitespace character
@NotEmpty String, Collection, Array, Map Must not be null and have at least one element (or length > 0 for String)
@Size(min=, max=) Collection, Array, String, Map Size must be within given boundaries
@Min(value) Numeric Must be >= specified value
@Max(value) Numeric Must be <= specified value
@DecimalMin(value) BigDecimal, String, etc. Must be >= specified decimal value
@DecimalMax(value) BigDecimal, String, etc. Must be <= specified decimal value
@Pattern(regexp=) String Must match the regex
@Email String Must be a valid email (requires hibernate-validator)
@Positive Numeric Must be > 0
@PositiveOrZero Numeric Must be >= 0
@Negative Numeric Must be < 0
@NegativeOrZero Numeric Must be <= 0
@Future Date (e.g., java.util.Date, java.time.LocalDate) Must be a future date
@FutureOrPresent Date Must be present or future
@Past Date Must be a past date
@PastOrPresent Date Must be present or past

@NoRepositoryBean

Indicates that an interface will not be instantiated as a bean on its own; it only serves as a parent interface for other repositories.

@PathVariable

Binds a method parameter to a URI template variable. Used in RESTful endpoints to extract values from the URL.

// URL: /test1/123
@RequestMapping("/test1/{username}")
public String test1(@PathVariable("username") String name) {
    if (name != null && !name.isEmpty()) {
        return name;
    }
    return "null";
}

@RequestParam

Binds a method parameter to a URL query parameter.

// URL: /test1?name=zhangsan
@RequestMapping("/test1")
public String test1(@RequestParam String name) {
    if (name != null && !name.isEmpty()) {
        return name;
    }
    return "null";
}

Various writing styles:

1. @RequestParam(value="id", required = true/false)
2. @RequestParam(value="id")
3. @RequestParam("id")
4. @RequestParam   // if parameter name matches
5. Omit the annotation entirely if the name matches

Summary for HTTP methods:

  • @GetMapping works with @RequestParam, @RequestBody, @PathVariable.
  • @PostMapping works with @RequestBody (using @RequestParam may cause issues).
  • @RequestParam: for wrappers, primitives, Strings; specify name with value.
  • @RequestBody: for objects, Maps, Lists.
  • @PathVariable: for URL placeholders.

@RequestBody

Binds the HTTP request body to a method parameter.

  • For form submissions, do not use @RequestBody; Spring MVC automatically binds form data.
  • If @RequestBody is used, it reads from the request body instead of the form.
  • POST endpoints require @RequestBody to correctly parse parameters; GET endpoints do not.

Example:

@RequestMapping("/test1")
public String test1(@RequestBody User user) {
    String name = user.getUsername();
    if (name != null && !name.isEmpty()) {
        return name;
    }
    return "null";
}

@ResponseBody

Indicates that the return value of a method should be written directly to the HTTP response body (e.g., as JSON), not parsed as a view path.

@Param

MyBatis annotation to bind method parameters to SQL parameters when names do not match.

public User getUser(@Param("userName") String name, String id);
<select id="getUser" resultMap="User">
    select * from user where user_name = #{userName} and user_id = #{id}
</select>

@ModelAttribute

Binds form data (application/x-www-form-urlencoded) to an object. For JSON data, use @RequestBody instead.

Conditional Registration Annotations

@ConditionalOnBean

Registers a bean only if the specified bean exists in the context.

@Bean
@ConditionalOnBean(Emp.class)
public User user(User user) {
    return new User("zhangsan");
}

@ConditionalOnProperty

Registers a bean only if the specified property is present in the configuration.

@ConditionalOnProperty(prefix = "person", name = {"name", "age"})
@Bean
public User user(@Value("${person.name}") String name, @Value("${person.pwd}") String pwd) {
    System.out.println("name:" + name + ",pwd:" + pwd);
    return new User();
}

@ConditionalOnMissingBean

Registers a bean only if the specified bean is missing from the context.

@ConditionalOnMissingBean(User.class)
@Bean
public Dept dept() {
    return new Dept();
}

@ConditionalOnClass

Registers a bean only if the specified class is present on the classpath.

@ConditionalOnClass(User.class)
public Dept dept() {
    return new Dept();
}

@PostConstruct

Executes after dependency injection is complete. Typically used for initialization logic. Unlike static{} blocks (which cannot use injected beans), @PostConstruct can.

@Component
public class MyBean {

    @PostConstruct
    public void init() {
        // initialization logic
    }
}

Execution order (for Spring-managed beans): static{} > Constructor > @Autowired > @PostConstruct > CommandLineRunner.

Reading Configuration Values

@ConfigurationProperties(prefix = "aliyun.oss.file")

Binds properties with a given prefix to a Java object. Requires getters and setters.

@Value

Injects a single property value.

@Value("${aliyun.oss.file.endpoint}")
private String endpoint;

Can also be used on method parameters:

@Bean
public User user(@Value("${person.name}") String name, @Value("${person.pwd}") String pwd) {
    System.out.println("name:" + name + ",pwd:" + pwd);
    return new User();
}

Global Exception Handling and Cross-Cutting Concerns

@ControllerAdvice

A class-level annotation for global exception handling and model attribute addition in traditional MVC controllers (returning view names).

@RestControllerAdvice

Similar to @ControllerAdvice but for @RestController-based REST APIs, returning JSON/XML responses.

@Bean

Indicates that a method produces a bean to be managed by the Spring container.

@Configuration
public class AppConfig {

    @Bean
    public MyService myService() {
        return new MyServiceImpl();
    }
}

Method parameters can be auto-injected if beans exist:

@Bean
public User user() {
    return new User();
}

@Bean
public Dept dept(User user) {
    return new Dept();
}

@Import

Imports additional configuration classes, usually when they are not under the component scan path.

Importing a Configuration Class

@Import(SpringBootConfig.class)
@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

Importing an ImportSelector Implementation

For bulk imports, implement ImportSelector:

public class MyImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata metadata) {
        return new String[]{"com.example.config.SpringBootConfig"};
    }
}

Then import via @Import(MyImportSelector.class). The implementation can read from a file (e.g., config.imports) for dynamic loading.

Jackson Annotations

@JsonSerialize(using = ToStringSerializer.class)

Converts Long to String to prevent precision loss when sent to frontend (e.g., large numbers become 0).

@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")

Formats date/time fields in JSON.

@JsonIgnore

Excludes a field from JSON serialization/deserialization.

public class User {
    @JsonIgnore
    private String name;
    // ...
}

@JsonView

Controls which fields are returned based on the view used in the controller.

Define interfaces:

public class UserVo {

    @JsonView(ListView.class)
    private String name;
    @JsonView(ListView.class)
    private String deptName;
    @JsonView(InfoView.class)
    private String phone;
    @JsonView(InfoView.class)
    private String email;

    public interface ListView {}
    public interface InfoView extends ListView {}
}

Use in controller:

@GetMapping("/info")
@JsonView(UserVo.InfoView.class)
public UserVo info() {
    // returns all fields
}

@GetMapping("/list")
@JsonView(UserVo.ListView.class)
public UserVo list() {
    // returns only name and deptName
}

If using a wrapper class (e.g., R<T>), additional configuration is needed:

  1. Add @JsonView on the wrapper's data field (affects all endpoints).
  2. Use MappingJacksonValue to set view per request.
  3. Custom serializer (recommended):
public class RSerializer<T> extends JsonSerializer<R<T>> {
    private final ObjectMapper mapper;

    public RSerializer(ObjectMapper mapper) {
        this.mapper = mapper;
    }

    @Override
    public void serialize(R<T> value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        gen.writeStartObject();
        gen.writeNumberField("code", value.getCode());
        gen.writeStringField("msg", value.getMsg());
        gen.writeFieldName("data");
        T data = value.getData();
        if (data == null) {
            gen.writeNull();
        } else {
            serializers.defaultSerializeValue(data, gen);
        }
        gen.writeEndObject();
    }
}

Register via configuration:

@Configuration
public class JacksonConfig {
    private final ObjectMapper objectMapper;

    public JacksonConfig(ObjectMapper objectMapper) {
        this.objectMapper = objectMapper;
    }

    @PostConstruct
    public void setUp() {
        SimpleModule module = new SimpleModule();
        module.addSerializer(R.class, new RSerializer<>(objectMapper));
        objectMapper.registerModule(module);
    }
}

Or via annotation on the wrapper class: @JsonSerialize(using = RSerializer.class).

@JsonNaming

Defines a naming strategy for serialization/deserialization. Common strategies: SnakeCaseStrategy, KebabCaseStrategy, UpperCamelCaseStrategy, LowerCamelCaseStrategy, PascalCaseStrategy, LowerDotCaseStrategy, UpperDotCaseStrategy.

Example:

@JsonNaming(PropertyNamingStrategies.UpperCamelCaseStrategy.class)
public class MyClass {}

@JsonRawValue

Serializes a field as raw JSON without escaping quotes.

Without @JsonRawValue: [{"code": 4, "desc": "资料未补全"}] With @JsonRawValue: [{"code": 4, "desc": "资料未补全"}]

@JsonInclude

Controls inclusion of properties during serialization.

Common values: ALWAYS, NON_NULL, NON_ABSENT, NON_EMPTY, NON_DEFAULT, CUSTOM, USE_DEFAULTS.

Example: @JsonInclude(JsonInclude.Include.NON_EMPTY).

@JsonProperty

Specifies the name of a property in JSON.

@JsonProperty("GPSBrand")
private String GPSBrand;

Handling Unknown Properties

If you configure a custom ObjectMapper, unknown properties may cause errors. Set:

objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

Timezone Issue with @JsonFormat

If dates appear off by one day, set timezone in ObjectMapper:

objectMapper.setTimeZone(TimeZone.getTimeZone(ZoneId.systemDefault()));

Duplicate Data in JSON

Avoid using both @JsonNaming and @JsonProperty on the same class/field, as it can produce duplicate entries.

MyBatis-Plus Annotations

@TableField(typeHandler = Fastjson2TypeHandler.class)

Auto-converts between database JSON strings and Java objects.

@TableField(typeHandler = Fastjson2TypeHandler.class)
private Object content;

Other Annotations

@DateTimeFormat vs @JsonFormat

  • @DateTimeFormat: for converting date strings from form/URL parameters (non-JSON).
  • @JsonFormat: for converting date strings in JSON (both incoming and outgoing).

Both can be used on the same field if needed.

Example: @DateTimeFormat(pattern = "yyyy-MM-dd") on a LocalDate field for form parameters.

Tags: java annotations Spring jackson Validation

Posted on Fri, 14 Aug 2026 16:53:12 +0000 by smonsivaes