or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

aop.mdcore-container.mddata-access.mdindex.mdintegration.mdmessaging.mdreactive-web.mdtesting.mdweb-framework.md

integration.mddocs/

0

# Integration & Support

1

2

Spring provides additional modules for integration with various enterprise technologies, cross-cutting concerns, and advanced features. This includes spring-aspects, spring-instrument, spring-context-support, spring-websocket, and spring-oxm modules.

3

4

## Maven Dependencies

5

6

```xml

7

<!-- Spring Aspects (AspectJ integration) -->

8

<dependency>

9

<groupId>org.springframework</groupId>

10

<artifactId>spring-aspects</artifactId>

11

<version>5.3.39</version>

12

</dependency>

13

14

<!-- Spring Instrument (Load-time weaving) -->

15

<dependency>

16

<groupId>org.springframework</groupId>

17

<artifactId>spring-instrument</artifactId>

18

<version>5.3.39</version>

19

</dependency>

20

21

<!-- Spring Context Support (Additional context implementations) -->

22

<dependency>

23

<groupId>org.springframework</groupId>

24

<artifactId>spring-context-support</artifactId>

25

<version>5.3.39</version>

26

</dependency>

27

28

<!-- Spring WebSocket -->

29

<dependency>

30

<groupId>org.springframework</groupId>

31

<artifactId>spring-websocket</artifactId>

32

<version>5.3.39</version>

33

</dependency>

34

35

<!-- Spring OXM (Object/XML Mapping) -->

36

<dependency>

37

<groupId>org.springframework</groupId>

38

<artifactId>spring-oxm</artifactId>

39

<version>5.3.39</version>

40

</dependency>

41

42

<!-- AspectJ Runtime -->

43

<dependency>

44

<groupId>org.aspectj</groupId>

45

<artifactId>aspectjrt</artifactId>

46

<version>1.9.7</version>

47

</dependency>

48

49

<!-- AspectJ Weaver -->

50

<dependency>

51

<groupId>org.aspectj</groupId>

52

<artifactId>aspectjweaver</artifactId>

53

<version>1.9.7</version>

54

</dependency>

55

```

56

57

## Core Imports

58

59

```java { .api }

60

// AspectJ Integration

61

import org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect;

62

import org.springframework.context.annotation.EnableLoadTimeWeaving;

63

import org.springframework.context.annotation.LoadTimeWeavingConfigurer;

64

import org.springframework.instrument.classloading.LoadTimeWeaver;

65

66

// Scheduling Support

67

import org.springframework.scheduling.annotation.Async;

68

import org.springframework.scheduling.annotation.EnableAsync;

69

import org.springframework.scheduling.annotation.Scheduled;

70

import org.springframework.scheduling.annotation.EnableScheduling;

71

import org.springframework.scheduling.TaskScheduler;

72

import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;

73

74

// Caching Support

75

import org.springframework.cache.annotation.Cacheable;

76

import org.springframework.cache.annotation.CacheEvict;

77

import org.springframework.cache.annotation.EnableCaching;

78

import org.springframework.cache.CacheManager;

79

import org.springframework.cache.concurrent.ConcurrentMapCacheManager;

80

81

// WebSocket Support

82

import org.springframework.web.socket.WebSocketHandler;

83

import org.springframework.web.socket.WebSocketSession;

84

import org.springframework.web.socket.config.annotation.EnableWebSocket;

85

import org.springframework.web.socket.config.annotation.WebSocketConfigurer;

86

import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;

87

88

// STOMP Support

89

import org.springframework.messaging.handler.annotation.MessageMapping;

90

import org.springframework.messaging.simp.annotation.EnableWebSocketMessageBroker;

91

import org.springframework.messaging.simp.config.MessageBrokerRegistry;

92

93

// OXM (Object/XML Mapping)

94

import org.springframework.oxm.Marshaller;

95

import org.springframework.oxm.Unmarshaller;

96

import org.springframework.oxm.jaxb.Jaxb2Marshaller;

97

98

// Validation Support

99

import org.springframework.validation.annotation.Validated;

100

import javax.validation.Valid;

101

import javax.validation.constraints.*;

102

```

103

104

## AspectJ Integration

105

106

### Load-Time Weaving

107

108

```java { .api }

109

// Enables load-time weaving support

110

@Target(ElementType.TYPE)

111

@Retention(RetentionPolicy.RUNTIME)

112

@Documented

113

@Import(LoadTimeWeavingConfiguration.class)

114

public @interface EnableLoadTimeWeaving {

115

116

AspectJWeaving aspectjWeaving() default AspectJWeaving.AUTODETECT;

117

118

enum AspectJWeaving {

119

ENABLED, DISABLED, AUTODETECT

120

}

121

}

122

123

// Configuration interface for load-time weaving

124

public interface LoadTimeWeavingConfigurer {

125

126

LoadTimeWeaver getLoadTimeWeaver();

127

}

128

129

// Load-time weaver interface

130

public interface LoadTimeWeaver {

131

132

void addTransformer(ClassFileTransformer transformer);

133

134

ClassLoader getInstrumentableClassLoader();

135

136

ClassLoader getThrowawayClassLoader();

137

}

138

139

// Configuration for AspectJ load-time weaving

140

@Configuration

141

@EnableLoadTimeWeaving

142

public class AspectJConfig implements LoadTimeWeavingConfigurer {

143

144

@Override

145

public LoadTimeWeaver getLoadTimeWeaver() {

146

return new InstrumentationLoadTimeWeaver();

147

}

148

149

@Bean

150

public AnnotationBeanConfigurerAspect beanConfigurerAspect() {

151

return AnnotationBeanConfigurerAspect.aspectOf();

152

}

153

}

154

```

