Entry Point & Annotations

The main application class, Spring Boot exclusions, component scan strategy, and the two custom annotations — @AdminRestController and @AllowedRoles.

Application Entry Point

File: org.arya.banking.admin.AryaBankingAdminServiceApplication

Java code-highlight
@SpringBootApplication(exclude = {
    DataSourceAutoConfiguration.class,
    DataSourceTransactionManagerAutoConfiguration.class,
    HibernateJpaAutoConfiguration.class
})
@ComponentScan(basePackages = {
    "org.arya.banking.admin",
    "org.arya.banking.common"
})
@EnableMongoAuditing
@EnableDiscoveryClient
public class AryaBankingAdminServiceApplication {

    public static void main(String[] args) {
        SpringApplication.run(AryaBankingAdminServiceApplication.class, args);
    }
}

Annotation Breakdown

@SpringBootApplication(exclude = ...)

The admin-service is MongoDB-only — it has no relational database. The three excluded auto-configurations prevent Spring Boot from attempting to set up a DataSource (JDBC), a transaction manager backed by a DataSource, and Hibernate JPA. Without these exclusions, the application would fail on startup because no javax.sql.DataSource bean is present on the classpath.

Excluded ClassWhy
DataSourceAutoConfigurationPrevents JDBC DataSource bean creation
DataSourceTransactionManagerAutoConfigurationPrevents JDBC transaction manager setup
HibernateJpaAutoConfigurationPrevents JPA/Hibernate EntityManagerFactory setup
MongoDB's own auto-configuration (MongoAutoConfiguration, MongoDataAutoConfiguration) is NOT excluded — it runs normally and wires up the MongoClient, MongoTemplate, and all MongoRepository beans.

@ComponentScan(basePackages = {...})

By default, Spring Boot scans only the package of the main class and its sub-packages (org.arya.banking.admin). The explicit @ComponentScan extends the scan to include org.arya.banking.common, which means:

  • GlobalExceptionHandler (@RestControllerAdvice) is registered — all GlobalException subclasses are handled automatically.
  • MetadataInitializer (active under metadata-loader profile) is picked up without any additional import.
  • Common @Component, @Service, and @Mapper beans from the shared library are wired into the application context.
If you add a new shared component to arya-banking-common and it does not appear in the context, verify that its package is under org.arya.banking.common — components in other packages will not be scanned.

@EnableMongoAuditing

Activates Spring Data MongoDB's auditing infrastructure. Any document class annotated with @CreatedDate and @LastModifiedDate (inherited from AryaBase in the common library) will have those fields populated automatically on insert and update.

Java code-highlight
// From AryaBase in arya-banking-common
public abstract class AryaBase {
    @CreatedDate
    private Instant createdAt;

    @LastModifiedDate
    private Instant updatedAt;

    private boolean deleted;
}

@EnableDiscoveryClient

Registers the service with Netflix Eureka on startup. The service appears in the Eureka dashboard as ARYA-BANKING-ADMIN-SERVICE and can be resolved by other services using its logical name through the gateway or Feign clients.


Custom Annotations

@AdminRestController

File: org.arya.banking.admin.annotation.AdminRestController

A composed annotation that bundles @RestController and @RequestMapping("/api/admin") into a single declaration. All controllers except ClientCreationController use it.

Java code-highlight
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@RestController
@RequestMapping("/api/admin")
public @interface AdminRestController {}

Usage on a controller:

Java code-highlight
@AdminRestController   // replaces @RestController + @RequestMapping("/api/admin")
public class VaultAppRoleController {

    @GetMapping("/vault-approle")
    public ResponseEntity<List<String>> getAppRoles() { ... }
}

Why it matters: Without this annotation, every controller would need to repeat @RequestMapping("/api/admin") individually. A single change to the base path requires touching only the annotation definition, not every controller.

ClientCreationController does not use @AdminRestController — it declares @RequestMapping("/api/admin") directly. This is a known inconsistency flagged for cleanup.

@AllowedRoles

File: org.arya.banking.admin.annotation.AllowedRoles

A method-level meta-annotation that wraps the RolePermissionValidator SpEL expression behind a clean, declarative interface.

Java code-highlight
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@PreAuthorize("@rolePermissionValidator.hasAnyRole(authentication, #allowedRoles.value())")
public @interface AllowedRoles {
    String value();
}

Intended usage:

Java code-highlight
// Instead of this (current approach):
@PreAuthorize("@rolePermissionValidator.hasAnyRole(authentication, 'vault-ops')")
@GetMapping("/vault-approle")
public ResponseEntity<?> getAppRoles() { ... }

// You would write:
@AllowedRoles("vault-ops")
@GetMapping("/vault-approle")
public ResponseEntity<?> getAppRoles() { ... }

How it works:

The #allowedRoles.value() in the SpEL expression is a parameter reference — #allowedRoles refers to the annotation instance itself, and .value() returns the String passed to the annotation. Spring Security evaluates this expression at method interception time, passing the resolved string to RolePermissionValidator.hasAnyRole(authentication, operation).

@AllowedRoles is defined but currently unused. All five controllers use inline @PreAuthorize expressions. Adopting @AllowedRoles consistently would reduce repetition and make role changes easier to trace. Either migrate all controllers to use it or remove it to avoid dead code.

Startup Sequence

Vault bootstrap happens before the application context is created. If the role-id or secret-id is invalid or expired, the JVM exits before Spring even begins wiring beans.
spring-bootannotationsentry-pointrbac