/* * Copyright 2002-2008 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.beans.factory.aspectj; import java.io.ObjectStreamException; import java.io.Serializable; /** * An aspect that injects dependency into any object whose type implements the {@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 * method may be implemented without relying on Spring container if so desired. *
** There are two cases that needs to be handled: *
new
' operator: this is
* taken care of by advising initialization()
join points.private. Since aspects cannot introduce a private member,
* while preserving its name, this option is ruled out.
public
. However, this shouldn't be a big burden, since
* use cases that need classes to implement readResolve() (custom enums,
* for example) are unlikely to be marked as @Configurable, and
* in any case asking to make that method public
should not
* pose any undue burden.readResolve()
, if any, must be
* public
) can be lifted as well if we were to use an
* experimental feature in AspectJ - the hasmethod()
PCD.* While having type implement the {@link ConfigurableObject} interface is certainly a valid choice, an alternative * is to use a 'declare parents' statement another aspect (a subaspect of this aspect would be a logical choice) * that declares the classes that need to be configured by supplying the {@link ConfigurableObject} interface. *
* * @author Ramnivas Laddad * @since 2.5.2 */ public abstract aspect AbstractInterfaceDrivenDependencyInjectionAspect extends AbstractDependencyInjectionAspect { /** * Select initialization join point as object construction */ public pointcut beanConstruction(Object bean) : initialization(ConfigurableObject+.new(..)) && this(bean); /** * Select deserialization join point made available through ITDs for ConfigurableDeserializationSupport */ public pointcut beanDeserialization(Object bean) : execution(Object ConfigurableDeserializationSupport+.readResolve()) && this(bean); public pointcut leastSpecificSuperTypeConstruction() : initialization(ConfigurableObject.new(..)); // Implementation to support re-injecting dependencies once an object is deserialized /** * Declare any class implementing Serializable and ConfigurableObject as also implementing * ConfigurableDeserializationSupport. This allows us to introduce the readResolve() * method and select it with the beanDeserialization() pointcut. * *Here is an improved version that uses the hasmethod() pointcut and lifts * even the minor requirement on user classes: * *
declare parents: ConfigurableObject+ Serializable+ * && !hasmethod(Object readResolve() throws ObjectStreamException) * implements ConfigurableDeserializationSupport; **/ declare parents: ConfigurableObject+ && Serializable+ implements ConfigurableDeserializationSupport; /** * A marker interface to which the
readResolve()
is introduced.
*/
static interface ConfigurableDeserializationSupport extends Serializable {
}
/**
* Introduce the readResolve()
method so that we can advise its
* execution to configure the object.
*
* Note if a method with the same signature already exists in a
* Serializable
class of ConfigurableObject type,
* that implementation will take precedence (a good thing, since we are
* merely interested in an opportunity to detect deserialization.)
*/
public Object ConfigurableDeserializationSupport.readResolve() throws ObjectStreamException {
return this;
}
}