155

156

### Dependency Injection in Domain Objects

157

158

```java { .api }

159

// Aspect for configuring Spring beans

160

public aspect AnnotationBeanConfigurerAspect {

161

162

// Configures objects with @Configurable annotation

163

public pointcut beanConstruction(Object bean) :

164

initialization((@Configurable *).new(..)) && this(bean);

165

166

after(Object bean) returning : beanConstruction(bean) {

167

configureBean(bean);

168

}

169

170

public void configureBean(Object bean) {

171

// Configure the bean using Spring's dependency injection

172

}

173

}

174

175

// Annotation for domain objects that should be configured by Spring

176

@Target(ElementType.TYPE)

177

@Retention(RetentionPolicy.RUNTIME)

178

@Documented

179

public @interface Configurable {

180

181

String value() default "";

182

183

Autowire autowire() default Autowire.NO;

184

185

boolean dependencyCheck() default false;

186

187

boolean preConstruction() default false;

188

}

189

190

// Usage example - domain object with dependency injection

191

@Entity

192

@Configurable

193

public class Order {

194

195

@Transient

196

@Autowired

197

private OrderValidator orderValidator;

198

199

@Transient

200

@Autowired

201

private PricingService pricingService;

202

203

private Long id;

204

private BigDecimal amount;

205

206

public void validate() {

207

orderValidator.validate(this);

208

}

209

210

public BigDecimal calculateTotalPrice() {

211

return pricingService.calculatePrice(this);

212

}

213

}

214

```

215

216

## Scheduling Support

217

218

### Async Processing

219

220

```java { .api }

221

// Enables async method execution

222

@Target(ElementType.TYPE)

223

@Retention(RetentionPolicy.RUNTIME)

224

@Documented

225

@Import(AsyncConfigurationSelector.class)

226

public @interface EnableAsync {

227

228

Class<? extends Annotation> annotation() default Async.class;

229

230

boolean proxyTargetClass() default false;

231

232

AdviceMode mode() default AdviceMode.PROXY;

233

234

int order() default Ordered.LOWEST_PRECEDENCE;

235

}

236

237

// Annotation to mark methods for async execution

238

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

239

@Retention(RetentionPolicy.RUNTIME)

240

@Documented

241

public @interface Async {

242

243

String value() default "";

244

}

245

246

// Configuration for async processing

247

@Configuration

248

@EnableAsync

249

public class AsyncConfig implements AsyncConfigurer {

250

251

@Override

252

public Executor getAsyncExecutor() {

253

ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();

254

executor.setCorePoolSize(5);

255

executor.setMaxPoolSize(20);

256

executor.setQueueCapacity(100);

257

executor.setThreadNamePrefix("async-");

258

executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());

259

executor.initialize();

260

return executor;

261

}

262

263

@Override

264

public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {

265

return new SimpleAsyncUncaughtExceptionHandler();

266

}

267

}

268

269

// Service with async methods

270

@Service

271

public class NotificationService {

272

273

@Async

274

public CompletableFuture<String> sendEmailAsync(String to, String subject, String body) {

275

// Simulate email sending delay

276

try {

277

Thread.sleep(1000);

278

} catch (InterruptedException e) {

279

Thread.currentThread().interrupt();

280

}

281

282

String result = "Email sent to " + to;

283

return CompletableFuture.completedFuture(result);

284

}

285

286

@Async("customExecutor")

287

public void processInBackground(ProcessingTask task) {

288

// Long-running background processing

289

task.process();

290

}

291

292

@Bean("customExecutor")

293

public TaskExecutor customTaskExecutor() {

294

ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();

295

executor.setCorePoolSize(2);

296

executor.setMaxPoolSize(10);

297

executor.setThreadNamePrefix("custom-");

298

executor.initialize();

299

return executor;

300

}

301

}

302

```

303

304

### Task Scheduling

305

306

