or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

annotation-based-definition.mdaspect-management.mdindex.mdjoin-point-introspection.mdreflection-api.mdruntime-utilities.mdsignature-system.md

aspect-management.mddocs/

0

# Aspect Management

1

2

Runtime support for aspect instantiation, lifecycle management, and access across different instantiation models. AspectJ supports various aspect instantiation patterns including singleton, per-object (perthis/pertarget), per-type-within, and control flow-based (percflow/percflowbelow) aspects. The aspect management API provides programmatic access to aspect instances and their binding status.

3

4

## Capabilities

5

6

### Aspects Class

7

8

The `Aspects` class handles generic `aspectOf` method functionality when those methods are not available in the aspects but added later through load time weaving. It provides reflective access to aspect instances across all supported instantiation models.

9

10

```java { .api }

11

/**

12

* Handles generic aspectOf method when those are not available in the aspects but added later on

13

* through load time weaving. Aspects.aspectOf(..) is doing reflective calls to the aspect aspectOf,

14

* so for better performance consider using ajc compilation of the aspects and using them as a binary

15

* dependencies in your project.

16

*/

17

public class Aspects {

18

/**

19

* Returns the singleton aspect or the percflow / percflowbelow associated with the current thread

20

* @param aspectClass the aspect class

21

* @return the singleton aspect or the percflow / percflowbelow associated with the current thread

22

* @throws NoAspectBoundException if no such aspect

23

*/

24

public static <T> T aspectOf(Class<T> aspectClass) throws NoAspectBoundException;

25

26

/**

27

* Returns the associated perthis / pertarget aspect instance

28

* @param aspectClass the aspect class

29

* @param perObject the this/target object for which to look for an aspect instance

30

* @return the associated perthis / pertarget aspect instance

31

* @throws NoAspectBoundException if no such aspect, or no aspect bound

32

*/

33

public static <T> T aspectOf(Class<T> aspectClass, Object perObject) throws NoAspectBoundException;

34

35

/**

36

* Returns the associated pertypewithin aspect instance

37

* @param aspectClass the aspect class

38

* @param perTypeWithin the class for which to search for an aspect instance

39

* @return the associated aspect instance

40

* @throws NoAspectBoundException if no such aspect, or no aspect bound

41

*/

42

public static <T> T aspectOf(Class<T> aspectClass, Class<?> perTypeWithin) throws NoAspectBoundException;

43

44

/**

45

* Checks if singleton aspect or percflow / percflowbelow aspect is bound

46

* @param aspectClass the aspect class

47

* @return true if singleton aspect or percflow / percflowbelow aspect is bound

48

*/

49

public static boolean hasAspect(Class<?> aspectClass);

50

51

/**

52

* Checks if the perthis / pertarget aspect is bound

53

* @param aspectClass the aspect class

54

* @param perObject the this/target object for which to look for an aspect instance

55

* @return true if the perthis / pertarget aspect is bound

56

*/

57

public static boolean hasAspect(Class<?> aspectClass, Object perObject);

58

59

/**

60

* Checks if the pertypewithin aspect is bound

61

* @param aspectClass the aspect class

62

* @param perTypeWithin class

63

* @return true if the pertypewithin aspect is bound

64

*/

65

public static boolean hasAspect(Class<?> aspectClass, Class<?> perTypeWithin);

66

}

67

```

68

69

**Usage Examples:**

70

71

```java

72

import org.aspectj.lang.Aspects;

73

import org.aspectj.lang.NoAspectBoundException;

74

75

// Singleton aspect access

76

@Aspect

77

public class LoggingAspect {

78

private int callCount = 0;

79

80

@Before("execution(* com.example..*.*(..))")

81

public void logCall() {

82

callCount++;

83

System.out.println("Call #" + callCount);

84

}

85

86

public int getCallCount() {

87

return callCount;

88

}

89

}

90

91

public class AspectClient {

92

public void checkLoggingAspect() {

93

try {

94

if (Aspects.hasAspect(LoggingAspect.class)) {

95

LoggingAspect aspect = Aspects.aspectOf(LoggingAspect.class);

96

System.out.println("Total calls: " + aspect.getCallCount());

97

} else {

98

System.out.println("Logging aspect is not bound");

99

}

100

} catch (NoAspectBoundException e) {

101

System.out.println("Failed to access aspect: " + e.getMessage());

102

}

103

}

104

}

105

```

106

107

### Per-Object Aspect Management

108

109

For aspects with `perthis()` or `pertarget()` instantiation, each target object gets its own aspect instance:

110

111

```java

112

// Per-object aspect example

113

@Aspect("perthis(execution(* com.example.service.*.*(..)))")

114

public class ServiceMonitorAspect {

115

private long startTime;

116

private int methodCount = 0;

117

118

@Before("execution(* com.example.service.*.*(..))")

119

public void startTiming() {

120

if (methodCount == 0) {

121

startTime = System.currentTimeMillis();

122

}

123

methodCount++;

124

}

125

126

public long getElapsedTime() {

127

return System.currentTimeMillis() - startTime;

128

}

129

130

public int getMethodCount() {

131

return methodCount;

132

}

133

}

134

135

public class ServiceClient {

136

public void monitorService(Object serviceInstance) {

137

try {

138

if (Aspects.hasAspect(ServiceMonitorAspect.class, serviceInstance)) {

139

ServiceMonitorAspect monitor =

140

Aspects.aspectOf(ServiceMonitorAspect.class, serviceInstance);

141

System.out.println("Service has been running for " +

142

monitor.getElapsedTime() + " ms");

143

System.out.println("Methods called: " + monitor.getMethodCount());

144

}

145

} catch (NoAspectBoundException e) {

146

System.out.println("No monitor bound to this service instance");

147

}

148

}

149

}

150

```

