Define a missing method through AOP? - aop

I'm in a situation where the implementation of a library we are using is newer than the implementation one of our dependencies was coded against. E.g. Dependency uses MyLibrary-1.0 and we're using MyLibrary-2.0.
In the newer implementation a deprecated method has been removed, which causes run-time errors for us.
I'm trying to use AOP (Spring-AOP to be specific) to intercept calls made to the missing method, and proxy them into an existing method... but I can't seem to get the Aspect right.
It feels like Java is raising the 'java.lang.NoSuchMethodError' exception before my Aspect has an opportunity to intercept. Is there some trick I'm missing, or is this just not feasible (e.g. the method must exist in order to aspect it)?
#Before("execution(* com.mylibrary.SomeClass.*(..))")
Fails with java.lang.NoSuchMethodError
#Around("target(com.mylibrary.SomeClass) && execution(* missingMethod(..))")
Fails with java.lang.NoSuchMethodError

Assuming that your are talking about a 3rd party library which is independent of Spring, you cannot use Spring AOP with its proxy-based "AOP lite" approach which only works for public, non-static methods of Spring components. Please use the more powerful AspectJ instead. The Spring manual explains how to integrate full AspectJ with load-time weaving (LTW) into Spring applications. If your application is not based on Spring so far and you just wanted to use the framework because of Spring AOP, you can skip the whole Spring stuff altogether and use plain AspectJ.
The feature you want to use is an inter-type declaration (ITD), more specifically AspectJ's ability to declare methods for existing classes. Here is some sample code:
3rd party library:
package org.library;
public class Utility {
public String toHex(int number) {
return Integer.toHexString(number);
}
// Let us assume that this method was removed from the new library version
/*
#Deprecated
public String toOct(int number) {
return Integer.toOctalString(number);
}
*/
}
Let us assume that the method I commented out was just removed from the latest version your own project depends on, but you know how to re-implement it.
Project dependency depending on old version of 3rd party library:
package com.dependency;
import org.library.Utility;
public class MyDependency {
public void doSomethingWith(int number) {
System.out.println(number + " in octal = " + new Utility().toOct(number));
}
}
Because the previously deprecated method Utility.toOct does not exist anymore in the version used by your own project, you will get NoSuchMethodError during runtime when calling MyDependency.doSomethingWith.
Your own application:
package de.scrum_master.app;
import org.library.Utility;
import com.dependency.MyDependency;
public class Application {
public static void main(String[] args) {
System.out.println("3333 in hexadecimal = " + new Utility().toHex(3333));
new MyDependency().doSomethingWith(987);
}
}
As you can see, the application also uses the same library, but a different method which still exists in the current version. Unfortunately, it also uses the dependency which relies on the existence of the removed method. So how should we repair this?
Aspect using ITD:
AspectJ to the rescue! We just add the missing method to the 3rd party library.
package de.scrum_master.aspect;
import org.library.Utility;
public aspect DeprecatedMethodProvider {
public String Utility.toOct(int number) {
return Integer.toOctalString(number);
}
}
If you compile this project with the AspectJ compiler Ajc, it just works. In your real life scenario, compile the aspect into its own aspect library, put the weaving agent aspectjweaver.jar on the JVM command line in order to activate LTW and enjoy how it weaves the method into the library class via byte code instrumentation during class-loading.
Log output:
3333 in hexadecimal = d05
987 in octal = 1733
Et voilĂ ! Enjoy. :-)

When the JVM load a class, it resolves all dependencies in a "linker" phase : external classes, properties and method. You can't pass this phase in your case, because methods are missing.
There are two modes on (Spring-)AOP: Proxy, and weaving.
Proxy create... a proxy around a class: the targeted class must exist and be loaded
Weaving can happen before a class is loaded: when a classloader load a class, an array of byte[] is passed to the weaver, which can manipulate the class bytecode before the class is really reified. This type of aop can work in your case. However, it will not be an easy task.

Related

Can we define order of weaving when using AspectJ load time weaving?

I have two aspects and I would want to know that if there is a way I can perform load time weaving for all of them but in a certain order.
Right now, the only way I can think of is doing the same via run-time/execution time weaving using spring proxies or something.
Edit below:
I tried to add a new aspect with #DeclarePrecendence and weave that as well in my aop.xml but that does not seem to work.
#Aspect
#DeclarePrecedence("aspect1, aspect2")
public class AspectOrdering {
/**
* Default constructor to allow instantiation by the AspectJ Weaver (has to be no-args).
*/
public AspectOrdering() {
// no instantiation done by constructor as arguments cannot be passed
}
}
Update:
It works. I think the server where I was testing was not picking up the updated aop.xml earlier.

Javassist NotFoundException when getting java.io.Serializable with JDK9

