Skip to content

Commit

Permalink
Polishing
Browse files Browse the repository at this point in the history
  • Loading branch information
jhoeller committed Jul 29, 2014
1 parent 7bc9660 commit 8f484d3
Show file tree
Hide file tree
Showing 14 changed files with 217 additions and 221 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,7 @@ class TestSourceSetDependenciesPlugin implements Plugin<Project> {
}
}

private void collectProjectDependencies(Set<ProjectDependency> projectDependencies,
Project project) {
private void collectProjectDependencies(Set<ProjectDependency> projectDependencies, Project project) {
for (def configurationName in ["compile", "optional", "provided", "testCompile"]) {
Configuration configuration = project.getConfigurations().findByName(configurationName)
if (configuration) {
Expand Down
Original file line number Diff line number Diff line change
@@ -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");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -27,20 +27,26 @@ import org.aspectj.lang.annotation.control.CodeGenerationHint;
* @since 2.5.2
*/
public abstract aspect AbstractDependencyInjectionAspect {
/**
* Select construction join points for objects to inject dependencies
*/
public abstract pointcut beanConstruction(Object bean);

private pointcut preConstructionCondition() :
leastSpecificSuperTypeConstruction() && preConstructionConfiguration();

private pointcut postConstructionCondition() :
mostSpecificSubTypeConstruction() && !preConstructionConfiguration();

/**
* Select deserialization join points for objects to inject dependencies
* Select least specific super type that is marked for DI
* (so that injection occurs only once with pre-construction injection).
*/
public abstract pointcut beanDeserialization(Object bean);
public abstract pointcut leastSpecificSuperTypeConstruction();

/**
* Select join points in a configurable bean
* Select the most-specific initialization join point
* (most concrete class) for the initialization of an instance.
*/
public abstract pointcut inConfigurableBean();
@CodeGenerationHint(ifNameSuffix="6f1")
public pointcut mostSpecificSubTypeConstruction() :
if (thisJoinPoint.getSignature().getDeclaringType() == thisJoinPoint.getThis().getClass());

/**
* Select join points in beans to be configured prior to construction?
Expand All @@ -49,29 +55,20 @@ public abstract aspect AbstractDependencyInjectionAspect {
public pointcut preConstructionConfiguration() : if (false);

/**
* Select the most-specific initialization join point
* (most concrete class) for the initialization of an instance.
* Select construction join points for objects to inject dependencies.
*/
@CodeGenerationHint(ifNameSuffix="6f1")
public pointcut mostSpecificSubTypeConstruction() :
if (thisJoinPoint.getSignature().getDeclaringType() == thisJoinPoint.getThis().getClass());
public abstract pointcut beanConstruction(Object bean);

/**
* Select least specific super type that is marked for DI (so that injection occurs only once with pre-construction inejection
* Select deserialization join points for objects to inject dependencies.
*/
public abstract pointcut leastSpecificSuperTypeConstruction();
public abstract pointcut beanDeserialization(Object bean);

/**
* Configure the bean
* Select join points in a configurable bean.
*/
public abstract void configureBean(Object bean);


private pointcut preConstructionCondition() :
leastSpecificSuperTypeConstruction() && preConstructionConfiguration();
public abstract pointcut inConfigurableBean();

private pointcut postConstructionCondition() :
mostSpecificSubTypeConstruction() && !preConstructionConfiguration();

/**
* Pre-construction configuration.
Expand Down Expand Up @@ -100,4 +97,10 @@ public abstract aspect AbstractDependencyInjectionAspect {
configureBean(bean);
}


/**
* Configure the given bean.
*/
public abstract void configureBean(Object bean);

}
Original file line number Diff line number Diff line change
@@ -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");
* you may not use this file except in compliance with the License.
Expand All @@ -20,49 +20,48 @@ import java.io.ObjectStreamException;
import java.io.Serializable;

/**
* An aspect that injects dependency into any object whose type implements the {@link ConfigurableObject} interface.
* <p>
* 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.
* </p>
* <p>
* There are two cases that needs to be handled:
* An aspect that injects dependency into any object whose type implements the
* {@link ConfigurableObject} interface.
*
* <p>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.
*
* <p>There are two cases that needs to be handled:
* <ol>
* <li>Normal object creation via the '{@code new}' operator: this is
* taken care of by advising {@code initialization()} join points.</li>
* <li>Object creation through deserialization: since no constructor is
* invoked during deserialization, the aspect needs to advise a method that a
* deserialization mechanism is going to invoke. Ideally, we should not
* 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
* where the chosen method is already implemented in classes (in which case,
* the user's implementation for that method should take precedence over the
* introduced implementation). There are a few choices for the chosen method:
* <ul>
* <li>readObject(ObjectOutputStream): Java requires that the method must be
* {@code private}</p>. Since aspects cannot introduce a private member,
* while preserving its name, this option is ruled out.</li>
* <li>readResolve(): Java doesn't pose any restriction on an access specifier.
* Problem solved! There is one (minor) limitation of this approach in
* that if a user class already has this method, that method must be
* {@code 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 &#64;Configurable, and
* in any case asking to make that method {@code public} should not
* pose any undue burden.</li>
* </ul>
* The minor collaboration needed by user classes (i.e., that the
* implementation of {@code readResolve()}, if any, must be
* {@code public}) can be lifted as well if we were to use an
* experimental feature in AspectJ - the {@code hasmethod()} PCD.</li>
* <li>Normal object creation via the '{@code new}' operator: this is
* taken care of by advising {@code initialization()} join points.</li>
* <li>Object creation through deserialization: since no constructor is
* invoked during deserialization, the aspect needs to advise a method that a
* deserialization mechanism is going to invoke. Ideally, we should not
* 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
* where the chosen method is already implemented in classes (in which case,
* the user's implementation for that method should take precedence over the
* introduced implementation). There are a few choices for the chosen method:
* <ul>
* <li>readObject(ObjectOutputStream): Java requires that the method must be
* {@code private}</p>. Since aspects cannot introduce a private member,
* while preserving its name, this option is ruled out.</li>
* <li>readResolve(): Java doesn't pose any restriction on an access specifier.
* Problem solved! There is one (minor) limitation of this approach in
* that if a user class already has this method, that method must be
* {@code 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 &#64;Configurable, and
* in any case asking to make that method {@code public} should not
* pose any undue burden.</li>
* </ul>
* The minor collaboration needed by user classes (i.e., that the implementation of
* {@code readResolve()}, if any, must be {@code public}) can be lifted as well if we
* were to use an experimental feature in AspectJ - the {@code hasmethod()} PCD.</li>
* </ol>
* <p>
* 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.
* </p>
*
* <p>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
Expand All @@ -72,35 +71,33 @@ public abstract aspect AbstractInterfaceDrivenDependencyInjectionAspect extends
* Select initialization join point as object construction
*/
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
*/
public pointcut beanDeserialization(Object bean) :
execution(Object ConfigurableDeserializationSupport+.readResolve()) &&
this(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()
* ConfigurableDeserializationSupport. This allows us to introduce the {@code readResolve()}
* method and select it with the beanDeserialization() pointcut.
*
* <p>Here is an improved version that uses the hasmethod() pointcut and lifts
* even the minor requirement on user classes:
*
* <pre class="code">declare parents: ConfigurableObject+ Serializable+
* && !hasmethod(Object readResolve() throws ObjectStreamException)
* implements ConfigurableDeserializationSupport;
* <pre class="code">
* declare parents: ConfigurableObject+ Serializable+
* && !hasmethod(Object readResolve() throws ObjectStreamException)
* implements ConfigurableDeserializationSupport;
* </pre>
*/
declare parents:
ConfigurableObject+ && Serializable+ implements ConfigurableDeserializationSupport;
declare parents: ConfigurableObject+ && Serializable+ implements ConfigurableDeserializationSupport;

/**
* A marker interface to which the {@code readResolve()} is introduced.
Expand All @@ -111,7 +108,6 @@ public abstract aspect AbstractInterfaceDrivenDependencyInjectionAspect extends
/**
* Introduce the {@code readResolve()} method so that we can advise its
* execution to configure the object.
*
* <p>Note if a method with the same signature already exists in a
* {@code Serializable} class of ConfigurableObject type,
* that implementation will take precedence (a good thing, since we are
Expand Down
Original file line number Diff line number Diff line change
@@ -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");
* you may not use this file except in compliance with the License.
Expand All @@ -19,7 +19,7 @@ package org.springframework.beans.factory.aspectj;
import java.io.Serializable;

import org.aspectj.lang.annotation.control.CodeGenerationHint;
import org.springframework.beans.BeansException;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.DisposableBean;
Expand All @@ -44,48 +44,47 @@ import org.springframework.beans.factory.wiring.BeanConfigurerSupport;
* @see org.springframework.beans.factory.annotation.Configurable
* @see org.springframework.beans.factory.annotation.AnnotationBeanWiringInfoResolver
*/
public aspect AnnotationBeanConfigurerAspect
extends AbstractInterfaceDrivenDependencyInjectionAspect
public aspect AnnotationBeanConfigurerAspect extends AbstractInterfaceDrivenDependencyInjectionAspect
implements BeanFactoryAware, InitializingBean, DisposableBean {

private BeanConfigurerSupport beanConfigurerSupport = new BeanConfigurerSupport();

public pointcut inConfigurableBean() : @this(Configurable);

public pointcut preConstructionConfiguration() : preConstructionConfigurationSupport(*);

declare parents: @Configurable * implements ConfigurableObject;

public void configureBean(Object bean) {
beanConfigurerSupport.configureBean(bean);
public void setBeanFactory(BeanFactory beanFactory) {
this.beanConfigurerSupport.setBeanFactory(beanFactory);
this.beanConfigurerSupport.setBeanWiringInfoResolver(new AnnotationBeanWiringInfoResolver());
}


public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
beanConfigurerSupport.setBeanFactory(beanFactory);
beanConfigurerSupport.setBeanWiringInfoResolver(new AnnotationBeanWiringInfoResolver());
public void afterPropertiesSet() throws Exception {
this.beanConfigurerSupport.afterPropertiesSet();
}

public void afterPropertiesSet() throws Exception {
beanConfigurerSupport.afterPropertiesSet();
public void configureBean(Object bean) {
this.beanConfigurerSupport.configureBean(bean);
}

public void destroy() throws Exception {
beanConfigurerSupport.destroy();
this.beanConfigurerSupport.destroy();
}


public pointcut inConfigurableBean() : @this(Configurable);

public pointcut preConstructionConfiguration() : preConstructionConfigurationSupport(*);

/*
* An intermediary to match preConstructionConfiguration signature (that doesn't expose the annotation object)
*/
@CodeGenerationHint(ifNameSuffix="bb0")
private pointcut preConstructionConfigurationSupport(Configurable c) : @this(c) && if (c.preConstruction());


declare parents: @Configurable * implements ConfigurableObject;

/*
* This declaration shouldn't be needed,
* except for an AspectJ bug (https://bugs.eclipse.org/bugs/show_bug.cgi?id=214559)
*/
declare parents: @Configurable Serializable+
implements ConfigurableDeserializationSupport;
declare parents: @Configurable Serializable+ implements ConfigurableDeserializationSupport;

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2014 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.
Expand Down Expand Up @@ -62,6 +62,7 @@ public final class Property {

private Annotation[] annotations;


public Property(Class<?> objectType, Method readMethod, Method writeMethod) {
this(objectType, readMethod, writeMethod, null);
}
Expand Down Expand Up @@ -241,34 +242,25 @@ private Class<?> declaringClass() {
}
}

@Override
public int hashCode() {
final int prime = 31;
int hashCode = 1;
hashCode = prime * hashCode + ObjectUtils.nullSafeHashCode(this.objectType);
hashCode = prime * hashCode + ObjectUtils.nullSafeHashCode(this.readMethod);
hashCode = prime * hashCode + ObjectUtils.nullSafeHashCode(this.writeMethod);
hashCode = prime * hashCode + ObjectUtils.nullSafeHashCode(this.name);
return hashCode;
}

@Override
public boolean equals(Object obj) {
if (this == obj) {
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
if (!(other instanceof Property)) {
return false;
}
Property other = (Property) obj;
boolean equals = true;
equals &= ObjectUtils.nullSafeEquals(this.objectType, other.objectType);
equals &= ObjectUtils.nullSafeEquals(this.readMethod, other.readMethod);
equals &= ObjectUtils.nullSafeEquals(this.writeMethod, other.writeMethod);
equals &= ObjectUtils.nullSafeEquals(this.name, other.name);
return equals;
Property otherProperty = (Property) other;
return (ObjectUtils.nullSafeEquals(this.objectType, otherProperty.objectType) &&
ObjectUtils.nullSafeEquals(this.name, otherProperty.name) &&
ObjectUtils.nullSafeEquals(this.readMethod, otherProperty.readMethod) &&
ObjectUtils.nullSafeEquals(this.writeMethod, otherProperty.writeMethod));
}

@Override
public int hashCode() {
return (ObjectUtils.nullSafeHashCode(this.objectType) * 31 + ObjectUtils.nullSafeHashCode(this.name));
}

}
Loading

0 comments on commit 8f484d3

Please sign in to comment.