Write a @DeclareParents declaration and explain each of its attributes (value, defaultImpl) and the field type.
answer
- field type = interface introduced
- value = AspectJ TYPE pattern (not method)
- '+' = include subtypes
- defaultImpl = concrete impl class
- pair with this(mixin) to bind in advice
basics
~10 sPut @DeclareParents on a field in an @Aspect. The field's type is the interface to introduce, value is an AspectJ pattern for target beans (e.g. "com.example.service.*+"), and defaultImpl is the class implementing that interface.
solid answer
~40 s@DeclareParents lives on a field declared inside an @Aspect class. Three things carry meaning: (1) the field's declared type is the interface Spring adds to the matched beans; (2) the value attribute is an AspectJ type-matching expression selecting which types receive the interface — the trailing + matches subtypes; (3) defaultImpl is the concrete class supplying the methods. At runtime Spring makes the proxy implement that interface, delegating its methods to a defaultImpl instance. To combine it with advice, you often pair it with a this() pointcut that binds the introduced interface, e.g. this(usageTracked), so advice can call the mixin methods. The field itself is just a declaration hook — its value is irrelevant; only its type matters.
code
java · 15 lines@Aspect
@Component
public class UsageTrackingAspect {
@DeclareParents(
value = "com.example.service.*+", // target TYPE pattern (+ = subtypes)
defaultImpl = DefaultUsageTracked.class) // concrete implementation
public static UsageTracked mixin; // field TYPE = introduced interface
// Bind the proxy-as-interface so advice can drive the mixin
@Before("execution(* com.example.service.*.*(..)) && this(usageTracked)")
public void recordUsage(UsageTracked usageTracked) {
usageTracked.incrementUseCount();
}
}go deeper
Recognize the annotation and that it names an interface to add.
Correctly map each part: field type, value pattern, defaultImpl; know value is a type pattern.
Also wire it to advice via this() binding and explain subtype matching with +.
Discuss maintainability of type patterns and how introductions interact with proxy creation across a module.
The **anatomy of a `@DeclareParents` declaration** has three load-bearing parts, and it is a common interview trap to confuse them. ```java @Aspect @Component public class UsageTrackingAspect { @DeclareParents( value = "com.example.service.*+", defaultImpl = DefaultUsageTracked.class) public static UsageTracked mixin; } ``` **1. The field's declared type (`UsageTracked`)** — this is the **interface being introduced**. Spring reads the field's *type*, not its value; the field is never actually assigned or used as data. People sometimes make it `static` to signal that. The point is purely to name the interface. **2. `value` — the AspectJ type pattern.** This selects *which types* gain the interface. `"com.example.service.*+"` means "any type directly in package `com.example.service`, plus (`+`) all subtypes." You can use fuller AspectJ type patterns here. Note this is a **type pattern**, not a method pointcut — introductions attach to types, not to individual join points. **3. `defaultImpl` — the implementation class.** This concrete class must implement the introduced interface and supply the actual method bodies. Spring instantiates it (via its no-arg constructor) to back the introduction. **Combining with advice.** Introductions become powerful when advice can call the mixin. Spring's reference example wires it with a `this()` designator that binds the proxy *as* the introduced interface: ```java @Before("execution(* com.example.service.*.*(..)) && this(usageTracked)") public void recordUsage(UsageTracked usageTracked) { usageTracked.incrementUseCount(); } ``` Here `this(usageTracked)` matches only when the proxy actually implements `UsageTracked` (which, thanks to the introduction, it now does), and binds it as the argument so the advice can update the mixin state on every business call. **Common mistakes:** - Writing a *method pointcut* into `value` (e.g. `execution(...)`) — wrong; `value` is a **type** pattern. - Forgetting the `+` and being surprised subclasses aren't matched. - Expecting the field's *value* to matter — only its *type* does. - Making `defaultImpl` an interface or an abstract class — it must be concrete and instantiable.
- Does the value attribute take a method pointcut like execution(...)?No. value is an AspectJ type-matching pattern selecting the target types (e.g. com.example.service.*+). Method pointcuts belong on the advice you pair with the introduction, not on @DeclareParents itself.
- Why is the annotated field often declared static and never read?Because only the field's declared type matters — it names the interface to introduce. The field is a declaration hook, never assigned or used as data, so static just underlines that it holds no per-instance state.
saying these in an interview costs you the question
- Putting an execution() method pointcut in the value attribute
- Thinking defaultImpl can be an interface or abstract class
- Believing the field's value (not type) is what's introduced