I have the following code:
private static CtClass resolveCtClass(String clazz) throws NotFoundException {
ClassPool pool = ClassPool.getDefault();
return pool.get( clazz );
}
When running under JDK8, if this method is called using java.io.Serializable, it works, but when running under the JDK9 environment, it throws the NotFoundException.
Is there something I overlooked here?
This does no longer happen with the current EA builds of Java 9. Class files are now always locatable even if they are encapsulated in a module.
This is a consequence of Java 9's module encapsulation where non-exported resources are no longer available via the ClassLoader API. Under the covers, Javassist calls
ClassLoader.getSystemClassLoader().findResource("java/io/Serializable.class");
to get hold of the class file for Serializable. It then parses this class file and represents the information similarly to the Java reflection API but without loading the class such that it can be edited prior to loading it.
Until Java 8, this class file was accessible as most class loaders rely on looking up a class file before loading it such that the above call returned a URL pointing to the file. Since Java 9, resources of named modules are only available via the new API method findResource(String, String) where the second arguments names the module of that class.
The short answer is: Javassist does no longer work with Java 9 and none of its dependant projects will. This is a known issue with the current Java 9 implementation and will hopefully be fixed prior to release.
(I never used Javassist so I'm just shooting in the dark, here...)
The documentation of ClassPool says:
If get() is called on this object, it searches various sources represented by ClassPath to find a class file and then it creates a CtClass object representing that class file.
This seems to be bound to the concept of the class path. Looking at ClassPath and CtClass supports that assumption.
If that is the case, then Javassist might just not be fit to look into JDK 9's brand new modules.
If my guess is correct, you should not be able to get any JDK class from the pool. This should be easily verifiable.

MOQ WCF Service

I need to MOQ wcfClientService while calling the SomeMethod().
Class ABC : IABC
{
internal WcfClientService wcfClientService = new WcfClientService();
public void SomeMethod(object pqr)
{
using(wcfClientService)
{
wcfClientService.Save(some parameters)
}
}
}
With the current implementation, you cannot isolate the "ABC" class as it is tightly coupled with wcfClientService. I would strongly suggest things mentioned below:
Extract an interface IClientService. This makes your "ABC" class depend on an abstraction instead of a concrete implementation. It will help in short term to isolate "ABC" better for unit testing. In long term, your "ABC" class would not have to be changed if a "RestfulClientService" was to be used.
Consider introducing a Dependency Injection framework. Anything like a Spring.Net, Unity or Autofac should serve the purpose. Ideally, your production code should never instantiate a dependency. Let the framework take care of it.
Now, register and resolve a mock implementation of the interface using the DI framework and start unit testing the "ABC" class.

Find Self-Referential Code in IntelliJ

In IntelliJ when code is not used anywhere it will be "grayed out." Is there any way to see if a set of classes aren't used anywhere?
I have this set of classes with references to each other so IntelliJ is counting this set of classes as being used. In this case I know the code is useless but it would be nice to have the ability to automatically detect this sort of thing. The logic to do this isn't amazingly difficult... Does anyone know if this is possible in IntelliJ?
This "greyed out" mark simply reflects declaration usages in other source code files or framework configuration files. Declaration usage search cannot detect orphan clusters of classes as these classes are formally referenced.
There is a technique, that may help here: define some root set of entry points (main() methods, web.xml declarations, etc) and trace all the references, effectively building a graph of used classes/methods. Once graph is completed, you can treat unvisited classes as dead code. Pretty similar to what Java garbage collector does during young gen collection. It is quite difficult and resource consuming for on-the-fly code analysis, so Intellij has it implemented as a separate inspection one can run manually.
To demonstrate it let's create a fresh project containing the following code:
public class Main {
public static void main(String[] args) {
System.out.println(new Used());
}
}
class Used {}
class ObviouslyUnused {}
class TrickyUnused1 {
TrickyUnused1() {
System.out.println(new TrickyUnused2());
}
}
class TrickyUnused2 {
TrickyUnused2() {
System.out.println(new TrickyUnused1());
}
}
In the editor we can see, that only ObvoiuslyUnused is greyed out. Let's run an "Unused declaration" inspection:
and here we go, inspections shows, that our unused self-referenced class cluster is not reachable:
You should be aware, though, that there are always means of referencing code in implicit ways: reflection, native calls, runtime code generation, SPI implementations, references from framework configuration files, etc. So no static anlisys tool can be 100% accurate when detecting dead code.

Scripting Eclipse with Rhino: classloader belongs to the plugin providing Rhino, not the plugin using it

I am using Rhino to script an Eclipse (RCP) application. The problem is that from Javascript I only have access to classes available to the plugin that provides Rhino, and not to all the classes available to the plugin that runs the scripts.
The obvious answer would be to put Rhino in the scripting plugin, but this doesn't work because it's already provided by one of the application's own plugins (which also provides things I need to script) and Eclipse always uses this version instead of the version closer to hand.
Is there a way to change the classloader used by Rhino
or is it possible to ensure that Eclipse loads the Rhino classes from one plugin rather than another?
Thanks to Thilo's answer I used this:
import net.weissmann.tom.rhino.Activator; // Plugin activator class
import org.mozilla.javascript.tools.shell.Main;
public class JSServer extends Thread {
//[...]
public void run() {
// recent versions of the Main class kindly export
// the context factory
Main.shellContextFactory.initApplicationClassLoader(
Activator.class.getClassLoader()
) ;
//[...]
}
Is there a way to change the classloader used by Rhino
Rhino should be using the current Thread's ContextClassLoader. Try Thread.setContextClassLoader (don't forget to restore it).
If that does not work, maybe you can create your own Rhino ContextFactory:
public final void initApplicationClassLoader(java.lang.ClassLoader loader)
Set explicit class loader to use when searching for Java classes.
I don't know Rhino specifics, but you could consider using Eclipse "buddy classloading" with the "registered" policy.
Rhino's plug-in (net.weissmann.tom.rhino, say) would declare itself "open to extension" by specifying Eclipse-BuddyPolicy: registered in its MANIFEST.MF. Plug-ins with classes that Rhino should be able to see would specify Eclipse-RegisterBuddy: net.weissmann.tom.rhino and would need a bundle-level dependency on net.weissmann.tom.rhino.
http://www.eclipsezone.com/articles/eclipse-vms/
http://wiki.eclipse.org/index.php/Context_Class_Loader_Enhancements#Technical_Solution