```java { .api }

307

// Enables scheduled task execution

308

@Target(ElementType.TYPE)

309

@Retention(RetentionPolicy.RUNTIME)

310

@Documented

311

@Import(SchedulingConfiguration.class)

312

public @interface EnableScheduling {

313

}

314

315

// Annotation for scheduling methods

316

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

317

@Retention(RetentionPolicy.RUNTIME)

318

@Documented

319

@Repeatable(Schedules.class)

320

public @interface Scheduled {

321

322

String CRON_DISABLED = "-";

323

324

String cron() default "";

325

326

String zone() default "";

327

328

long fixedDelay() default -1;

329

330

String fixedDelayString() default "";

331

332

long fixedRate() default -1;

333

334

String fixedRateString() default "";

335

336

long initialDelay() default -1;

337

338

String initialDelayString() default "";

339

}

340

341

// Configuration for scheduling

342

@Configuration

343

@EnableScheduling

344

public class SchedulingConfig implements SchedulingConfigurer {

345

346

@Override

347

public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {

348

taskRegistrar.setScheduler(taskScheduler());

349

}

350

351

@Bean

352

public TaskScheduler taskScheduler() {

353

ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();

354

scheduler.setPoolSize(5);

355

scheduler.setThreadNamePrefix("scheduled-");

356

scheduler.setWaitForTasksToCompleteOnShutdown(true);

357

scheduler.setAwaitTerminationSeconds(30);

358

scheduler.initialize();

359

return scheduler;

360

}

361

}

362

363

// Service with scheduled methods

364

@Service

365

public class ScheduledTaskService {

366

367

private static final Logger logger = LoggerFactory.getLogger(ScheduledTaskService.class);

368

369

// Fixed rate execution (every 5 seconds)

370

@Scheduled(fixedRate = 5000)

371

public void performPeriodicTask() {

372

logger.info("Executing periodic task at {}", LocalDateTime.now());

373

}

374

375

// Fixed delay execution (5 seconds after previous completion)

376

@Scheduled(fixedDelay = 5000)

377

public void performTaskWithDelay() {

378

logger.info("Executing task with delay at {}", LocalDateTime.now());

379

// Simulate processing time

380

try {

381

Thread.sleep(2000);

382

} catch (InterruptedException e) {

383

Thread.currentThread().interrupt();

384

}

385

}

386

387

// Cron-based scheduling (every minute)

388

@Scheduled(cron = "0 * * * * *")

389

public void performCronTask() {

390

logger.info("Executing cron task at {}", LocalDateTime.now());

391

}

392

393

// Daily cleanup at 2 AM

394

@Scheduled(cron = "0 0 2 * * *", zone = "America/New_York")

395

public void dailyCleanup() {

396

logger.info("Performing daily cleanup at {}", LocalDateTime.now());

397

cleanupOldData();

398

}

399

400

// Conditional scheduling based on properties

401

@Scheduled(fixedRate = 10000)

402

@ConditionalOnProperty(name = "app.monitoring.enabled", havingValue = "true")

403

public void monitoringTask() {

404

logger.info("Performing monitoring task");

405

performHealthCheck();

406

}

407

408

// Initial delay before first execution

409

@Scheduled(fixedRate = 30000, initialDelay = 10000)

410

public void taskWithInitialDelay() {

411

logger.info("Task with initial delay executed");

412

}

413

414

private void cleanupOldData() {

415

// Cleanup logic

416

}

417

418

private void performHealthCheck() {

419

// Health check logic

420

}

421

}

422

```

423

424

## Caching Support

425

426

### Caching Annotations

427

428

```java { .api }

429

// Enables caching support

430

@Target(ElementType.TYPE)

431

@Retention(RetentionPolicy.RUNTIME)

432

@Documented

433

@Import(CachingConfigurationSelector.class)

434

public @interface EnableCaching {

435

436

boolean proxyTargetClass() default false;

437

438

AdviceMode mode() default AdviceMode.PROXY;

439

440

int order() default Ordered.LOWEST_PRECEDENCE;

441

}

442

443

// Annotation to cache method results

444

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

445

@Retention(RetentionPolicy.RUNTIME)

446

@Inherited

447

@Documented

448

public @interface Cacheable {

449

450

@AliasFor("cacheNames")

451

String[] value() default {};

452

453

@AliasFor("value")

454

String[] cacheNames() default {};

455

456

String key() default "";

457

458

String keyGenerator() default "";

459

460

String cacheManager() default "";

461

462

String cacheResolver() default "";

463

464

String condition() default "";

465

466

String unless() default "";

467

468

boolean sync() default false;

469

}

470

471

// Annotation to evict cache entries

472

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

473

@Retention(RetentionPolicy.RUNTIME)

474

@Inherited

475

@Documented

476

public @interface CacheEvict {

477

478

@AliasFor("cacheNames")

479

String[] value() default {};

480

481

@AliasFor("value")

482

String[] cacheNames() default {};

483

484

String key() default "";

485

486

String keyGenerator() default "";

487

488

String cacheManager() default "";

489

490

String cacheResolver() default "";

491

492

String condition() default "";

493

494

boolean allEntries() default false;

495

496

boolean beforeInvocation() default false;

497

}

498

499

// Annotation to update cache entries

500

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

501

@Retention(RetentionPolicy.RUNTIME)

502

@Inherited

503

@Documented

504

public @interface CachePut {

505

506

@AliasFor("cacheNames")

507

String[] value() default {};

508

509

@AliasFor("value")

510

String[] cacheNames() default {};

511

512

String key() default "";

513

514

String keyGenerator() default "";

515

516

String cacheManager() default "";

517

518

String cacheResolver() default "";

519

520

String condition() default "";

521

522

String unless() default "";

523

}

524

```

