CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-aspectj--aspectjweaver

The AspectJ weaver applies aspects to Java classes and can be used as a Java agent for load-time weaving (LTW).

Pending
Overview
Eval results
Files

multi-classloader.mddocs/

Multi-Classloader Support

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.

Core Context Interfaces

IWeavingContext

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);
}

getResources

Retrieves resources with the given name from the context.

Enumeration<URL> getResources(String name) throws IOException

Parameters:

  • name - Resource name to search for

Returns: Enumeration of URLs for matching resources

Throws: IOException if resource lookup fails

getBundleIdFromURL

Returns the bundle ID for a given URL (deprecated, OSGi-specific).

String getBundleIdFromURL(URL url)

Parameters:

  • url - URL to get bundle ID for

Returns: Bundle identifier string

Deprecated: This method is deprecated in favor of more generic approaches

getClassLoaderName

Returns a descriptive name for the classloader.

String getClassLoaderName()

Returns: Human-readable name for the classloader

getClassLoader

Returns the classloader associated with this context.

ClassLoader getClassLoader()

Returns: ClassLoader instance for this context

getFile

Returns the file path for a given URL.

String getFile(URL url)

Parameters:

  • url - URL to convert to file path

Returns: File path string

getId

Returns a unique identifier for this weaving context.

String getId()

Returns: Unique context identifier

isLocallyDefined

Checks if a class is locally defined in this context.

boolean isLocallyDefined(String classname)

Parameters:

  • classname - Fully qualified class name

Returns: True if class is defined locally in this context

getDefinitions

Returns weaving definitions for the given classloader and adaptor.

List<Definition> getDefinitions(ClassLoader loader, WeavingAdaptor adaptor)

Parameters:

  • loader - ClassLoader to get definitions for
  • adaptor - WeavingAdaptor instance

Returns: List of Definition objects containing weaving configuration

DefaultWeavingContext

Default implementation of IWeavingContext.

public class DefaultWeavingContext implements IWeavingContext {
    public DefaultWeavingContext(ClassLoader loader);
    // Implements all IWeavingContext methods
}

Constructor

public DefaultWeavingContext(ClassLoader loader)

Creates a default weaving context for the specified classloader.

Parameters:

  • loader - ClassLoader to create context for

Specialized ClassLoaders

WeavingURLClassLoader

URLClassLoader 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
}

Constructors

public WeavingURLClassLoader(URL[] urls, ClassLoader parent)

Creates a weaving classloader with the specified URLs and parent.

Parameters:

  • urls - Array of URLs to load classes from
  • parent - Parent classloader
public 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 from
  • parent - Parent classloader
  • factory - URLStreamHandlerFactory for custom protocol handling

Configuration and Options

Options

Configuration options for load-time weaving.

public class Options {
    // Configuration methods and constants for weaving options
}

DefaultMessageHandler

Default message handler for weaving operations.

public class DefaultMessageHandler implements IMessageHandler {
    public DefaultMessageHandler();
    // Message handling implementation
}

Constructor

public DefaultMessageHandler()

Creates a default message handler for weaving messages.

Usage Examples

Custom Weaving Context

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];
    }
}

Multi-ClassLoader Environment

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;
    }
}

OSGi Environment Support

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
    }
}

Class Loading Isolation

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;
    }
}

Configuration

Context-Specific Configuration

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>

System Properties

  • aj.class.path: Additional classpath for aspect resolution
  • org.aspectj.weaver.loadtime.configuration: Custom configuration file location
  • aj.weaving.loadtime.configuration.debug: Debug configuration loading

Best Practices

  1. Context Isolation: Use separate weaving contexts for different modules
  2. Resource Management: Properly clean up classloaders and contexts
  3. Cache Scoping: Use appropriate cache scoping for classloader hierarchies
  4. Configuration Management: Keep weaving configuration close to the code it affects

Troubleshooting

Common Issues

  1. ClassNotFoundException: Check classloader hierarchy and resource visibility
  2. Aspect Not Applied: Verify aspect is visible from the target class's classloader
  3. Memory Leaks: Ensure proper cleanup of custom classloaders and contexts

Debug Output

// Enable classloader debugging
System.setProperty("aj.weaving.loadtime.configuration.debug", "true");
System.setProperty("java.system.class.loader", "custom.DebuggingClassLoader");

Context Information

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

docs

caching.md

index.md

java-agent.md

multi-classloader.md

programmatic-weaving.md

tile.json