Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create a version of HotSwapper that uses the Instrumentation package #119

Closed
alugowski opened this issue Jan 19, 2017 · 9 comments
Closed

Comments

@alugowski
Copy link

Class bytecode redefinition at runtime is a very powerful concept. javassist's HotSwapper is a good way to accomplish this, but it has serious drawbacks. It works in our testing environment, but causes a JVM freeze in our production highly multithreaded high load environment. We suspect that this is because the debug agent that HotSwapper depends on has thread safety issues; in fact we have to disable it on some of our machines because we saw a problem in its class loading hooks.

Java comes with Instrumentation.redefineClasses that can do the same job without involving the debug agent.

This method works great in our production environment. I know it's not very well documented on the web, so I published a writeup and short class that implements the approach here: https://github.com/turn/RedefineClassAgent

This class already works well with javassist, but it might be handy for the javassist user base to have that approach bundled with javassist. Maybe a HotSwapper2?

@chibash
Copy link
Member

chibash commented Jan 19, 2017

This idea sounds interesting. The best way seems to include your RedefineClassAgent in the main source tree but, to do that, we need to resolve a copyright issue. Can you change the copyright notice into MPL/LGPL/Apache triple? If your organization does not allow it, I'll reimplement your class, though. I hope your organization does not care about looking at your code when I write my own. :-)

@alugowski
Copy link
Author

Sure, no worries. You are half the reason I published this in the first place :) Though from what I gather, BSD 3-clause license is compatible with LGPL and Apache, and I believe MPL as well so you should be good to go as is. I'd rather have a short comment at the top instead of a complicated 500 line one :P

I'll let you decide if including that file or writing one that more tightly integrates with javassist is best. I know that HotSwapper doesn't use ClassDefinition, instead it takes class name as a String and bytecode array directly. The reason I didn't make a PR is because I don't know enough about your workflow to make the choice myself.

@chibash
Copy link
Member

chibash commented Jan 19, 2017

Thanks. The reason I asked to change the license is that some organizations (their lawyers) require the software explicitly states its license is Apache. I know BSD is compatible to LGPL/AP but some lawyers do not believe so.

@alugowski
Copy link
Author

No problem. Just so I understand, would a simple Apache license be enough? Or does "triple license" mean all three?

@chibash
Copy link
Member

chibash commented Jan 19, 2017

For consistency, triple license is preferable. I know it's ugly but this is a legal issue.

@alugowski
Copy link
Author

I relicensed it. It's now MIT for general use (even less restrictive), but also can be used by the three licenses referenced in HotSwapper.java. For inclusion in javassist you have our permission to remove the reference to MIT and match the licensing of the rest of javassist.

@Elisedlund
Copy link

Elisedlund commented Jan 23, 2017

This I highly interesting and I can see several use cases for this.
Something I want to achieve with the HotSwapper which I have not been able to is to use in in a similar fashion as ProxyFactory where I define a method handler for a class:

 private static final MethodHandler METHOD_HANDLER = new MethodHandler() {

        @Override
        public Object invoke(Object self, Method thisMethod, Method proceed,
                Object[] args) throws Throwable {
            System.out.println("(enchantment) invoked method: " + thisMethod.getName());
            return proceed.invoke(self);
        }
    };

      //        ProxyFactory is great for creating a new class with modified behavior but it won't actually alter to original MyClass which this HotSwapper could do. 
        //        What I would like is a HotSwapper with a similar API as ProxyFactory, where I could use the the same MethodHandler to alter behavior of a of existing classes.

        HotSwapper.modify(MyClass.class, METHOD_HANDLER);
        MyClass myClass = new MyClass(); //will now be a modified MyClass which will execute METHOD_HANDLER with the proceed being the original method call. 

        // main use cases I have for this right now is where I want to use this for unit testing, (as a strange way of mocking things) 

Do you have any ideas how I could get something like this to work where instead of hotSwapping Strings with code that I could hotswap something like a MethodHandler on existing classes

Use case:

        List<String> list = new ArrayList<String>();
        MyClass myClass = new MyClass(list);
        HotSwapper.modify(ArrayList.class,new MethodHandler() {
            @Override
            public Object invoke(Object self, Method thisMethod, Method proceed,
                    Object[] args) throws Throwable {
                if (thisMethod.getName().contentEquals("size")) {
                    return 0; //inject fault were list always return 0
                }
                return proceed.invoke(self); //invoke original
            }
        };)
        //use myClass somehow and assert  exception happens because of size 0 (even tho its not!)
        HotSwapper.restore(ArrayList.class);

(+points if it possible to achieve this without tools.jar, it not that different to ProxyFactory in javassist)

@chibash
Copy link
Member

chibash commented Apr 16, 2017

I wrote javassist.util.HotSwapAgent.java, which is based on your RedefineClassAgent, and committed it (d5ea684) mainly for licensing and backward compatibility.
I added your name in the javadoc comment. Hope it's OK for you.

Anyway thank you for your contribution!

@alugowski
Copy link
Author

It looks great!

Glad you found this useful :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants