The AspectJ weaver applies aspects to Java classes and can be used as a Java agent for load-time weaving (LTW).
—
The AspectJ weaver provides comprehensive support for complex classloader hierarchies, OSGi environments, and multi-module applications. The weaving context system allows customization of class loading behavior and resource resolution for different deployment scenarios.
Interface for supporting AspectJ in OSGi and multi-classloader environments.
public interface IWeavingContext {
Enumeration<URL> getResources(String name) throws IOException;
String getBundleIdFromURL(URL url);
String getClassLoaderName();
ClassLoader getClassLoader();
String getFile(URL url);
String getId();
boolean isLocallyDefined(String classname);
List<Definition> getDefinitions(ClassLoader loader, WeavingAdaptor adaptor);
}Retrieves resources with the given name from the context.
Enumeration<URL> getResources(String name) throws IOExceptionParameters:
name - Resource name to search forReturns: Enumeration of URLs for matching resources
Throws: IOException if resource lookup fails
Returns the bundle ID for a given URL (deprecated, OSGi-specific).
String getBundleIdFromURL(URL url)Parameters:
url - URL to get bundle ID forReturns: Bundle identifier string
Deprecated: This method is deprecated in favor of more generic approaches
Returns a descriptive name for the classloader.
String getClassLoaderName()Returns: Human-readable name for the classloader
Returns the classloader associated with this context.
ClassLoader getClassLoader()Returns: ClassLoader instance for this context
Returns the file path for a given URL.
String getFile(URL url)Parameters:
url - URL to convert to file pathReturns: File path string
Returns a unique identifier for this weaving context.
String getId()Returns: Unique context identifier
Checks if a class is locally defined in this context.
boolean isLocallyDefined(String classname)Parameters:
classname - Fully qualified class nameReturns: True if class is defined locally in this context
Returns weaving definitions for the given classloader and adaptor.
List<Definition> getDefinitions(ClassLoader loader, WeavingAdaptor adaptor)Parameters:
loader - ClassLoader to get definitions foradaptor - WeavingAdaptor instanceReturns: List of Definition objects containing weaving configuration
Default implementation of IWeavingContext.
public class DefaultWeavingContext implements IWeavingContext {
public DefaultWeavingContext(ClassLoader loader);
// Implements all IWeavingContext methods
}public DefaultWeavingContext(ClassLoader loader)Creates a default weaving context for the specified classloader.
Parameters:
loader - ClassLoader to create context forURLClassLoader implementation with integrated weaving capabilities.
public class WeavingURLClassLoader extends URLClassLoader implements WeavingClassLoader {
public WeavingURLClassLoader(URL[] urls, ClassLoader parent);
public WeavingURLClassLoader(URL[] urls, ClassLoader parent, URLStreamHandlerFactory factory);
// Additional weaving-specific methods
}public WeavingURLClassLoader(URL[] urls, ClassLoader parent)Creates a weaving classloader with the specified URLs and parent.
Parameters:
urls - Array of URLs to load classes fromparent - Parent classloaderpublic WeavingURLClassLoader(URL[] urls, ClassLoader parent, URLStreamHandlerFactory factory)Creates a weaving classloader with URLs, parent, and URL stream handler factory.
Parameters:
urls - Array of URLs to load classes fromparent - Parent classloaderfactory - URLStreamHandlerFactory for custom protocol handlingConfiguration options for load-time weaving.
public class Options {
// Configuration methods and constants for weaving options
}Default message handler for weaving operations.
public class DefaultMessageHandler implements IMessageHandler {
public DefaultMessageHandler();
// Message handling implementation
}public DefaultMessageHandler()Creates a default message handler for weaving messages.
import org.aspectj.weaver.loadtime.IWeavingContext;
import org.aspectj.weaver.loadtime.Aj;
public class CustomWeavingContext implements IWeavingContext {
private final ClassLoader classLoader;
private final String contextId;
public CustomWeavingContext(ClassLoader loader, String id) {
this.classLoader = loader;
this.contextId = id;
}
@Override
public Enumeration<URL> getResources(String name) throws IOException {
// Custom resource resolution logic
return classLoader.getResources(name);
}
@Override
public String getClassLoaderName() {
return classLoader.getClass().getSimpleName() + "@" + System.identityHashCode(classLoader);
}
@Override
public ClassLoader getClassLoader() {
return classLoader;
}
@Override
public String getId() {
return contextId;
}
@Override
public boolean isLocallyDefined(String classname) {
// Check if class is defined in this specific classloader
try {
Class<?> clazz = classLoader.loadClass(classname);
return clazz.getClassLoader() == classLoader;
} catch (ClassNotFoundException e) {
return false;
}
}
@Override
public List<Definition> getDefinitions(ClassLoader loader, WeavingAdaptor adaptor) {
// Return weaving definitions for this context
return Collections.emptyList();
}
@Override
public String getFile(URL url) {
return url.getFile();
}
@Override
public String getBundleIdFromURL(URL url) {
// Legacy method, return null for non-OSGi environments
return null;
}
}
// Usage
public class CustomWeavingExample {
public static void setupCustomWeaving() {
ClassLoader loader = Thread.currentThread().getContextClassLoader();
IWeavingContext context = new CustomWeavingContext(loader, "custom-context");
// Create Aj processor with custom context
Aj processor = new Aj(context);
processor.initialize();
// Use processor for weaving
byte[] originalBytes = getClassBytes("com.example.MyClass");
byte[] wovenBytes = processor.preProcess("com.example.MyClass",
originalBytes, loader, null);
}
private static byte[] getClassBytes(String className) {
// Implementation to get class bytes
return new byte[0];
}
}import org.aspectj.weaver.tools.WeavingAdaptor;
import org.aspectj.weaver.loadtime.WeavingURLClassLoader;
public class MultiClassLoaderExample {
public static void setupMultiClassLoaderWeaving() {
// Create parent classloader
ClassLoader parentLoader = Thread.currentThread().getContextClassLoader();
// Create weaving classloaders for different modules
URL[] moduleAUrls = {getModuleAUrl()};
URL[] moduleBUrls = {getModuleBUrl()};
WeavingURLClassLoader moduleALoader = new WeavingURLClassLoader(moduleAUrls, parentLoader);
WeavingURLClassLoader moduleBLoader = new WeavingURLClassLoader(moduleBUrls, parentLoader);
// Create separate weaving adaptors for each module
WeavingAdaptor adaptorA = new WeavingAdaptor(moduleALoader);
WeavingAdaptor adaptorB = new WeavingAdaptor(moduleBLoader);
// Load and weave classes from different modules
loadAndWeaveClass(adaptorA, moduleALoader, "com.modulea.ClassA");
loadAndWeaveClass(adaptorB, moduleBLoader, "com.moduleb.ClassB");
}
private static void loadAndWeaveClass(WeavingAdaptor adaptor, ClassLoader loader, String className) {
try {
// Load original class bytes
byte[] originalBytes = getClassBytesFromLoader(loader, className);
// Weave the class
byte[] wovenBytes = adaptor.weaveClass(className, originalBytes);
// Define the class in the appropriate classloader
Class<?> wovenClass = defineClass(loader, className, wovenBytes);
System.out.println("Successfully wove class: " + wovenClass.getName());
} catch (Exception e) {
System.err.println("Failed to weave class " + className + ": " + e.getMessage());
}
}
private static URL getModuleAUrl() {
// Return URL for module A classes
return null;
}
private static URL getModuleBUrl() {
// Return URL for module B classes
return null;
}
private static byte[] getClassBytesFromLoader(ClassLoader loader, String className) {
// Implementation to get class bytes from specific loader
return new byte[0];
}
private static Class<?> defineClass(ClassLoader loader, String name, byte[] bytes) {
// Implementation to define class in loader
return null;
}
}import org.aspectj.weaver.loadtime.IWeavingContext;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
public class OSGiWeavingContext implements IWeavingContext {
private final Bundle bundle;
private final BundleContext bundleContext;
public OSGiWeavingContext(Bundle bundle) {
this.bundle = bundle;
this.bundleContext = bundle.getBundleContext();
}
@Override
public Enumeration<URL> getResources(String name) throws IOException {
// Use OSGi bundle resource lookup
return bundle.getResources(name);
}
@Override
public String getBundleIdFromURL(URL url) {
// Extract bundle ID from OSGi URL
String path = url.getPath();
if (path.startsWith("/bundle")) {
String[] parts = path.split("/");
if (parts.length > 1) {
return parts[1];
}
}
return String.valueOf(bundle.getBundleId());
}
@Override
public String getClassLoaderName() {
return "OSGi Bundle: " + bundle.getSymbolicName();
}
@Override
public ClassLoader getClassLoader() {
// OSGi bundles don't expose classloaders directly
return this.getClass().getClassLoader();
}
@Override
public String getId() {
return bundle.getSymbolicName() + "_" + bundle.getVersion();
}
@Override
public boolean isLocallyDefined(String classname) {
try {
// Check if class is provided by this bundle
return bundle.loadClass(classname) != null;
} catch (ClassNotFoundException e) {
return false;
}
}
@Override
public List<Definition> getDefinitions(ClassLoader loader, WeavingAdaptor adaptor) {
// Load weaving definitions from bundle resources
List<Definition> definitions = new ArrayList<>();
try {
Enumeration<URL> aopXmlUrls = getResources("META-INF/aop.xml");
while (aopXmlUrls.hasMoreElements()) {
URL aopXmlUrl = aopXmlUrls.nextElement();
// Parse aop.xml and create Definition objects
Definition def = parseAopXml(aopXmlUrl);
definitions.add(def);
}
} catch (IOException e) {
System.err.println("Failed to load aop.xml from bundle: " + e.getMessage());
}
return definitions;
}
@Override
public String getFile(URL url) {
return url.getFile();
}
private Definition parseAopXml(URL aopXmlUrl) {
// Implementation to parse aop.xml file
return null;
}
}
// Usage in OSGi environment
public class OSGiWeavingExample {
public void setupOSGiWeaving(Bundle bundle) {
IWeavingContext context = new OSGiWeavingContext(bundle);
Aj processor = new Aj(context);
processor.initialize();
// Use processor for OSGi-aware weaving
}
}import org.aspectj.weaver.tools.cache.WeavedClassCache;
public class IsolatedWeavingExample {
public static void setupIsolatedWeaving() {
// Create isolated classloaders for different application modules
ClassLoader appLoader = createApplicationClassLoader();
ClassLoader pluginLoader1 = createPluginClassLoader("plugin1");
ClassLoader pluginLoader2 = createPluginClassLoader("plugin2");
// Create separate caches for each classloader
List<String> appAspects = Arrays.asList("com.app.LoggingAspect");
List<String> plugin1Aspects = Arrays.asList("com.plugin1.SecurityAspect");
List<String> plugin2Aspects = Arrays.asList("com.plugin2.MetricsAspect");
WeavedClassCache appCache = WeavedClassCache.createCache(appLoader, appAspects, null, null);
WeavedClassCache plugin1Cache = WeavedClassCache.createCache(pluginLoader1, plugin1Aspects, null, null);
WeavedClassCache plugin2Cache = WeavedClassCache.createCache(pluginLoader2, plugin2Aspects, null, null);
// Each cache operates independently with its own classloader scope
System.out.println("App cache: " + appCache.getName());
System.out.println("Plugin1 cache: " + plugin1Cache.getName());
System.out.println("Plugin2 cache: " + plugin2Cache.getName());
}
private static ClassLoader createApplicationClassLoader() {
URL[] urls = {getApplicationJarUrl()};
return new URLClassLoader(urls, ClassLoader.getSystemClassLoader());
}
private static ClassLoader createPluginClassLoader(String pluginName) {
URL[] urls = {getPluginJarUrl(pluginName)};
return new URLClassLoader(urls, ClassLoader.getSystemClassLoader());
}
private static URL getApplicationJarUrl() {
// Return URL for application JAR
return null;
}
private static URL getPluginJarUrl(String pluginName) {
// Return URL for plugin JAR
return null;
}
}Different classloader contexts can have different weaving configurations:
<!-- META-INF/aop.xml for Module A -->
<aspectj>
<weaver options="-verbose">
<include within="com.modulea..*"/>
</weaver>
<aspects>
<aspect name="com.modulea.LoggingAspect"/>
</aspects>
</aspectj><!-- META-INF/aop.xml for Module B -->
<aspectj>
<weaver options="-showWeaveInfo">
<include within="com.moduleb..*"/>
</weaver>
<aspects>
<aspect name="com.moduleb.SecurityAspect"/>
</aspects>
</aspectj>aj.class.path: Additional classpath for aspect resolutionorg.aspectj.weaver.loadtime.configuration: Custom configuration file locationaj.weaving.loadtime.configuration.debug: Debug configuration loading// Enable classloader debugging
System.setProperty("aj.weaving.loadtime.configuration.debug", "true");
System.setProperty("java.system.class.loader", "custom.DebuggingClassLoader");public static void printContextInfo(IWeavingContext context) {
System.out.println("Context ID: " + context.getId());
System.out.println("ClassLoader: " + context.getClassLoaderName());
System.out.println("ClassLoader instance: " + context.getClassLoader());
// Test resource resolution
try {
Enumeration<URL> resources = context.getResources("META-INF/aop.xml");
while (resources.hasMoreElements()) {
System.out.println("Found aop.xml: " + resources.nextElement());
}
} catch (IOException e) {
System.err.println("Failed to load resources: " + e.getMessage());
}
}Install with Tessl CLI
npx tessl i tessl/maven-org-aspectj--aspectjweaver