151

152

### Per-Type-Within Aspect Management

153

154

For aspects with `pertypewithin()` instantiation, each type within the specified type pattern gets its own aspect instance:

155

156

```java

157

// Per-type-within aspect example

158

@Aspect("pertypewithin(com.example.model.*)")

159

public class EntityAuditAspect {

160

private final String entityType;

161

private int operationCount = 0;

162

163

public EntityAuditAspect() {

164

// The entity type is determined at aspect creation time

165

this.entityType = thisJoinPoint.getSignature().getDeclaringType().getSimpleName();

166

}

167

168

@Before("execution(* set*(..))")

169

public void auditPropertyChange() {

170

operationCount++;

171

System.out.println("Property change in " + entityType +

172

" (operation #" + operationCount + ")");

173

}

174

175

public int getOperationCount() {

176

return operationCount;

177

}

178

}

179

180

public class EntityAuditClient {

181

public void checkEntityAudit(Class<?> entityClass) {

182

try {

183

if (Aspects.hasAspect(EntityAuditAspect.class, entityClass)) {

184

EntityAuditAspect audit =

185

Aspects.aspectOf(EntityAuditAspect.class, entityClass);

186

System.out.println("Audit operations for " + entityClass.getSimpleName() +

187

": " + audit.getOperationCount());

188

}

189

} catch (NoAspectBoundException e) {

190

System.out.println("No audit aspect for " + entityClass.getSimpleName());

191

}

192

}

193

}

194

```

195

196

### Exception Handling

197

198

The aspect management API uses `NoAspectBoundException` to indicate when aspects are not available:

199

200

```java { .api }

201

/**

202

* Thrown by the aspectOf special method on aspect types

203

* when there is no aspect of that type currently bound.

204

*/

205

public class NoAspectBoundException extends RuntimeException {

206

/**

207

* Constructs exception with aspect name and optional cause

208

* @param aspectName name of the aspect that is not bound

209

* @param inner the underlying cause, if any

210

*/

211

public NoAspectBoundException(String aspectName, Throwable inner);

212

213

/**

214

* Default constructor for cases where no specific information is available

215

*/

216

public NoAspectBoundException();

217

218

/**

219

* Returns the underlying cause of this exception

220

* @return the cause, or null if there is no cause

221

*/

222

public Throwable getCause();

223

}

224

```

225

226

**Usage Examples:**

227

228

```java

229

public class RobustAspectClient {

230

231

public <T> T safeAspectAccess(Class<T> aspectClass) {

232

try {

233

return Aspects.aspectOf(aspectClass);

234

} catch (NoAspectBoundException e) {

235

System.err.println("Aspect " + aspectClass.getSimpleName() +

236

" is not bound: " + e.getMessage());

237

if (e.getCause() != null) {

238

System.err.println("Underlying cause: " + e.getCause().getMessage());

239

}

240

return null;

241

}

242

}

243

244

public void conditionalAspectUsage(Object target) {

245

// Check before attempting access

246

if (Aspects.hasAspect(ServiceMonitorAspect.class, target)) {

247

try {

248

ServiceMonitorAspect monitor =

249

Aspects.aspectOf(ServiceMonitorAspect.class, target);

250

// Use the aspect safely

251

System.out.println("Monitor found: " + monitor.getMethodCount() + " calls");

252

} catch (NoAspectBoundException e) {

253

// This should rarely happen if hasAspect returned true

254

System.err.println("Race condition: aspect became unbound");

255

}

256

}

257

}

258

}

259

```

260

261

## Aspect Instantiation Models

262

263

AspectJ supports several instantiation models that determine when and how aspect instances are created:

264

265

### Singleton (Default)

266

267

- **Pattern**: `@Aspect` or `@Aspect("")`

268

- **Behavior**: One aspect instance per JVM

269

- **Access**: `Aspects.aspectOf(AspectClass.class)`

270

- **Use Case**: Global cross-cutting concerns like logging, security

271

272

### Per-This

273

274

- **Pattern**: `@Aspect("perthis(pointcut)")`

275

- **Behavior**: One aspect instance per object matched by `this()`

276

- **Access**: `Aspects.aspectOf(AspectClass.class, thisObject)`

277

- **Use Case**: State tracking per object instance

278

279

### Per-Target

280

281

- **Pattern**: `@Aspect("pertarget(pointcut)")`

282

- **Behavior**: One aspect instance per object matched by `target()`

283

- **Access**: `Aspects.aspectOf(AspectClass.class, targetObject)`

284

- **Use Case**: Monitoring or decorating target objects

285

286

### Per-Type-Within

287

288

- **Pattern**: `@Aspect("pertypewithin(TypePattern)")`

289

- **Behavior**: One aspect instance per type matching the pattern

290

- **Access**: `Aspects.aspectOf(AspectClass.class, matchingClass)`

291

- **Use Case**: Per-class statistics or type-specific behavior

292

293

### Per-Control-Flow

294

295

- **Pattern**: `@Aspect("percflow(pointcut)")` or `@Aspect("percflowbelow(pointcut)")`

296

- **Behavior**: One aspect instance per control flow thread

297

- **Access**: `Aspects.aspectOf(AspectClass.class)` (thread-local)

298

- **Use Case**: Request tracking, transaction management

299

300

## Performance Considerations

301

302

- **Compilation vs. Runtime**: For better performance, compile aspects with `ajc` and use them as binary dependencies rather than relying on load-time weaving

303

- **Reflection Overhead**: The `Aspects` class uses reflection internally, so direct aspect access (when available) is more efficient

304

- **Instance Checking**: Use `hasAspect()` before `aspectOf()` to avoid exceptions in conditional access scenarios

305

- **Thread Safety**: Singleton aspects should be thread-safe; per-object aspects are naturally isolated