525

526

### Cache Configuration

527

528

```java { .api }

529

// Cache configuration

530

@Configuration

531

@EnableCaching

532

public class CacheConfig {

533

534

@Bean

535

public CacheManager cacheManager() {

536

ConcurrentMapCacheManager cacheManager = new ConcurrentMapCacheManager();

537

cacheManager.setCacheNames(Arrays.asList(

538

"users", "products", "orders", "settings"

539

));

540

cacheManager.setAllowNullValues(false);

541

return cacheManager;

542

}

543

544

// Custom key generator

545

@Bean

546

public KeyGenerator customKeyGenerator() {

547

return (target, method, params) -> {

548

StringBuilder key = new StringBuilder();

549

key.append(target.getClass().getSimpleName());

550

key.append(".").append(method.getName());

551

for (Object param : params) {

552

key.append(".").append(param != null ? param.toString() : "null");

553

}

554

return key.toString();

555

};

556

}

557

558

// Redis cache manager (if using Redis)

559

@Bean

560

@ConditionalOnClass(RedisTemplate.class)

561

public CacheManager redisCacheManager(RedisConnectionFactory connectionFactory) {

562

RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()

563

.serializeKeysWith(RedisSerializationContext.SerializationPair

564

.fromSerializer(new StringRedisSerializer()))

565

.serializeValuesWith(RedisSerializationContext.SerializationPair

566

.fromSerializer(new GenericJackson2JsonRedisSerializer()))

567

.entryTtl(Duration.ofHours(1));

568

569

return RedisCacheManager.builder(connectionFactory)

570

.cacheDefaults(config)

571

.build();

572

}

573

}

574

575

// Service with caching

576

@Service

577

public class UserService {

578

579

private final UserRepository userRepository;

580

581

public UserService(UserRepository userRepository) {

582

this.userRepository = userRepository;

583

}

584

585

@Cacheable(value = "users", key = "#id")

586

public User findById(Long id) {

587

System.out.println("Loading user from database: " + id);

588

return userRepository.findById(id).orElse(null);

589

}

590

591

@Cacheable(value = "users", key = "#username")

592

public User findByUsername(String username) {

593

System.out.println("Loading user by username: " + username);

594

return userRepository.findByUsername(username).orElse(null);

595

}

596

597

@CachePut(value = "users", key = "#result.id")

598

public User save(User user) {

599

return userRepository.save(user);

600

}

601

602

@CacheEvict(value = "users", key = "#id")

603

public void deleteById(Long id) {

604

userRepository.deleteById(id);

605

}

606

607

@CacheEvict(value = "users", allEntries = true)

608

public void clearAllUsers() {

609

// This will clear all entries from the "users" cache

610

}

611

612

// Conditional caching

613

@Cacheable(value = "users", condition = "#id > 0", unless = "#result == null")

614

public User findByIdConditional(Long id) {

615

return userRepository.findById(id).orElse(null);

616

}

617

618

// Custom key generator

619

@Cacheable(value = "users", keyGenerator = "customKeyGenerator")

620

public List<User> findByAgeRange(int minAge, int maxAge) {

621

return userRepository.findByAgeBetween(minAge, maxAge);

622

}

623

}

624

```

625

626

## WebSocket Support

627

628

### WebSocket Configuration

629

630

