Using java.lang.reflect.Proxy for interposition

Discussion in 'Java' started by David C. Partridge, Apr 13, 2004.

  1. I want to intercept method calls on Java classes. The classes in question
    are delivered by a third party in a jar file and I do not have access to the
    sources for that. The client code that uses those classes is also not
    available to me. If I were writing C code I'd just create a new shared
    library that exported the API calls I wanted to intercept, and dynamically
    load the real API calls (after adjusting the appropriate environment
    variables so that my library was picked up first.

    I was hoping to use java.lang.reflect.Proxy to do this, and in Tom Harpin's
    article "Using java.lang.reflect.Proxy to Interpose on Java Class Methods",
    he said:

    ===QUOTE===
    At class load time, the interposed class must be found before the original
    one. This can be readily accomplished through manipulation of the CLASSPATH
    environment variable or a -classpath switch on the commandline. The
    interposed class must have the same full name as the original. For example,
    a class Foo may exist in package pub.foo and create an instance of class Bar
    from package pub.bar. Creating a file Bar.java in another directory, such as
    fake/pub/bar and prepending /fake to the classpath, ensures that the JVM
    will load our definition of class pub.bar.Bar rather than the original. In
    this way, we can interpose our definitions of Bar's methods over the
    originals.
    There is a problem, however, if we now wish to dispatch to the original
    method. Since each classloader maintains a cache of unique class names, the
    interposed and original classes pub.bar.Bar cannot coexist in the same
    classloader's namespace. Therfore, the original class must be loaded by a
    separate classloader (using a different classpath) and a technique must be
    devised to "trampoline" from the interposed method call to the original.
    ===QUOTE===

    and also said:

    ===QUOTE===
    The proxy class is relatively flexible and straightforward to use, but there
    are some distinct limitations on its use for method interposing. One
    limitation is that the method must be called through an instance of the
    proxy class. So nested methods calls, for instance, would not be
    intercepted. Another limitation is that the method must have been defined in
    an Interface that is implemented by the object being proxied. It can not be
    called through an instance of a class that does not implement an interface.
    The next article in this series will illustrate some techniques for
    overcoming these limitations.
    ===QUOTE===

    As far as I can determine, no such article was ever published. Does anyone
    know of techniques that I can use to achieve the required result so that I
    can intercept those method calls (preferably by just modifying CLASSPATH so
    my jar file is picked up ahead of the other one).

    Dave
     
    David C. Partridge, Apr 13, 2004
    #1
    1. Advertising

  2. David C. Partridge

    Chris Smith Guest

    David C. Partridge wrote:
    > I want to intercept method calls on Java classes. The classes in question
    > are delivered by a third party in a jar file and I do not have access to the
    > sources for that. The client code that uses those classes is also not
    > available to me. If I were writing C code I'd just create a new shared
    > library that exported the API calls I wanted to intercept, and dynamically
    > load the real API calls (after adjusting the appropriate environment
    > variables so that my library was picked up first.
    >
    > I was hoping to use java.lang.reflect.Proxy to do this, and in Tom Harpin's
    > article "Using java.lang.reflect.Proxy to Interpose on Java Class Methods",
    > he said:


    Use of java.lang.reflect.Proxy looks rather suspect, unless you know
    that a few conditions are true of the code you are trying to intercept.
    Specifically, the methods you are intercepting would need to be
    specified by interfaces, and the client code would need to call this
    code only through those given interfaces. I had not read Tom's article
    until now, but he does mention these limitations as well.

    If that's not the case, then the Proxy class does not meet your needs,
    and there's really no way to make it work.

    > As far as I can determine, no such article was ever published. Does anyone
    > know of techniques that I can use to achieve the required result so that I
    > can intercept those method calls (preferably by just modifying CLASSPATH so
    > my jar file is picked up ahead of the other one).


    You won't be using Proxy, but it is possible to intercept method calls
    by interposing your own code if you care to write your code statically
    (i.e., you will have to write the intercepting class instead of having
    it generated for you) and you know the APIs to implement.

    The situation with classloaders is a bit difficult. You do *not* want
    your intercepting code or the library code to be loaded by the system
    classloader, because the names defined would then be effectively
    globally accessible and would always conflict with any attempt to define
    another such entry point with the same name. Furthermore, your
    intercepting code cannot by loaded by the same loader as the library
    code, because the entry point names are the same. You therefore need
    three classloaders, chained in this specific way:

    1. System classloader
    1a) Intercepting classloader
    1b) Library classloader

    Now, you want the application to see your intercepting classes rather
    than the library classes. The easiest way to do this is to load the
    application into the intercepting classloader. That means that you'll
    need a custom launcher class loaded by the system classloader, to
    interject instead of the original class, which will set up the remaining
    two classloaders. It would look like this (with tedious code omitted;
    let me know if you don't know how to write the tedious code, and I'll
    post it):

    public class InterjectingLauncher
    {
    public static ClassLoader appLoader;
    public static ClassLoader libLoader;

    public static void main(String[] args)
    {
    if (args.length < 1) usage();
    String className = args[0];
    String[] newArgs = new String[args.length - 1];
    System.arraycopy(/* from args to newargs */);

    appLoader = new URLClassLoader(/* URL to app */);
    libLoader = new URLClassLoader(/* URL to lib */);

    /* Load className from appLaoder and invoke its main method */
    }
    }

    Then you'd write your interceptors to explicitly switch over to the
    other loader if you want to pass the call along. For example:

    package original.package.name;

    public class OriginalClassName
    {
    public void foo(Object param)
    {
    /* do your thing */

    ClassLoader ldr = InterjectingLauncher.libLoader;
    /* load "OriginalClassName" from ldr and dispatch */
    }
    }

    That said, it's worth deciding if it's even worth your effort here. If
    this isn't something that's going to happen at deployment, then can you
    solve your problem with JVMPI or JVMDI instead. If it is happening
    post-deployment, it's possible that there are legal problems with
    creating a look-alike API in someone else's proprietary package (but I'm
    not a lawyer, so check with yours for further advice there).

    --
    www.designacourse.com
    The Easiest Way to Train Anyone... Anywhere.

    Chris Smith - Lead Software Developer/Technical Trainer
    MindIQ Corporation
     
    Chris Smith, Apr 13, 2004
    #2
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. snatchitup
    Replies:
    3
    Views:
    1,990
    Larry A. Barowski
    Dec 4, 2003
  2. Nikita A. Visnevski

    Problem with java.lang.reflect.Proxy

    Nikita A. Visnevski, Apr 22, 2004, in forum: Java
    Replies:
    1
    Views:
    1,783
    Nikita A. Visnevski
    Apr 22, 2004
  3. Ovidiu

    java.lang.reflect.Proxy

    Ovidiu, Aug 10, 2004, in forum: Java
    Replies:
    1
    Views:
    500
    John C. Bollinger
    Aug 10, 2004
  4. Karsten Wutzke
    Replies:
    1
    Views:
    916
    Steven Simpson
    Aug 20, 2007
  5. Sébastien de Mapias

    Purpose of using java.lang.reflect.Proxy ?

    Sébastien de Mapias, Jun 11, 2009, in forum: Java
    Replies:
    1
    Views:
    712
    Joshua Cranmer
    Jun 11, 2009
Loading...

Share This Page