Use AspectJ to monitor database access methods - java

I want to use AspectJ to monitor database statements.
When I define the pointcut as
#Pointcut("execution(* java.sql.*Statement.execute*(..))")
it does not work. But when I define the pointcut as
#Pointcut("execution(* *.*(..))")
it can monitor all methods.
How can I define the pointcut to monitor database access methods only?

What you say is not true, because with the second pointcut you can capture a whole lot of method executions but nothing inside the JDK. If you think about it for a while you understand why: AspectJ instruments byte code, but only the byte code of your own classes or libraries, not the JDK byte code because you do not weave your aspects into the JDK. Thus, you cannot capture any execution() joinpoints inside the JDK (except if you instrument the class files inside rt.jar or so).
Now how do you solve your problem? First you need to understand the fundamental difference between execution() and call() pointcuts: The former is woven into callees, i.e. right into the target methods. The latter is woven into callers, i.e. into all places where the target method is called.
So you want to try
#Pointcut("call(* java.sql.*Statement.execute*(..))")
But there is a caveat: You are fine if your own code, i.e. the one compiled with AspectJ, calls the statements directly. If you are interested in capturing calls made by 3rd party libraries as well, you either need to weave those as well via binary weaving (producing a new library with woven class files replacing the original one) or via load-time weaving (instrumenting the byte code while it is loaded during runtime). Both is possible. But how to do that is beyond the scope of this article, please read the AspectJ documentation for instructions. Last but not least, if JDK code calls those methods internally, you will not be able to capture the calls by any other means than also weaving the JDK (rt.jar or wherever the SQL code resides), as mentioned above.
I know this is a complex answer to a simple question, but you really need to understand AspectJ before you use it, otherwise you might not fully grasp what I was trying to explain. AspectJ is fun to learn and experiment with, take your time and enjoy it. If you just copy and paste code snippets you are but a fool with a (very powerful) tool. :-)

Related

Detect weaved class by aspectJ with byte-buddy agent

I would like to verify that the code has been woven by aspectJ. One of the methods I've heard of is using agents from the byte-buddy library. Unfortunately, I am completely green in it and I do not know what I could do.
I tried to use JADE with agents, but byte-buddy is more friendly for myself and I think it's more suitable.
To verify the method I created a simple springboot application with MySQL connection and added some aspectJ code. I tried with Spring AOP, but AOP cannot read private methods, so I decided to provide my idea with aspectJ.
I already used another aspect to define joinPoints and throw an exception, but it's hard and takes a lot of works with the low results.
Do u have any ideas about methods or implementation of an agent with byte-buddy to detect aspectJ?
First an answer to your comment:
I wanted to have more experience with untrusted code. For example if I get a big project in Java and then I get some untrusted plugin with changes created by AspectJ, then I prefer to know what's to do to inspect that my classes are secured from AspectJ or that the AspectJ just weaves into my classes.
For AspectJ there are two scenarios:
Compile-time weaving
Your application does not use AspectJ, no AspectJ Maven plugin in your Maven build or something similar in your Gradle build: Even if your third-party library is on the classpath, nothing gets woven into your own code. How could it? There is no AspectJ compiler.
Your application uses the AspectJ compiler: Even if the third-party library is on the classpath, no aspects are woven into your own code because you would have to explicitly put the library on the aspect path in order to achieve that. BTW, if the third-party library is aspect-enhanced, it will have a dependency on the AspectJ runtime aspectjrt.jar, otherwise it would not work. Even if the runtime was shaded into that other JAR, still nothing would happen to your own code.
Load-time weaving
Your application does not use LTW: Obviously nothing would happen, no aspects from the other JAR could be woven into your code without you starting the JVM with an active weaving agent.
Your application uses LTW: You would need to provide an aop.xml file and there you can explicitly list aspects you want to be applied, which target classes or packages to include into or exclude from weaving, turn on -showWeaveInfo in order too see on the console which aspects are woven into which joinpoints. There is one caveat, though: If the AspectJ weaver finds more than one aop.xml or aop-ajc.xml files on the classpath, it will conceptually merge them. I.e. if the third-party library comes with such a file, it would be merged into your own as explained in the AspectJ development guide (search for "several configuration files" on the page). So this could lead to some undesired side effects. The simplest thing to do if you want to inspect your third-party libraries is to scan the JARs for the presence of aop.xml or aop-ajc.xml, respectively. Then you can look at the content of those files, if any, and easily assess their possible effect on your code. But just checking the output of -showWeaveInfo on application start-up also reveals if unwanted aspects are woven into your own code.
So actually you don't need to scan for anything inside class files in order to detect AspectJ markers, but if you absolutely wish to here is something you can do:
Most AspectJ-woven classes contain fields or methods (can be static or non-static, private or public) with ajc$ somewhere in their name, usually at the beginning. That's just a heuristic approach, but hey - whatever works, right?
If I say "most classes" I mean that in some cases if an aspect only uses ITD in order to make a class implement an interface, introduce new methods or public fields, the class would just get the new elements but no AspectJ-specific code. But then they would just be normal classes, there is no cross-cutting advice code or whatever which could affect your own application.
If you would find such members or fields, it would indicate that you either found classes enhanced by aspects (which could not affect your own classes even in the LTW scenario with extra aop.xml) or aspects themselves because they also contain the same markers plus some other stuff you could scan for.
So how can you scan those third-party class files?
Command line: javap -p path/to/MyClass.class | grep 'ajc[$]'
Java code to scan classes already loaded into your (test or inspection) application:
package de.scrum_master.aspect;
import java.lang.reflect.Member;
import java.util.stream.Stream;
public class AspectJDetector {
public static boolean hasAspectJMarker(Class<?> clazz) {
return Stream.concat(
Stream.of((Member[]) clazz.getDeclaredMethods()),
Stream.of((Member[]) clazz.getDeclaredFields())
)
.filter(member -> member.getName().contains("ajc$"))
.findFirst()
.isPresent();
}
}
Just call hasAspectJMarker(MyClassOfInterest.class) for each class you want to check. If you find AspectJ-enhanced classes, there is again no need to worry. Only if you find aspects there might be. But as I said above: This would be easier to detect via aop.xml in that JAR. The XML file would even list the aspects explicitly via <aspect name="com.MyAspect"/>, basically a no-brainer.

How can aspectJ pointcuts be used with dynamic selector?

I'm working on a small project that determines code coverage when testing a java application. It basically consists of a plugin for an IDE which finds all the classes and methods in the project and saves them in a database, and an agent with aspectJ pointcuts that weave around all of these methods to log their execution.
The problem I have is that I only want to log the methods that are actually written by the developers of that very project and not those of underlying libraries. So the pointcuts need to be defined in a way that only methods of classes in the actual project packages are woven. On the other hand, since the agent is to be used with all sorts of projects, I can't hardcode those packages.
My attempt so far was to read all the package names from the database and build a string from that. Basically what it looks like is this:
private static final String POINTCUT_STRING = AspectUtil.buildPointcutString();
And then, when defining the pointcut:
#Pointcut(POINTCUT_STRING)
Thing is, this doesn't work because apparently when defining a Pointcut, the
Attribute value needs to be a constant.
So, how can I make it so that i can only weave methods in classes in the packages that I have in my database?
Thanks in advance, have a good one!
I don't think a dynamic aspect approach is going to work as aspectj does not expose the weaver to any state management or changes. Although this would be theoretically possible at runtime it's definitely not possible at compile time (and you have the option to add your aspects at compile time).
But to your issue...
What weave strategy are you using? compile or runtime? I've found compile to work very well and I'm not sure how to use runtime with aspectj. But what I can say is that if you use compile you'll only be weaving the application classes in any case as that is all you'll have access to.
Another comment to make is if you want to do something dynamic you'd be better off putting the condition on whether to monitor that method for code coverage downstream of the aspect. So when the aspect is executed the first thing it will do is decide if this class/method call should be monitored for coverage and then go on from there...
When I asked you:
What do you mean by "runtime weaving"? Load-time weaving (LTW) maybe? I.e. you are using aop.xml? I am asking for a specific reason.
You replied:
Yes, LTW. I am using an aop.xml file.
In that case you have the option of specifying pointcut definitions in aop.xml which is read during JVM start-up when the weaving agent is activated. For refererence, please read the AspectJ Developers Guide, there is a chapter on LTW. You will find sample code and sample XML definitions there, showing how you can extend an abstract aspect with an abstract pointcut in the XML file and specify a concrete pointut for a concrete subclass. That should give you the options you need to keep your pointcut out of the Java code, for whatever reason you think that's a good thing and you need it.
Please note that you cannot expect to modify aop.xml during runtime and re-load it, possibly re-applying the aspect dynamically to all classes. AspectJ LTW works in connection with class-loading, i.e. you only have one shot at JVM start-up before all application classes are loaded. This is not an AspectJ limitation but just how bytecode instrumentation in the JVM works.

How to add Java annotation over methods during runtime [duplicate]

Is there a way to modify .class files in order to add Java annotations to certain methods? Basically I want to traverse methods of each class file in a jar file and annotate certain ones. Note that this is not at run-time while using the jar file. Rather, after I'm done I want to have modified class files with the annotations.
I do have access to the source code, so if there's an automatic source code modifier, that would work as well...
I'm assuming I'll need a tool such as Javassist or ASM. If so, which one should I use and how would I go about it?
Actually, this is a classic use case for AspectJ:
declare #method : public * BankAccount+.*(..) : #Secured(role="supervisor")
While I will grant you that direct byte code manipulation is more powerful, AspectJ is much more user-friendly, and it immediately gives you compiler warnings when you are doing something wrong.
Also, if you use Load Time Weaving, you can leave the original library jar unchanged, because the weaving happens at class-load time.
Reference:
Declare Annotation
AspectJ in Action (book)
Googling for an hour or so turned this article up which seems to completely answer my question: use ASM. To write class files using the changed bytecode, use ClassWriter.
Well, time to get to work then, I guess. :)