```java { .api }

631

// Enables WebSocket support

632

@Target(ElementType.TYPE)

633

@Retention(RetentionPolicy.RUNTIME)

634

@Documented

635

@Import(DelegatingWebSocketConfiguration.class)

636

public @interface EnableWebSocket {

637

}

638

639

// Configuration interface for WebSocket

640

public interface WebSocketConfigurer {

641

642

void registerWebSocketHandlers(WebSocketHandlerRegistry registry);

643

}

644

645

// WebSocket handler interface

646

public interface WebSocketHandler {

647

648

void afterConnectionEstablished(WebSocketSession session) throws Exception;

649

650

void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception;

651

652

void handleTransportError(WebSocketSession session, Throwable exception) throws Exception;

653

654

void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception;

655

656

boolean supportsPartialMessages();

657

}

658

659

// WebSocket session interface

660

public interface WebSocketSession extends Closeable {

661

662

String getId();

663

664

URI getUri();

665

666

HttpHeaders getHandshakeHeaders();

667

668

Map<String, Object> getAttributes();

669

670

Principal getPrincipal();

671

672

InetSocketAddress getLocalAddress();

673

674

InetSocketAddress getRemoteAddress();

675

676

String getAcceptedProtocol();

677

678

void sendMessage(WebSocketMessage<?> message) throws IOException;

679

680

boolean isOpen();

681

682

void close() throws IOException;

683

684

void close(CloseStatus status) throws IOException;

685

}

686

687

// WebSocket configuration

688

@Configuration

689

@EnableWebSocket

690

public class WebSocketConfig implements WebSocketConfigurer {

691

692

@Override

693

public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {

694

registry.addHandler(new ChatWebSocketHandler(), "/chat")

695

.addInterceptors(new HttpSessionHandshakeInterceptor())

696

.setAllowedOrigins("*");

697

698

registry.addHandler(new EchoWebSocketHandler(), "/echo")

699

.withSockJS(); // Enable SockJS fallback

700

}

701

702

@Bean

703

public WebSocketHandler chatWebSocketHandler() {

704

return new ChatWebSocketHandler();

705

}

706

}

707

708

// WebSocket handler implementation

709

public class ChatWebSocketHandler extends TextWebSocketHandler {

710

711

private static final Logger logger = LoggerFactory.getLogger(ChatWebSocketHandler.class);

712

private final Set<WebSocketSession> sessions = new CopyOnWriteArraySet<>();

713

714

@Override

715

public void afterConnectionEstablished(WebSocketSession session) throws Exception {

716

sessions.add(session);

717

logger.info("WebSocket connection established: {}", session.getId());

718

719

// Send welcome message

720

String welcomeMessage = "Welcome to chat! Session ID: " + session.getId();

721

session.sendMessage(new TextMessage(welcomeMessage));

722

}

723

724

@Override

725

public void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {

726

logger.info("Received message from {}: {}", session.getId(), message.getPayload());

727

728

// Broadcast message to all connected sessions

729

String broadcastMessage = session.getId() + ": " + message.getPayload();

730

for (WebSocketSession webSocketSession : sessions) {

731

if (webSocketSession.isOpen()) {

732

webSocketSession.sendMessage(new TextMessage(broadcastMessage));

733

}

734

}

735

}

736

737

@Override

738

public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {

739

logger.error("Transport error for session {}: {}", session.getId(), exception.getMessage());

740

sessions.remove(session);

741

}

742

743

@Override

744

public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception {

745

sessions.remove(session);

746

logger.info("WebSocket connection closed: {} with status {}", session.getId(), closeStatus);

747

}

748

}

749

```

750

751

### STOMP Messaging Support

752

753

```java { .api }

754

// Enables WebSocket message broker

755

@Target(ElementType.TYPE)

756

@Retention(RetentionPolicy.RUNTIME)

757

@Documented

758

@Import(DelegatingWebSocketMessageBrokerConfiguration.class)

759

public @interface EnableWebSocketMessageBroker {

760

}

761

762

// Configuration interface for WebSocket message broker

763

public interface WebSocketMessageBrokerConfigurer {

764

765

default void configureMessageBroker(MessageBrokerRegistry registry) {

766

}

767

768

default void registerStompEndpoints(StompEndpointRegistry registry) {

769

}

770

771

default void configureWebSocketTransport(WebSocketTransportRegistration registry) {

772

}

773

774

default void configureClientInboundChannel(ChannelRegistration registration) {

775

}

776

777

default void configureClientOutboundChannel(ChannelRegistration registration) {

778

}

779

}

780

781

// STOMP configuration

782

@Configuration

783

@EnableWebSocketMessageBroker

784

public class WebSocketMessageConfig implements WebSocketMessageBrokerConfigurer {

785

786

@Override

787

public void configureMessageBroker(MessageBrokerRegistry registry) {

788

// Enable simple in-memory broker

789

registry.enableSimpleBroker("/topic", "/queue");

790

791

// Set application destination prefix

792

registry.setApplicationDestinationPrefixes("/app");

793

794

// Configure user destination prefix

795

registry.setUserDestinationPrefix("/user");

796

}

797

798

@Override

799

public void registerStompEndpoints(StompEndpointRegistry registry) {

800

// Register STOMP endpoint

801

registry.addEndpoint("/ws")

802

.setAllowedOrigins("*")

803

.withSockJS();

804

}

805

806

@Override

807

public void configureClientInboundChannel(ChannelRegistration registration) {

808

registration.interceptors(new ChannelInterceptor() {

809

@Override

810

public Message<?> preSend(Message<?> message, MessageChannel channel) {

811

StompHeaderAccessor accessor = MessageHeaderAccessor.getAccessor(message, StompHeaderAccessor.class);

812

if (StompCommand.CONNECT.equals(accessor.getCommand())) {

813

// Authentication logic here

814

}

815

return message;

816

}

817

});

818

}

819

}

820

821

// STOMP message controller

822

@Controller

823

public class WebSocketMessageController {

824

825

private final SimpMessagingTemplate messagingTemplate;

826

827

public WebSocketMessageController(SimpMessagingTemplate messagingTemplate) {

828

this.messagingTemplate = messagingTemplate;

829

}

830

831

@MessageMapping("/chat.send")

832

@SendTo("/topic/public")

833

public ChatMessage sendMessage(@Payload ChatMessage chatMessage) {

834

return chatMessage;

835

}

836

837

@MessageMapping("/chat.addUser")

838

@SendTo("/topic/public")

839

public ChatMessage addUser(@Payload ChatMessage chatMessage,

840

SimpMessageHeaderAccessor headerAccessor) {

841

// Add username in web socket session

842

headerAccessor.getSessionAttributes().put("username", chatMessage.getSender());

843

return chatMessage;

844

}

845

846

// Send message to specific user

847

@MessageMapping("/private")

848

public void sendToUser(@Payload PrivateMessage message, Principal principal) {

849

messagingTemplate.convertAndSendToUser(

850

message.getRecipient(),

851

"/queue/messages",

852

message

853

);

854

}

855

856

// Scheduled message broadcasting

857

@Scheduled(fixedRate = 30000)

858

public void sendPeriodicMessage() {

859

ServerMessage message = ServerMessage.builder()

860

.content("Server time: " + LocalDateTime.now())

861

.timestamp(LocalDateTime.now())

862

.build();

863

864

messagingTemplate.convertAndSend("/topic/server", message);

865

}

866

}

867

868

// WebSocket event listener

869

@Component

870

public class WebSocketEventListener {

871

872

private static final Logger logger = LoggerFactory.getLogger(WebSocketEventListener.class);

873

874

@Autowired

875

private SimpMessagingTemplate messagingTemplate;

876

877

@EventListener

878

public void handleWebSocketConnectListener(SessionConnectedEvent event) {

879

logger.info("Received a new web socket connection");

880

}

881

882

@EventListener

883

public void handleWebSocketDisconnectListener(SessionDisconnectEvent event) {

884

StompHeaderAccessor headerAccessor = StompHeaderAccessor.wrap(event.getMessage());

885

886

String username = (String) headerAccessor.getSessionAttributes().get("username");

887

if (username != null) {

888

logger.info("User disconnected: {}", username);

889

890

ChatMessage chatMessage = ChatMessage.builder()

891

.type(MessageType.LEAVE)

892

.sender(username)

893

.build();

894

895

messagingTemplate.convertAndSend("/topic/public", chatMessage);

896

}

897

}

898

}

899

```

