skip to content

What is post-compile (binary) weaving, and when would you use it instead of ordinary compile-time weaving?

level: seniorimportance: should knowfreq 30%

answer

  1. weave compiled .class/JARs, not source
  2. ajc -inpath (woven) vs -classpath (visible only)
  3. advise third-party / vendor bytecode
  4. weaveDependencies / aspectLibraries in the plugin
  5. still needs aspectjrt, no agent

basics

~20 s

Post-compile (binary) weaving runs ajc over already-compiled .class files or JARs instead of source. You use it to weave aspects into bytecode you didn't compile yourself — third-party libraries or a separately built module — via ajc's -inpath.

solid answer

~50 s

Compile-time weaving needs source: ajc compiles your .java together with the aspects and weaves in one step. Post-compile weaving, also called binary weaving, takes *already compiled* bytecode — .class files or whole JARs — and weaves aspects into it after the fact. You point ajc's -inpath at the compiled artifacts (as opposed to -sourceroots for source), and it emits woven copies. With the aspectj-maven-plugin you configure weaveDependencies or a weaveDirectories/inpath entry. The killer use case is advising code you don't own or can't recompile from source: a vendor JAR, a shaded library, or a downstream module already built by another team. It's also how you weave an aspect library that itself ships as a compiled JAR (aspectLibraries). The result is still fully static woven bytecode — no runtime agent, no proxy — with the same aspectjrt runtime dependency as CTW.

code

xml · 24 lines
xml
<!-- aspectj-maven-plugin: binary-weave a dependency's compiled bytecode -->
<plugin>
  <groupId>dev.aspectj</groupId>
  <artifactId>aspectj-maven-plugin</artifactId>
  <configuration>
    <!-- weave aspects INTO this already-compiled dependency (-inpath) -->
    <weaveDependencies>
      <weaveDependency>
        <groupId>com.vendor</groupId>
        <artifactId>legacy-lib</artifactId>
      </weaveDependency>
    </weaveDependencies>
    <!-- aspects supplied as a compiled JAR (-aspectpath) -->
    <aspectLibraries>
      <aspectLibrary>
        <groupId>com.katajob</groupId>
        <artifactId>audit-aspects</artifactId>
      </aspectLibrary>
    </aspectLibraries>
  </configuration>
  <executions>
    <execution><goals><goal>compile</goal></goals></execution>
  </executions>
</plugin>

go deeper

for a junior

Just know it weaves compiled bytecode/JARs rather than source.

for a middle

Add the third-party/no-source use case and the -inpath mechanism.

for a senior

Explain plugin config (weaveDependencies/aspectLibraries), -inpath vs -classpath, and version-brittleness gotchas.

for a principal

Reason about when to prefer binary weaving vs LTW for instrumenting artifacts you can't recompile, including support/licensing and upgrade-fragility implications.

AspectJ offers three weaving times: **compile-time**, **post-compile (binary)**, and **load-time**. This question is about the middle one. **Compile-time weaving (CTW)** compiles source with `ajc` and weaves in the same pass — you must have the `.java` for the code being advised. **Post-compile / binary weaving** decouples the two: the code is *already compiled* (by `javac` or an earlier `ajc` run) into `.class` files or JARs, and `ajc` then runs again purely as a *weaver* over that bytecode. Nothing about the source is needed — only the bytecode. The mechanics: - `ajc -inpath <jars-or-dirs>` feeds **compiled artifacts to be woven** (contrast `-sourceroots`/`-classpath`, where classpath entries are visible but NOT woven). - `-aspectpath <jar>` supplies **already-compiled aspects** to apply. - The output is woven `.class`/JAR bytecode, semantically identical to what CTW would have produced. **With the `aspectj-maven-plugin`** (groupId `dev.aspectj`, or historically `org.codehaus.mojo`) you express binary weaving through: - `<weaveDependencies>` — list Maven dependencies (by groupId/artifactId) whose compiled classes should be woven (each becomes an `-inpath` entry). - `<weaveDirectories>` — weave classes in a directory. - `<aspectLibraries>` — apply aspects packaged in an external JAR (`-aspectpath`). **When to choose it over CTW:** 1. **You lack the source** — a third-party or vendor library where you only have the JAR. CTW is impossible; binary weaving can still instrument it. 2. **Cross-module / multi-project builds** — module A is compiled independently (perhaps by another team or in another repo), and you want to weave aspects into its published bytecode without forcing a recompile of A's source. 3. **Shared aspect libraries** — the aspects live in their own compiled artifact and are applied via `-aspectpath`/`aspectLibraries`. 4. **Instrumenting test or generated bytecode** produced by tools that only emit `.class`. **Edge cases / gotchas:** - You still need `aspectjrt` at runtime; the woven vendor classes now call into it. - Weaving vendor bytecode can be brittle across upstream version bumps — pointcuts matching internal methods may silently stop matching after an upgrade, so prefer stable public signatures. - Re-weaving already-woven classes is generally avoided; AspectJ tracks weave state to prevent double-weaving. - Licensing/warranty: modifying a vendor's bytecode may have legal or support implications. - If the goal is purely *runtime* instrumentation you can't rebuild at all, **load-time weaving** (agent + `aop.xml`) may be a better fit; binary weaving still requires a build step that rewrites the artifact. **Bottom line:** binary weaving = CTW's mechanism applied to bytecode instead of source, chosen precisely when source isn't available or recompilation isn't desirable, while keeping the static, proxy-free, agent-free runtime profile.

  • What's the difference between ajc's -inpath and -classpath?
    -inpath lists compiled artifacts that ajc will actually weave into and re-emit; -classpath lists artifacts only made visible for type resolution and are NOT woven. Binary weaving hinges on putting the target on -inpath.
  • Could you achieve the same third-party instrumentation with load-time weaving instead?
    Yes — LTW weaves the vendor classes as they're loaded via the aspectjweaver agent and aop.xml, needing no rebuilt artifact, but it adds a java agent and class-load-time cost. Binary weaving bakes it into a rebuilt JAR up front with no agent.

saying these in an interview costs you the question

  • Claiming post-compile weaving needs the target's source code.
  • Confusing -inpath (woven) with -classpath (visible only).
  • Saying binary weaving uses a runtime agent like LTW does.

context