Deprecating an java JRE method

I would like to mark usage of certain methods provide by the JRE as deprecated. How do I do this?
You can't. Only code within your control can have the #Deprecated annotation added. Any attempt to reverse engineer the bytecode will result in a non-portable JRE. This is contrary to Java's write once, run anywhere methodology.
you can't deprecate JRE methods, but you can add warnings or even compile errors to your build system i.e. using AspectJ or forbid the use of given methods in the IDE.
For example in Eclipse:
Go to Project properties -->Java Compiler --> Errors Warnings, Then enable project specific settings, Expand Deprecated and restrited APIs category
"Forbidden reference (acess rule)"
Obviously you could instrument or override the class adding #Deprecated annotation, but it's not a clean solution.
Add such restrictions to your coding guidelines, and enforce as part of your code review process.
You only can do it, if and only if you are building your own JRE! In that case just add #Deprecated above the corresponding code block! But if you are using Oracle's JRE, you are no where to do so!
In what context? Do you mean you want to be able to easily configure your IDE to inhibit use of certain API? Or are you trying to dictate to the world what APIs you prohibit? Or are you trying to do something at runtime?
If the first case, Eclipse, and I assume other IDEs, allow you to mark any API as forbidden, discouraged, or accessible at the package or class level.
If you mean the second, you can't, of course. That would be silly.
If you are trying to prohibit certain methods from being called at runtime, you can configure a security policy to prevent code loaded from specified locations from being able to call specific methods that check with the SecurityManager, if one is installed.
You can compile your own version of the class and add it to the boot class path or lib/ext directory. http://docs.oracle.com/javase/tutorial/ext/basics/install.html This will change the JDK and the JRE.
In fact you can remove it for compiling and your program won't compile if it is used.
Snihalani: Just so that I get this straight ...
You want to 'deprecate methods in the JRE' in order to 'Making sure people don't use java's implementation and use my implementation from now on.' ?
First of all: you can't change anything in the JRE, neither are you allowed to, it's property of Oracle. Uou might be able to change something locally if you want to go through the trouble, but that 'll just be in your local JRE, not in the ones that can be downloaded from the Oracle webpage.
Next to that, nobody has your implementation, so how would we be able to use it anyway? The implementations provided by Oracle do exactly what they should do, and when a flaw/bug/... is found it'll be corrected or replaced by a new method (at which point the original method becomes deprecated).
But, what mostly worries me, is that you would go and change implementations with something you came up with. Reminds me quite lot of phishing and such techniques, having us run your code, without knowing what it does, without even knowing we are running your code. After all, if you would have access to the original code and "build" the JRE, what's to stop you from altering the code in the original method?
Deprecated is a way for the author to say:
"Yup ... I did this in the past, but it seems that there are problems with the method.
just in order not to change the behaviour of existing applications using this method, I will not change this method, rather mark it as deprecated, and add a method that solves this problem".
You are not the author, so it isn't up to you to decide whether or not the methods work the way they should anyway.

Plugging in to Java compilers

I have a post-compilation step that manipulates the Java bytecode of generated classes. I'd like to make life as painless as possible for library consumers, so I'm looking at ways I can make this process automatic and (if possible) compiler agnostic.
The Annotation Processing API provides many of the desired features (automatic service discovery; supported by Eclipse). Unfortunately, this is aimed at code generators and doesn't support manipulation of existing artefacts:
The initial inputs to the tool are
considered to be created by the zeroth
round; therefore, attempting to create
a source or class file corresponding
to one of those inputs will result in
a FilerException.
The Decorator pattern recommended by the API is not an option.
I can see how to perform the step with a runtime agent/instrumentation, but this is a worse option than a manual build step as it would require anyone even peripherally touched by the API to configure their JVMs in a non-obvious manner.
Is there a way to plug into or wrap the compiler tool as invoked by javac? Has anyone successfully subverted the annotation processors to manipulate bytecode, no matter what the doc says?
The Groovy compiler is the only bytecode compiler which allows to hook into the compilation process (example: Generate bytecode to support the Singleton pattern)
The Annotation Processing API is not meant to change the code. As you have already found out, all you can do is install a classloader, examine the bytecode at runtime and manipulate it. It's braindead but it works. This follows the general "we're afraid that a developer could try something stupid" theme which you will find throughout Java. There is no way to extend javac. The relevant classes are either private, final or will change with the next version of Java.
Another option is to write annotated Java, for example you write a class "ExampleTpl.java". Then, you use a precompiler which expands the annotations in that file to get "Example.java". In the rest of the code, you use Example and ignore ExampleTpl.
For Eclipse, there is a bug report to automate this step. I'm not aware of any other work in this area.
It can be done.
Take a look at my blog post Roman Numerals, in our Java where an annotation processor is used to rewrite code. Limitation being that it works with Sun's javac only.

Categories