900

901

## Object/XML Mapping (OXM)

902

903

### Marshalling Support

904

905

```java { .api }

906

// Interface for marshalling objects to XML

907

public interface Marshaller {

908

909

boolean supports(Class<?> clazz);

910

911

void marshal(Object graph, Result result) throws IOException, XmlMappingException;

912

}

913

914

// Interface for unmarshalling XML to objects

915

public interface Unmarshaller {

916

917

boolean supports(Class<?> clazz);

918

919

Object unmarshal(Source source) throws IOException, XmlMappingException;

920

}

921

922

// JAXB marshaller implementation

923

public class Jaxb2Marshaller implements Marshaller, Unmarshaller, InitializingBean {

924

925

public void setContextPath(String contextPath);

926

public void setClassesToBeBound(Class<?>... classesToBeBound);

927

public void setPackagesToScan(String... packagesToScan);

928

public void setSchema(Resource schema);

929

public void setMarshallerProperties(Map<String, ?> properties);

930

public void setUnmarshallerProperties(Map<String, ?> properties);

931

public void setValidationEventHandler(ValidationEventHandler validationEventHandler);

932

933

@Override

934

public boolean supports(Class<?> clazz);

935

936

@Override

937

public void marshal(Object graph, Result result) throws XmlMappingException;

938

939

@Override

940

public Object unmarshal(Source source) throws XmlMappingException;

941

}

942

943

// OXM configuration

944

@Configuration

945

public class OxmConfig {

946

947

@Bean

948

public Jaxb2Marshaller marshaller() {

949

Jaxb2Marshaller marshaller = new Jaxb2Marshaller();

950

marshaller.setPackagesToScan("com.example.xml.model");

951

952

Map<String, Object> properties = new HashMap<>();

953

properties.put(Marshaller.JAXB_FORMATTED_OUTPUT, true);

954

properties.put(Marshaller.JAXB_ENCODING, "UTF-8");

955

marshaller.setMarshallerProperties(properties);

956

957

return marshaller;

958

}

959

960

@Bean

961

public MarshallingService marshallingService(Jaxb2Marshaller marshaller) {

962

return new MarshallingService(marshaller, marshaller);

963

}

964

}

965

966

// XML model with JAXB annotations

967

@XmlRootElement(name = "user")

968

@XmlAccessorType(XmlAccessType.FIELD)

969

public class UserXml {

970

971

@XmlElement

972

private Long id;

973

974

@XmlElement

975

private String username;

976

977

@XmlElement

978

private String email;

979

980

@XmlElement(name = "created_date")

981

@XmlJavaTypeAdapter(LocalDateTimeAdapter.class)

982

private LocalDateTime createdDate;

983

984

@XmlElementWrapper(name = "orders")

985

@XmlElement(name = "order")

986

private List<OrderXml> orders;

987

988

// Constructors, getters, setters

989

}

990

991

// Marshalling service

992

@Service

993

public class MarshallingService {

994

995

private final Marshaller marshaller;

996

private final Unmarshaller unmarshaller;

997

998

public MarshallingService(Marshaller marshaller, Unmarshaller unmarshaller) {

999

this.marshaller = marshaller;

1000

this.unmarshaller = unmarshaller;

1001

}

1002

1003

public String marshalToString(Object object) {

1004

try (StringWriter writer = new StringWriter()) {

1005

marshaller.marshal(object, new StreamResult(writer));

1006

return writer.toString();

1007

} catch (Exception e) {

1008

throw new XmlProcessingException("Failed to marshal object", e);

1009

}

1010

}

1011

1012

public void marshalToFile(Object object, String filename) {

1013

try (FileOutputStream fos = new FileOutputStream(filename)) {

1014

marshaller.marshal(object, new StreamResult(fos));

1015

} catch (Exception e) {

1016

throw new XmlProcessingException("Failed to marshal to file", e);

1017

}

1018

}

1019

1020

@SuppressWarnings("unchecked")

1021

public <T> T unmarshalFromString(String xml, Class<T> clazz) {

1022

try (StringReader reader = new StringReader(xml)) {

1023

return (T) unmarshaller.unmarshal(new StreamSource(reader));

1024

} catch (Exception e) {

1025

throw new XmlProcessingException("Failed to unmarshal from string", e);

1026

}

1027

}

1028

1029

@SuppressWarnings("unchecked")

1030

public <T> T unmarshalFromFile(String filename, Class<T> clazz) {

1031

try (FileInputStream fis = new FileInputStream(filename)) {

1032

return (T) unmarshaller.unmarshal(new StreamSource(fis));

1033

} catch (Exception e) {

1034

throw new XmlProcessingException("Failed to unmarshal from file", e);

1035

}

1036

}

1037

}

1038

```

