/*
* Copyright 2002-2007 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.instrument.classloading;
import java.lang.instrument.ClassFileTransformer;
import org.aspectj.weaver.loadtime.ClassPreProcessorAgentAdapter;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
/**
* Generic configurer for bean-style linking in of
* {@link java.lang.instrument.ClassFileTransformer} definitions.
*
* <p>Can for example be used to register a custom transformer
* on an InstrumentationLoadTimeWeaver:
*
* <pre>
* <bean id="loadTimeWeaver" class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver"/>
*
* <bean class="org.springframework.instrument.classloading.ClassTransformationConfigurer">
* <property name="loadTimeWeaver" ref="loadTimeWeaver"/>
* <property name="transformers">
* <bean class="mypackage.MyClassTransformer"/>
* </property>
* </bean></pre>
*
* A further common usage scenario is activating AspectJ load-time
* weaving through the built-in "registerAspectjPreProcessor" flag:
*
* <pre>
* <bean class="org.springframework.instrument.classloading.ClassTransformationConfigurer">
* <property name="loadTimeWeaver" ref="loadTimeWeaver"/>
* <property name="registerAspectjPreProcessor" value="true"/>
* </bean></pre>
*
* Of course, a LoadTimeWeaver definition like the above can be reused
* for JPA weaving, for example, linked into a
* {@link org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean}
* definition:
*
* <pre>
* <bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
* <property name="dataSource" ref="dataSource"/>
* <property name="loadTimeWeaver" ref="loadTimeWeaver"/>
* </bean></pre>
*
* @author Juergen Hoeller
* @since 2.1
* @see #setLoadTimeWeaver
* @see #setTransformers
* @see #setRegisterAspectjPreProcessor
*/
public class ClassTransformationConfigurer implements BeanFactoryPostProcessor {
private LoadTimeWeaver loadTimeWeaver;
private boolean registerAspectjPreProcessor = false;
private ClassFileTransformer[] transformers;
/**
* Set the LoadTimeWeaver to register the transformers on.
* @see InstrumentationLoadTimeWeaver
* @see ReflectiveLoadTimeWeaver
* @see org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean#setLoadTimeWeaver
*/
public void setLoadTimeWeaver(LoadTimeWeaver loadTimeWeaver) {
this.loadTimeWeaver = loadTimeWeaver;
}
/**
* Specify whether to register the AspectJ
* {@link org.aspectj.weaver.loadtime.ClassPreProcessorAgentAdapter}
* with the given LoadTimeWeaver.
* <p>Default is "false". Set this flag to "true" to activate AspectJ
* load-time weaving based on AspectJ's "META-INF/aop.xml" descriptor,
* weaving application classes with AspectJ aspects.
* <p>This is a convenience shortcut for specifying a ClassPreProcessorAgentAdapter
* instance via the generic "transformers" property. The pre-processor created
* through this flag will be registered <i>before</i> any ClassFileTransformers
* specified on the "transformers" property.
* @see org.aspectj.weaver.loadtime.ClassPreProcessorAgentAdapter
* @see #setTransformers
*/
public void setRegisterAspectjPreProcessor(boolean registerAspectjPreProcessor) {
this.registerAspectjPreProcessor = registerAspectjPreProcessor;
}
/**
* Specify custom ClassFileTransformers to register on the LoadTimeWeaver
* that this configurer operates on.
* @see #setLoadTimeWeaver
*/
public void setTransformers(ClassFileTransformer[] transformers) {
this.transformers = transformers;
}
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
if (this.loadTimeWeaver == null) {
throw new IllegalArgumentException("Property 'loadTimeWeaver' is required");
}
if (this.registerAspectjPreProcessor) {
this.loadTimeWeaver.addTransformer(AspectJPreProcessorFactory.createAspectJPreProcessor());
}
if (this.transformers != null) {
for (int i = 0; i < this.transformers.length; i++) {
this.loadTimeWeaver.addTransformer(this.transformers[i]);
}
}
}
/**
* Inner factory class used to just introduce an AspectJ dependency
* when actually registering the AspectJ pre-processor.
*/
private static class AspectJPreProcessorFactory {
public static ClassFileTransformer createAspectJPreProcessor() {
return new ClassPreProcessorAgentAdapter();
}
}
}