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

programmatic-weaving.mddocs/

Programmatic Weaving

The AspectJ Weaver provides programmatic APIs for embedding aspect weaving capabilities directly into applications. This allows developers to weave classes on-demand or integrate weaving into custom class loading mechanisms.

Core Weaving Classes

WeavingAdaptor

Main adaptor for embedding AspectJ weaving capabilities.

public class WeavingAdaptor {
    public WeavingAdaptor(WeavingClassLoader loader);
    public WeavingAdaptor(GeneratedClassHandler handler, URL[] classURLs, URL[] aspectURLs);
    public void addURL(URL url);
    public byte[] weaveClass(String name, byte[] bytes) throws IOException;
    public byte[] weaveClass(String name, byte[] bytes, boolean mustWeave) throws IOException;
    public IMessageHolder getMessageHolder();
    public String getContextId();
}

Constructors

public WeavingAdaptor(WeavingClassLoader loader)

Creates a weaving adaptor with a weaving class loader.

Parameters:

  • loader - Class loader implementing WeavingClassLoader interface
public WeavingAdaptor(GeneratedClassHandler handler, URL[] classURLs, URL[] aspectURLs)

Creates a weaving adaptor with explicit URLs and class handler.

Parameters:

  • handler - Handler for generated classes during weaving
  • classURLs - URLs containing classes to be woven
  • aspectURLs - URLs containing aspect definitions

Methods

public void addURL(URL url)

Adds a URL to the weaving classpath.

Parameters:

  • url - URL to add to classpath
public byte[] weaveClass(String name, byte[] bytes) throws IOException

Weaves a class using the configured aspects.

Parameters:

  • name - Fully qualified class name (e.g., "com.example.MyClass")
  • bytes - Original class bytes

Returns: Woven class bytes or original bytes if no weaving applied

Throws: IOException if weaving fails

public byte[] weaveClass(String name, byte[] bytes, boolean mustWeave) throws IOException

Weaves a class with optional forced weaving.

Parameters:

  • name - Fully qualified class name
  • bytes - Original class bytes
  • mustWeave - If true, forces weaving even if no aspects match

Returns: Woven class bytes

Throws: IOException if weaving fails

public IMessageHolder getMessageHolder()

Returns the message holder for weaving messages and warnings.

Returns: IMessageHolder instance containing weaving messages

public String getContextId()

Returns the context identifier for this weaving adaptor.

Returns: String identifier for the weaving context

ClassLoaderWeavingAdaptor

Extended weaving adaptor with classloader-specific functionality.

public class ClassLoaderWeavingAdaptor extends WeavingAdaptor {
    // Additional classloader-specific methods
}

Core Preprocessor Interface

ClassPreProcessor

Generic preprocessor interface for separating AspectJ weaving from JVMTI interfaces.

public interface ClassPreProcessor {
    void initialize();
    byte[] preProcess(String className, byte[] bytes, ClassLoader classLoader, 
        ProtectionDomain protectionDomain);
    void prepareForRedefinition(ClassLoader loader, String className);
}

initialize

Initializes the preprocessor.

void initialize()

preProcess

Preprocesses class bytes, applying weaving transformations.

byte[] preProcess(String className, byte[] bytes, ClassLoader classLoader, 
    ProtectionDomain protectionDomain)

Parameters:

  • className - Name of class being processed
  • bytes - Original class bytes
  • classLoader - ClassLoader defining the class
  • protectionDomain - Security protection domain

Returns: Processed class bytes

prepareForRedefinition

Prepares for class redefinition during hotswap scenarios.

void prepareForRedefinition(ClassLoader loader, String className)

Parameters:

  • loader - ClassLoader containing the class
  • className - Name of class being redefined

Aj

Main preprocessor implementation adapting between the preprocessor interface and AspectJ weaver.

public class Aj implements ClassPreProcessor {
    public Aj();
    public Aj(IWeavingContext context);
    public void initialize();
    public byte[] preProcess(String className, byte[] bytes, ClassLoader classLoader, 
        ProtectionDomain protectionDomain);
}

Constructors

public Aj()

Creates an Aj preprocessor with default weaving context.

public Aj(IWeavingContext context)

Creates an Aj preprocessor with custom weaving context.

Parameters:

  • context - Custom weaving context for multi-classloader environments

Usage Examples

Basic Programmatic Weaving

import org.aspectj.weaver.tools.WeavingAdaptor;
import java.io.FileInputStream;
import java.io.IOException;

public class BasicWeavingExample {
    public static void main(String[] args) throws IOException {
        // Create weaving adaptor
        WeavingAdaptor adaptor = new WeavingAdaptor(
            null, // GeneratedClassHandler
            new URL[]{new URL("file:///path/to/classes/")}, // Class URLs
            new URL[]{new URL("file:///path/to/aspects/")}  // Aspect URLs
        );
        
        // Read original class bytes
        byte[] originalBytes = readClassBytes("com.example.MyClass");
        
        // Weave the class
        byte[] wovenBytes = adaptor.weaveClass("com.example.MyClass", originalBytes);
        
        // Use the woven bytes (e.g., save to file or define class)
        saveWovenClass("com.example.MyClass", wovenBytes);
        
        // Check for weaving messages
        IMessageHolder messages = adaptor.getMessageHolder();
        if (messages.hasAnyMessage(IMessage.ERROR)) {
            System.err.println("Weaving errors occurred");
        }
    }
    