1039

1040

## Email Support

1041

1042

### JavaMail Integration

1043

1044

```java { .api }

1045

// Mail configuration

1046

@Configuration

1047

@ConditionalOnProperty(name = "spring.mail.host")

1048

public class MailConfig {

1049

1050

@Bean

1051

public JavaMailSender mailSender(

1052

@Value("${spring.mail.host}") String host,

1053

@Value("${spring.mail.port:587}") int port,

1054

@Value("${spring.mail.username}") String username,

1055

@Value("${spring.mail.password}") String password) {

1056

1057

JavaMailSenderImpl mailSender = new JavaMailSenderImpl();

1058

mailSender.setHost(host);

1059

mailSender.setPort(port);

1060

mailSender.setUsername(username);

1061

mailSender.setPassword(password);

1062

1063

Properties props = mailSender.getJavaMailProperties();

1064

props.put("mail.transport.protocol", "smtp");

1065

props.put("mail.smtp.auth", "true");

1066

props.put("mail.smtp.starttls.enable", "true");

1067

props.put("mail.debug", "false");

1068

1069

return mailSender;

1070

}

1071

1072

@Bean

1073

public TemplateEngine templateEngine() {

1074

SpringTemplateEngine templateEngine = new SpringTemplateEngine();

1075

templateEngine.addTemplateResolver(emailTemplateResolver());

1076

return templateEngine;

1077

}

1078

1079

private ITemplateResolver emailTemplateResolver() {

1080

ClassLoaderTemplateResolver templateResolver = new ClassLoaderTemplateResolver();

1081

templateResolver.setPrefix("/mail-templates/");

1082

templateResolver.setSuffix(".html");

1083

templateResolver.setTemplateMode(TemplateMode.HTML);

1084

templateResolver.setCharacterEncoding("UTF-8");

1085

templateResolver.setCacheable(false);

1086

return templateResolver;

1087

}

1088

}

1089

1090

// Email service

1091

@Service

1092

public class EmailService {

1093

1094

private final JavaMailSender mailSender;

1095

private final TemplateEngine templateEngine;

1096

1097

@Value("${app.mail.from}")

1098

private String fromEmail;

1099

1100

public EmailService(JavaMailSender mailSender, TemplateEngine templateEngine) {

1101

this.mailSender = mailSender;

1102

this.templateEngine = templateEngine;

1103

}

1104

1105

public void sendSimpleEmail(String to, String subject, String text) {

1106

SimpleMailMessage message = new SimpleMailMessage();

1107

message.setFrom(fromEmail);

1108

message.setTo(to);

1109

message.setSubject(subject);

1110

message.setText(text);

1111

1112

mailSender.send(message);

1113

}

1114

1115

public void sendHtmlEmail(String to, String subject, String templateName, Map<String, Object> variables) {

1116

try {

1117

MimeMessage mimeMessage = mailSender.createMimeMessage();

1118

MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true, "UTF-8");

1119

1120

helper.setFrom(fromEmail);

1121

helper.setTo(to);

1122

helper.setSubject(subject);

1123

1124

Context context = new Context();

1125

context.setVariables(variables);

1126

String htmlContent = templateEngine.process(templateName, context);

1127

1128

helper.setText(htmlContent, true);

1129

1130

mailSender.send(mimeMessage);

1131

} catch (MessagingException e) {

1132

throw new EmailException("Failed to send HTML email", e);

1133

}

1134

}

1135

1136

public void sendEmailWithAttachment(String to, String subject, String text, String attachmentPath) {

1137

try {

1138

MimeMessage mimeMessage = mailSender.createMimeMessage();

1139

MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);

1140

1141

helper.setFrom(fromEmail);

1142

helper.setTo(to);

1143

helper.setSubject(subject);

1144

helper.setText(text);

1145

1146

File attachment = new File(attachmentPath);

1147

helper.addAttachment(attachment.getName(), attachment);

1148

1149

mailSender.send(mimeMessage);

1150

} catch (MessagingException e) {

1151

throw new EmailException("Failed to send email with attachment", e);

1152

}

1153

}

1154

1155

@Async

1156

public CompletableFuture<Void> sendEmailAsync(String to, String subject, String templateName, Map<String, Object> variables) {

1157

sendHtmlEmail(to, subject, templateName, variables);

1158

return CompletableFuture.completedFuture(null);

1159

}

1160

}

1161

```

