|
|
|
@ -1,5 +1,5 @@ |
|
|
|
/* |
|
|
|
/* |
|
|
|
* Copyright 2002-2013 the original author or authors. |
|
|
|
* Copyright 2002-2014 the original author or authors. |
|
|
|
* |
|
|
|
* |
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
|
|
* you may not use this file except in compliance with the License. |
|
|
|
* you may not use this file except in compliance with the License. |
|
|
|
@ -20,49 +20,48 @@ import java.io.ObjectStreamException; |
|
|
|
import java.io.Serializable; |
|
|
|
import java.io.Serializable; |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* An aspect that injects dependency into any object whose type implements the {@link ConfigurableObject} interface. |
|
|
|
* An aspect that injects dependency into any object whose type implements the |
|
|
|
* <p> |
|
|
|
* {@link ConfigurableObject} interface. |
|
|
|
* This aspect supports injecting into domain objects when they are created for the first time as well as |
|
|
|
* |
|
|
|
* upon deserialization. Subaspects need to simply provide definition for the configureBean() method. This |
|
|
|
* <p>This aspect supports injecting into domain objects when they are created |
|
|
|
* method may be implemented without relying on Spring container if so desired. |
|
|
|
* for the first time as well as upon deserialization. Subaspects need to simply |
|
|
|
* </p> |
|
|
|
* provide definition for the configureBean() method. This method may be |
|
|
|
* <p> |
|
|
|
* implemented without relying on Spring container if so desired. |
|
|
|
* There are two cases that needs to be handled: |
|
|
|
* |
|
|
|
|
|
|
|
* <p>There are two cases that needs to be handled: |
|
|
|
* <ol> |
|
|
|
* <ol> |
|
|
|
* <li>Normal object creation via the '{@code new}' operator: this is |
|
|
|
* <li>Normal object creation via the '{@code new}' operator: this is |
|
|
|
* taken care of by advising {@code initialization()} join points.</li> |
|
|
|
* taken care of by advising {@code initialization()} join points.</li> |
|
|
|
* <li>Object creation through deserialization: since no constructor is |
|
|
|
* <li>Object creation through deserialization: since no constructor is |
|
|
|
* invoked during deserialization, the aspect needs to advise a method that a |
|
|
|
* invoked during deserialization, the aspect needs to advise a method that a |
|
|
|
* deserialization mechanism is going to invoke. Ideally, we should not |
|
|
|
* deserialization mechanism is going to invoke. Ideally, we should not |
|
|
|
* require user classes to implement any specific method. This implies that |
|
|
|
* require user classes to implement any specific method. This implies that |
|
|
|
* we need to <i>introduce</i> the chosen method. We should also handle the cases |
|
|
|
* we need to <i>introduce</i> the chosen method. We should also handle the cases |
|
|
|
* where the chosen method is already implemented in classes (in which case, |
|
|
|
* where the chosen method is already implemented in classes (in which case, |
|
|
|
* the user's implementation for that method should take precedence over the |
|
|
|
* the user's implementation for that method should take precedence over the |
|
|
|
* introduced implementation). There are a few choices for the chosen method: |
|
|
|
* introduced implementation). There are a few choices for the chosen method: |
|
|
|
* <ul> |
|
|
|
* <ul> |
|
|
|
* <li>readObject(ObjectOutputStream): Java requires that the method must be |
|
|
|
* <li>readObject(ObjectOutputStream): Java requires that the method must be |
|
|
|
* {@code private}</p>. Since aspects cannot introduce a private member, |
|
|
|
* {@code private}</p>. Since aspects cannot introduce a private member, |
|
|
|
* while preserving its name, this option is ruled out.</li> |
|
|
|
* while preserving its name, this option is ruled out.</li> |
|
|
|
* <li>readResolve(): Java doesn't pose any restriction on an access specifier. |
|
|
|
* <li>readResolve(): Java doesn't pose any restriction on an access specifier. |
|
|
|
* Problem solved! There is one (minor) limitation of this approach in |
|
|
|
* Problem solved! There is one (minor) limitation of this approach in |
|
|
|
* that if a user class already has this method, that method must be |
|
|
|
* that if a user class already has this method, that method must be |
|
|
|
* {@code public}. However, this shouldn't be a big burden, since |
|
|
|
* {@code public}. However, this shouldn't be a big burden, since |
|
|
|
* use cases that need classes to implement readResolve() (custom enums, |
|
|
|
* use cases that need classes to implement readResolve() (custom enums, |
|
|
|
* for example) are unlikely to be marked as @Configurable, and |
|
|
|
* for example) are unlikely to be marked as @Configurable, and |
|
|
|
* in any case asking to make that method {@code public} should not |
|
|
|
* in any case asking to make that method {@code public} should not |
|
|
|
* pose any undue burden.</li> |
|
|
|
* pose any undue burden.</li> |
|
|
|
* </ul> |
|
|
|
* </ul> |
|
|
|
* The minor collaboration needed by user classes (i.e., that the |
|
|
|
* The minor collaboration needed by user classes (i.e., that the implementation of |
|
|
|
* implementation of {@code readResolve()}, if any, must be |
|
|
|
* {@code readResolve()}, if any, must be {@code public}) can be lifted as well if we |
|
|
|
* {@code public}) can be lifted as well if we were to use an |
|
|
|
* were to use an experimental feature in AspectJ - the {@code hasmethod()} PCD.</li> |
|
|
|
* experimental feature in AspectJ - the {@code hasmethod()} PCD.</li> |
|
|
|
|
|
|
|
* </ol> |
|
|
|
* </ol> |
|
|
|
|
|
|
|
* |
|
|
|
* <p> |
|
|
|
* <p>While having type implement the {@link ConfigurableObject} interface is certainly |
|
|
|
* While having type implement the {@link ConfigurableObject} interface is certainly a valid choice, an alternative |
|
|
|
* a valid choice, an alternative is to use a 'declare parents' statement another aspect |
|
|
|
* is to use a 'declare parents' statement another aspect (a subaspect of this aspect would be a logical choice) |
|
|
|
* (a subaspect of this aspect would be a logical choice) that declares the classes that |
|
|
|
* that declares the classes that need to be configured by supplying the {@link ConfigurableObject} interface. |
|
|
|
* need to be configured by supplying the {@link ConfigurableObject} interface. |
|
|
|
* </p> |
|
|
|
|
|
|
|
* |
|
|
|
* |
|
|
|
* @author Ramnivas Laddad |
|
|
|
* @author Ramnivas Laddad |
|
|
|
* @since 2.5.2 |
|
|
|
* @since 2.5.2 |
|
|
|
@ -72,35 +71,33 @@ public abstract aspect AbstractInterfaceDrivenDependencyInjectionAspect extends |
|
|
|
* Select initialization join point as object construction |
|
|
|
* Select initialization join point as object construction |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public pointcut beanConstruction(Object bean) : |
|
|
|
public pointcut beanConstruction(Object bean) : |
|
|
|
initialization(ConfigurableObject+.new(..)) && this(bean); |
|
|
|
initialization(ConfigurableObject+.new(..)) && this(bean); |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Select deserialization join point made available through ITDs for ConfigurableDeserializationSupport |
|
|
|
* Select deserialization join point made available through ITDs for ConfigurableDeserializationSupport |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public pointcut beanDeserialization(Object bean) : |
|
|
|
public pointcut beanDeserialization(Object bean) : |
|
|
|
execution(Object ConfigurableDeserializationSupport+.readResolve()) && |
|
|
|
execution(Object ConfigurableDeserializationSupport+.readResolve()) && this(bean); |
|
|
|
this(bean); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public pointcut leastSpecificSuperTypeConstruction() : initialization(ConfigurableObject.new(..)); |
|
|
|
public pointcut leastSpecificSuperTypeConstruction() : initialization(ConfigurableObject.new(..)); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Implementation to support re-injecting dependencies once an object is deserialized |
|
|
|
// Implementation to support re-injecting dependencies once an object is deserialized |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Declare any class implementing Serializable and ConfigurableObject as also implementing |
|
|
|
* Declare any class implementing Serializable and ConfigurableObject as also implementing |
|
|
|
* ConfigurableDeserializationSupport. This allows us to introduce the readResolve() |
|
|
|
* ConfigurableDeserializationSupport. This allows us to introduce the {@code readResolve()} |
|
|
|
* method and select it with the beanDeserialization() pointcut. |
|
|
|
* method and select it with the beanDeserialization() pointcut. |
|
|
|
* |
|
|
|
|
|
|
|
* <p>Here is an improved version that uses the hasmethod() pointcut and lifts |
|
|
|
* <p>Here is an improved version that uses the hasmethod() pointcut and lifts |
|
|
|
* even the minor requirement on user classes: |
|
|
|
* even the minor requirement on user classes: |
|
|
|
* |
|
|
|
* <pre class="code"> |
|
|
|
* <pre class="code">declare parents: ConfigurableObject+ Serializable+ |
|
|
|
* declare parents: ConfigurableObject+ Serializable+ |
|
|
|
* && !hasmethod(Object readResolve() throws ObjectStreamException) |
|
|
|
* && !hasmethod(Object readResolve() throws ObjectStreamException) |
|
|
|
* implements ConfigurableDeserializationSupport; |
|
|
|
* implements ConfigurableDeserializationSupport; |
|
|
|
* </pre> |
|
|
|
* </pre> |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
declare parents: |
|
|
|
declare parents: ConfigurableObject+ && Serializable+ implements ConfigurableDeserializationSupport; |
|
|
|
ConfigurableObject+ && Serializable+ implements ConfigurableDeserializationSupport; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* A marker interface to which the {@code readResolve()} is introduced. |
|
|
|
* A marker interface to which the {@code readResolve()} is introduced. |
|
|
|
@ -111,7 +108,6 @@ public abstract aspect AbstractInterfaceDrivenDependencyInjectionAspect extends |
|
|
|
/** |
|
|
|
/** |
|
|
|
* Introduce the {@code readResolve()} method so that we can advise its |
|
|
|
* Introduce the {@code readResolve()} method so that we can advise its |
|
|
|
* execution to configure the object. |
|
|
|
* execution to configure the object. |
|
|
|
* |
|
|
|
|
|
|
|
* <p>Note if a method with the same signature already exists in a |
|
|
|
* <p>Note if a method with the same signature already exists in a |
|
|
|
* {@code Serializable} class of ConfigurableObject type, |
|
|
|
* {@code Serializable} class of ConfigurableObject type, |
|
|
|
* that implementation will take precedence (a good thing, since we are |
|
|
|
* that implementation will take precedence (a good thing, since we are |
|
|
|
|