Implementing Aspect-Oriented Programming for Common Field Population in Spring Boot

Case Study: Common Field Population

Adding Required Dependencies

To enable aspect-oriented programming in a Spring Boot project, include the following dependencies in your pom.xml:

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjrt</artifactId>
</dependency>

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
</dependency>

Defining a Custom Annotation

Create a custom annotation to mark methods that require automatic field population:

/**
 * Custom annotation to indicate methods needing automatic field population.
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface FieldPopulation {
    // Specifies the database operation type: UPDATE or INSERT
    OperationType operation();
}

Creating an Aspect Class

Implement an aspect class to handle the logic for populating common fields:

/**
 * Aspect class for automatic population of common fields.
 */
@Aspect
@Component
@Slf4j
public class FieldPopulationAspect {

    /**
     * Pointcut definition targeting methods in mapper classes annotated with @FieldPopulation.
     */
    @Pointcut("execution(* com.example.mapper.*.*(..)) && @annotation(com.example.annotation.FieldPopulation)")
    public void fieldPopulationPointcut() {}

    /**
     * Before advice to populate common fields before method execution.
     */
    @Before("fieldPopulationPointcut()")
    public void populateFields(JoinPoint joinPoint) {
        log.info("Starting automatic field population...");

        // Retrieve the method signature and annotation
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        FieldPopulation fieldPopulation = methodSignature.getMethod().getAnnotation(FieldPopulation.class);
        OperationType operation = fieldPopulation.operation();

        // Get the method arguments, assuming the first argument is the entity object
        Object[] arguments = joinPoint.getArgs();
        if (arguments == null || arguments.length == 0) {
            return;
        }
        Object entity = arguments[0];

        // Prepare data for population
        LocalDateTime currentTime = LocalDateTime.now();
        Long currentUserId = UserContext.getCurrentUserId();

        // Populate fields based on operation type using reflection
        try {
            if (operation == OperationType.INSERT) {
                // Set four common fields for INSERT operations
                Method setCreationTime = entity.getClass().getDeclaredMethod(FieldConstants.SET_CREATION_TIME, LocalDateTime.class);
                Method setCreator = entity.getClass().getDeclaredMethod(FieldConstants.SET_CREATOR, Long.class);
                Method setModificationTime = entity.getClass().getDeclaredMethod(FieldConstants.SET_MODIFICATION_TIME, LocalDateTime.class);
                Method setModifier = entity.getClass().getDeclaredMethod(FieldConstants.SET_MODIFIER, Long.class);

                setCreationTime.invoke(entity, currentTime);
                setCreator.invoke(entity, currentUserId);
                setModificationTime.invoke(entity, currentTime);
                setModifier.invoke(entity, currentUserId);
            } else if (operation == OperationType.UPDATE) {
                // Set two common fields for UPDATE operations
                Method setModificationTime = entity.getClass().getDeclaredMethod(FieldConstants.SET_MODIFICATION_TIME, LocalDateTime.class);
                Method setModifier = entity.getClass().getDeclaredMethod(FieldConstants.SET_MODIFIER, Long.class);

                setModificationTime.invoke(entity, currentTime);
                setModifier.invoke(entity, currentUserId);
            }
        } catch (Exception e) {
            log.error("Error during field population: ", e);
        }
    }
}

Applying the Annottaion

Finally, annotate the methods in your mapper classes that require automatic field population with @FieldPopulation. For example:

@FieldPopulation(operation = OperationType.INSERT)
public void insertEntity(Entity entity) {
    // Method implementation
}

This setup ensures that common fields like creation time, creator, modification time, and modifier are auotmatically populated based on the specified database operation type, reducing boilerplate code and improving maintainability.

Tags: Spring Boot aop aspectj annotations reflection

Posted on Sat, 03 Oct 2026 16:52:27 +0000 by chelerblondi