1162

1163

## Validation Support

1164

1165

### Bean Validation Integration

1166

1167

```java { .api }

1168

// Validation configuration

1169

@Configuration

1170

public class ValidationConfig {

1171

1172

@Bean

1173

public LocalValidatorFactoryBean validator() {

1174

return new LocalValidatorFactoryBean();

1175

}

1176

1177

@Bean

1178

public MethodValidationPostProcessor methodValidationPostProcessor(LocalValidatorFactoryBean validator) {

1179

MethodValidationPostProcessor processor = new MethodValidationPostProcessor();

1180

processor.setValidator(validator);

1181

return processor;

1182

}

1183

}

1184

1185

// Service with method-level validation

1186

@Service

1187

@Validated

1188

public class UserValidationService {

1189

1190

public User createUser(@Valid CreateUserRequest request) {

1191

// Method parameter validation

1192

return new User(request.getUsername(), request.getEmail());

1193

}

1194

1195

public List<User> getUsers(

1196

@Min(0) @Max(100) int page,

1197

@Min(1) @Max(50) int size) {

1198

// Parameter validation with constraints

1199

return findUsers(page, size);

1200

}

1201

1202

public void updateUser(

1203

@NotNull @Positive Long id,

1204

@Valid @NotNull UpdateUserRequest request) {

1205

// Multiple parameter validation

1206

updateUserById(id, request);

1207

}

1208

1209

@NotNull

1210

public User findUserById(@NotNull @Positive Long id) {

1211

// Return value validation

1212

return getUserById(id);

1213

}

1214

1215

private User getUserById(Long id) {

1216

// Implementation

1217

return new User();

1218

}

1219

1220

private List<User> findUsers(int page, int size) {

1221

// Implementation

1222

return new ArrayList<>();

1223

}

1224

1225

private void updateUserById(Long id, UpdateUserRequest request) {

1226

// Implementation

1227

}

1228

}

1229

1230

// Custom validator

1231

@Component

1232

public class UniqueUsernameValidator implements ConstraintValidator<UniqueUsername, String> {

1233

1234

private final UserRepository userRepository;

1235

1236

public UniqueUsernameValidator(UserRepository userRepository) {

1237

this.userRepository = userRepository;

1238

}

1239

1240

@Override

1241

public boolean isValid(String username, ConstraintValidatorContext context) {

1242

if (username == null) {

1243

return true; // Let @NotNull handle null values

1244

}

1245

1246

return !userRepository.existsByUsername(username);

1247

}

1248

}

1249

1250

// Custom validation annotation

1251

@Target({ElementType.FIELD, ElementType.PARAMETER})

1252

@Retention(RetentionPolicy.RUNTIME)

1253

@Constraint(validatedBy = UniqueUsernameValidator.class)

1254

@Documented

1255

public @interface UniqueUsername {

1256

1257

String message() default "Username already exists";

1258

1259

Class<?>[] groups() default {};

1260

1261

Class<? extends Payload>[] payload() default {};

1262

}

1263

1264

// DTO with validation annotations

1265

public class CreateUserRequest {

1266

1267

@NotBlank(message = "Username is required")

1268

@Size(min = 3, max = 50, message = "Username must be between 3 and 50 characters")

1269

@UniqueUsername

1270

private String username;

1271

1272

@NotBlank(message = "Email is required")

1273

@Email(message = "Email should be valid")

1274

private String email;

1275

1276

@NotBlank(message = "First name is required")

1277

@Size(max = 50)

1278

private String firstName;

1279

1280

@NotBlank(message = "Last name is required")

1281

@Size(max = 50)

1282

private String lastName;

1283

1284

@Pattern(regexp = "^\\+?[1-9]\\d{1,14}$", message = "Invalid phone number")

1285

private String phoneNumber;

1286

1287

@Past(message = "Birth date must be in the past")

1288

private LocalDate birthDate;

1289

1290

// Constructors, getters, setters

1291

}

1292

```

1293

1294

Spring's integration and support modules provide essential capabilities for building enterprise applications with advanced features like AspectJ integration, caching, scheduling, WebSocket communication, XML processing, email support, and comprehensive validation.