    private static byte[] readClassBytes(String className) throws IOException {
        // Implementation to read class bytes from file system
        String path = className.replace('.', '/') + ".class";
        return Files.readAllBytes(Paths.get(path));
    }
    
    private static void saveWovenClass(String className, byte[] bytes) throws IOException {
        // Implementation to save woven bytes
        String path = "woven/" + className.replace('.', '/') + ".class";
        Files.write(Paths.get(path), bytes);
    }
}

Custom Class Loading with Weaving

import org.aspectj.weaver.tools.WeavingAdaptor;

public class WeavingClassLoader extends URLClassLoader {
    private final WeavingAdaptor weavingAdaptor;
    
    public WeavingClassLoader(URL[] urls, ClassLoader parent) {
        super(urls, parent);
        this.weavingAdaptor = new WeavingAdaptor(this);
    }
    
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        try {
            // Get original class bytes
            byte[] originalBytes = getClassBytes(name);
            
            // Weave the class
            byte[] wovenBytes = weavingAdaptor.weaveClass(name, originalBytes);
            
            // Define the woven class
            return defineClass(name, wovenBytes, 0, wovenBytes.length);
            
        } catch (IOException e) {
            throw new ClassNotFoundException("Failed to weave class: " + name, e);
        }
    }
    
    private byte[] getClassBytes(String name) throws IOException {
        String resourceName = name.replace('.', '/') + ".class";
        InputStream is = getResourceAsStream(resourceName);
        if (is == null) {
            throw new IOException("Class not found: " + name);
        }
        return is.readAllBytes();
    }
}

Preprocessor Integration

import org.aspectj.weaver.loadtime.Aj;
import org.aspectj.weaver.loadtime.ClassPreProcessor;

public class CustomPreprocessorExample {
    private final ClassPreProcessor processor;
    
    public CustomPreprocessorExample() {
        this.processor = new Aj();
        processor.initialize();
    }
    
    public byte[] processClass(String className, byte[] originalBytes, 
                              ClassLoader loader) {
        return processor.preProcess(className, originalBytes, loader, null);
    }
    
    public void handleClassRedefinition(ClassLoader loader, String className) {
        processor.prepareForRedefinition(loader, className);
    }
}

Error Handling and Diagnostics

import org.aspectj.bridge.IMessage;
import org.aspectj.bridge.IMessageHolder;

public class WeavingDiagnostics {
    public static void checkWeavingResults(WeavingAdaptor adaptor) {
        IMessageHolder messages = adaptor.getMessageHolder();
        
        // Check for errors
        if (messages.hasAnyMessage(IMessage.ERROR)) {
            System.err.println("Weaving errors:");
            for (IMessage message : messages.getMessages(IMessage.ERROR, true)) {
                System.err.println("  " + message.getMessage());
            }
        }
        
        // Check for warnings
        if (messages.hasAnyMessage(IMessage.WARNING)) {
            System.out.println("Weaving warnings:");
            for (IMessage message : messages.getMessages(IMessage.WARNING, true)) {
                System.out.println("  " + message.getMessage());
            }
        }
        
        // Check for info messages
        if (messages.hasAnyMessage(IMessage.INFO)) {
            System.out.println("Weaving info:");
            for (IMessage message : messages.getMessages(IMessage.INFO, true)) {
                System.out.println("  " + message.getMessage());
            }
        }
    }
}

Configuration Options

System Properties

  • WeavingAdaptor.WEAVING_ADAPTOR_VERBOSE: Enable verbose weaving output
  • WeavingAdaptor.SHOW_WEAVE_INFO_PROPERTY: Show detailed weave information
  • WeavingAdaptor.TRACE_MESSAGES_PROPERTY: Enable message tracing

Programmatic Configuration

// Enable verbose output
System.setProperty(WeavingAdaptor.WEAVING_ADAPTOR_VERBOSE, "true");

// Create adaptor with verbose settings
WeavingAdaptor adaptor = new WeavingAdaptor(classLoader);

Performance Considerations

  1. Reuse WeavingAdaptor: Create once and reuse for multiple classes
  2. Batch Processing: Process multiple classes in a single session
  3. Caching: Use WeavedClassCache for repeated weaving operations
  4. Memory Management: Monitor memory usage during large weaving operations

Troubleshooting

Common Issues

  1. ClassNotFoundException: Ensure all required classes and aspects are on the classpath
  2. IOException during weaving: Check class format and aspect compatibility
  3. Performance degradation: Consider enabling caching for repeated operations

Debug Output

// Enable debug output
System.setProperty("org.aspectj.weaver.showWeaveInfo", "true");
System.setProperty("aj.weaving.verbose", "true");

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