javamavenaopaspectjhikaricp

AspectJ weave external dependency code, repackage jar and force dependency users to use it


Let's say I have a common multi-module maven project which modules are used as dependencies across bunch of the projects, I want to weave my Aspects into Hikari dependency classes and make this logic in the on of these common modules and make those common multi-module users to have woven Hikari jar. As I guess the following steps are required:

  1. Compile code with aspects (did that)
  2. Repackage external jar with code from 1)
  3. Somehow force all the projects having this common dependency to use this repackaged jar.

I am kind of confused of steps 2-3 possibility and didn't manage to find any reliable guides or doc references. Is it even possible in the way all the changes will be seamless for dependency users? Project to look at or play with : git-repo


Solution

  • First of all, I do believe AspectJ is not proper choice for this particular case, since you are using spring-framework you may build more elegant solution using BeanPostProcessor and datasource-proxy project, smth. like:

    public class DiagDataSourcePostProcessor implements BeanPostProcessor {
    
        @Override
        public Object postProcessAfterInitialization(@NonNull Object bean, @NonNull String beanName) throws BeansException {
            if (!(bean instanceof DataSource)) {
                return bean;
            }
    
            ProxyDataSourceBuilder builder = ProxyDataSourceBuilder.create(beanName, (DataSource) bean);
            builder.listener(new JdbcLifecycleEventListenerAdapter() {
    
                public void beforeClose(MethodExecutionContext executionContext) {
                    if (executionContext.getTarget() instanceof Connection) {
                        // some logic here
                    }
                }
    
                public void afterGetConnection(MethodExecutionContext executionContext) {
                    // some logic here
                }
    
    
            });
            return builder.build();
        }
    
    }
    
    @Bean
    public static BeanPostProcessor diagDataSourcePostProcessor() {
        return new DiagDataSourcePostProcessor();
    }
    

    As regards to your aspectj project it contains some smells which actually prevent you from achieving your goal:

    1. you should avoid defining plugins and dependencies in aggregate pom's - in your case you have turned aspectj module into "application" however that should be a "library", so, aggregate pom (demo) should look like:
    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>3.1.4</version>
            <relativePath/> <!-- lookup parent from repository -->
        </parent>
        
        <groupId>com.example</groupId>
        <artifactId>demo</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <packaging>pom</packaging>
        <name>aspectj-demo</name>
        <description>Demo project for Spring Boot</description>
    
        <properties>
            <java.version>17</java.version>
        </properties>
    
        <modules>
            <module>aspectj</module>
            <module>some-app</module>
        </modules>
    
    </project>
    
    1. since the purpose of aspectj module is to build some kind of "enhanced" version of HikariCP (in case of compile-time weaving), it should not "depend" on HikariCP from "library observer" perspective, otherwise application classpath will contain two versions of HikariCP library: "enhanced" and the original one, so, aspectj pom should look like:
    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <parent>
            <groupId>com.example</groupId>
            <artifactId>demo</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </parent>
    
        <groupId>org.example</groupId>
        <artifactId>aspectj</artifactId>
    
        <properties>
            <maven.compiler.source>17</maven.compiler.source>
            <maven.compiler.target>17</maven.compiler.target>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        </properties>
    
        <dependencies>
            <dependency>
                <groupId>org.aspectj</groupId>
                <artifactId>aspectjrt</artifactId>
                <version>1.9.20</version>
            </dependency>
            <dependency>
                <groupId>org.slf4j</groupId>
                <artifactId>slf4j-api</artifactId>
            </dependency>
            <dependency>
                <groupId>com.zaxxer</groupId>
                <artifactId>HikariCP</artifactId>
                <scope>provided</scope>
                <optional>true</optional>
            </dependency>
        </dependencies>
    
        <dependencyManagement>
            <dependencies>
                <dependency>
                    <groupId>com.zaxxer</groupId>
                    <artifactId>HikariCP</artifactId>
                    <version>5.0.1</version>
                </dependency>
            </dependencies>
        </dependencyManagement>
    
        <build>
            <plugins>
             <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>aspectj-maven-plugin</artifactId>
                <version>1.14.0</version>
                <configuration>
                    <complianceLevel>11</complianceLevel>
                    <showWeaveInfo>true</showWeaveInfo>
                    <verbose>true</verbose>
                    <Xlint>ignore</Xlint>
                    <weaveDependencies>
                        <weaveDependency>
                            <groupId>com.zaxxer</groupId>
                            <artifactId>HikariCP</artifactId>
                        </weaveDependency>
                    </weaveDependencies>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>compile</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
        </build>
    
    </project>
    
    1. and, I believe, that is clear the application module (some-app) should depend on aspectj module and do not depended on HikariCP, so, finally we get:
    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <parent>
            <groupId>com.example</groupId>
            <artifactId>demo</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </parent>
    
        <groupId>org.example</groupId>
        <artifactId>some-app</artifactId>
    
        <properties>
            <maven.compiler.source>17</maven.compiler.source>
            <maven.compiler.target>17</maven.compiler.target>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        </properties>
    
        <dependencies>
            <dependency>
                <groupId>org.example</groupId>
                <artifactId>aspectj</artifactId>
                <version>0.0.1-SNAPSHOT</version>
            </dependency>
    
            <dependency>
                <groupId>org.postgresql</groupId>
                <artifactId>postgresql</artifactId>
                <version>42.5.4</version>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-data-jpa</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <optional>true</optional>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
        </dependencies>
    
        <dependencyManagement>
            <dependencies>
                <dependency>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-data-jpa</artifactId>
                    <version>3.1.4</version>
                    <exclusions>
                        <exclusion>
                            <groupId>com.zaxxer</groupId>
                            <artifactId>HikariCP</artifactId>
                        </exclusion>
                    </exclusions>
                </dependency>
            </dependencies>
        </dependencyManagement>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                    <configuration>
                        <excludes>
                            <exclude>
                                <groupId>org.projectlombok</groupId>
                                <artifactId>lombok</artifactId>
                            </exclude>
                        </excludes>
                    </configuration>
                </plugin>
            </plugins>
        </build>
    
    </project>
    

    Unfortunately, the configuration above is unreliable, the problem is it does work within maven context but there is no chance it will work smoothly in IDE.