Search code examples
javahibernatejdbcaspectjaspectj-maven-plugin

Aspect which intercept all sql queries


I have a library with aspect which scan all statement executions and doing some logic with sql sentence.

@Pointcut("target(java.sql.Statement)")
public void statement() {}

@AfterReturning("!within(AnalyzerAspect) && statement() && args(sql)")
public void after(JoinPoint jp, String sql) throws Throwable {
  // some logic
}

When I use it for jdbc operations it works fine. I also used library with spring-jdbc with aspectj plugin options

            <plugin>
                <groupId>dev.aspectj</groupId>
                <artifactId>aspectj-maven-plugin</artifactId>
                <version>${aspect.compiler.plugin.version}</version>
                <configuration>
                    <weaveDependencies>
                        <weaveDependency>
                            <groupId>org.springframework</groupId>
                            <artifactId>spring-jdbc</artifactId>
                        </weaveDependency>
                        <weaveDependency>
                            <groupId>org.hibernate</groupId> 
                            <artifactId>hibernate-core</artifactId>
                        </weaveDependency>
                    </weaveDependencies>
                    <aspectLibraries>
                        <aspectLibrary>
                            <groupId>edu.ifmo.diploma</groupId> <!-- My library -->
                            <artifactId>db-analyzer</artifactId>
                        </aspectLibrary>
                    </aspectLibraries>
                    <complianceLevel>${maven.compiler.target}</complianceLevel>
                    <showWeaveInfo>true</showWeaveInfo>
                    <Xlint>ignore</Xlint>
                    <encoding>UTF-8</encoding>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>compile</goal>
                            <goal>test-compile</goal>
                        </goals>
                    </execution>
                </executions>
                <dependencies>
                    <dependency>
                        <groupId>org.aspectj</groupId>
                        <artifactId>aspectjtools</artifactId>
                        <version>${aspectj.version}</version>
                    </dependency>
                </dependencies>
            </plugin>

and query execution

jdbcTemplate.query("SELECT * FROM person", new BeanPropertyRowMapper<>(Person.class));

and aspect works correctly, but when I'm trying to use it with spring-data-jpa repository

public interface PersonRepository extends JpaRepository<Person, UUID> {

    @Query(nativeQuery = true, value = "SELECT * FROM person")
    List<Person> findAll();
}
personRepository.findAll();

my aspect doesn't intercept its execution despite hibernate weaving in my plugin.

My main goal is improve this library to it won't depends on db library and just intercept jdbc statement execution, because all of db libraries anyway use it under the hood. If you suggest me easier way than mine, I will be grateful to you.


Solution

  • I forget about checking prepared statement in my aspect, I debugged my repository call and detect that it calls preparedStatement.executeQuery().

    Now my aspect intercept statement and prepared statement execution.

        @Pointcut("target(java.sql.Statement)")
        fun statement() {
        }
    
        @Pointcut("target(java.sql.PreparedStatement)")
        fun preparedStatement() {
        }
    
        @AfterReturning("!within(AnalyzerAspect) && preparedStatement()")
        fun afterWithoutSqlArgs(jp: JoinPoint) {
            if (!jp.signature.name.startsWith("execute")) {
                return
            }
            val target = jp.target as PreparedStatement
            after(jp, target.toString())
        }
    
        @AfterReturning("!within(AnalyzerAspect) && statement() && args(sql)")
        fun after(jp: JoinPoint, sql: String) {
            //some logic
        }
    

    If u have same task to intercept all sql queries you have to put aspect above in your code and configure aspectj plugin this way

                <plugin>
                    <groupId>dev.aspectj</groupId>
                    <artifactId>aspectj-maven-plugin</artifactId>
                    <version>${aspect.compiler.plugin.version}</version>
                    <configuration>
                        <weaveDependencies>
                            <weaveDependency>
                                <groupId>org.postgresql</groupId> <!-- or another driver you use -->
                                <artifactId>postgresql</artifactId>
                            </weaveDependency>
                        </weaveDependencies>
                        <aspectLibraries>
                            <aspectLibrary>
                                <groupId>edu.ifmo.diploma</groupId> <!-- library with aspect -->
                                <artifactId>db-analyzer</artifactId>
                            </aspectLibrary>
                        </aspectLibraries>
                        <complianceLevel>${maven.compiler.target}</complianceLevel>
                        <showWeaveInfo>true</showWeaveInfo>
                        <Xlint>ignore</Xlint>
                        <encoding>UTF-8</encoding>
                    </configuration>
                    <executions>
                        <execution>
                            <goals>
                                <goal>compile</goal>
                                <goal>test-compile</goal>
                            </goals>
                        </execution>
                    </executions>
                    <dependencies>
                        <dependency>
                            <groupId>org.aspectj</groupId>
                            <artifactId>aspectjtools</artifactId>
                            <version>${aspectj.version}</version>
                        </dependency>
                    </dependencies>
                </plugin>