4

I have a class which behavior I would like to change. I need to replace private method with another realization. Common reflection techniques allow to modify private variable or to invoke private methods. But I find little information about replacing entire methods.

I presume that there are advanced techniques to do so. May be its impossible with standard java reflection but there are probably other tools to recompile byte code in runtime.

ayvango
  • 5,867
  • 3
  • 34
  • 73
  • What exactly are you trying to accomplish? I assume you don't own the class, but there is just too little information here to suggest a solution. However, in general private methods are private for a reason, so you should think long and hard before you attempt to circumvent the author's intent. – pens-fan-69 Apr 27 '15 at 12:39
  • I don't own the class. I just need a dirty hack to overcome issue that resides in jira for years – ayvango Apr 27 '15 at 12:42
  • Do you have control over where the method is called? Over the instance that it is called on? Access to the source-code of the method and its class? – tucuxi Apr 27 '15 at 12:53
  • It is called from bunch of other private methods – ayvango Apr 27 '15 at 12:54
  • If it's open source, you may have luck sending in a pull request to get the original authors to merge it into their mainline. This has worked for me before (and you get to feel warm&fuzzy and avoid maintenance cost too!). – tucuxi Apr 27 '15 at 12:56

3 Answers3

2

Modify & replace:

One option is to mask the class with a modified copy (modify code, recompile code, add modified classes to the classpath before patched classes), similar to the approach used here to inspect how a normally unavailable method works.

If you do not have sources to modify, you can "reverse" almost any .class file into more-or-less readable source code using decompilers. Notice that, depending on licensing, you may not have permission to do so and/or to redistribute your changes.

Patch via agent:

You can also patch the methods using the -javaagent:<jarpath>[=<options>] commant-line option. The "agent" is a jar that gets to modify loaded classes and alter their behaviour. More information here.

Mock:

If you have control over where the methods are called, you can replace the target instance with a stubbed version. Libraries such as Mockito make this very, very easy:

LinkedList mockedList = mock(LinkedList.class);
// stubbing appears before the actual execution
when(mockedList.get(0)).thenReturn("first");

Even though Mockito does not support mocking private methods natively (mostly because it is considered bad manners to look at other classes' privates), using PowerMock allows you to do so (thanks, @talex).

Community
  • 1
  • 1
tucuxi
  • 17,561
  • 2
  • 43
  • 74
1

You can't replace method in runtime (at least without hack into JVM). But you can replace whole class. There are several way to do it. For example you can use thing called "aspect".

But from my experience I can say that if you need to do this you have wrong turn somewhere in beginning of you way.

Maybe you better make one step back and look at whole picture

talex
  • 17,973
  • 3
  • 29
  • 66
0

Instead of going for advanced techniques, there is a simple trick to achieve this.

If you class is part of an open-source jar, get source code of this class file from grepcode.com. Change the method that you want to change and compile it. And update your jar file/classpath with this updated class file.

Ashishkumar Singh
  • 3,580
  • 1
  • 23
  • 41
  • If you do this, then you will be responsible for either maintaining the code for that jar for your project in perpetuity or making the same change every time a new version of the jar is released. This is a very bad idea. – pens-fan-69 Apr 27 '15 at 12:36
  • I'm diving into the ASM documentation now. It is what I seek probably – ayvango Apr 27 '15 at 12:36
  • @pens-fan you are write that who ever update the jar will be responsible for maintaining the code if version of jar is changed. But there are some scenario where there is no other option left. e.g. if you want, in a web application, some-line to not shown while source code is generated and configuration for this is not provided by developer, then you can either ask developer to update jar or use given trick – Ashishkumar Singh Apr 27 '15 at 12:42
  • 1
    @talex - if given a choice between maintaining a source-code patch up to date and a maintaining a bytecode patch up to date, source-code is less painful. Grepcode may not be the best resource to get source (if it is open-source, they probably use publicly-available version control) - but otherwise, Ashish's answer is not that bad. – tucuxi Apr 27 '15 at 12:51
  • @tucuxi I believe that problems like this can be solved without need of hacking. But in both case I suggest to create several test that will executed every day. Because it very easy to forget about changes like that and very difficult to find problem if something goes wrong. – talex Apr 27 '15 at 12:53
  • @talex. You are right but there are certain situation where you are left with little choice and doing this harm very little. e.g.In our project, we were using zk jar V 5.65. Now when html pages were generated, zk used to include it's version inside the html. Zk people have provided the configuration after version 7.0 to not show this in source code but for security reason we wanted to stop showing version in source code. So either we had to migrate to latest zk version or some how remove the line which display version. And we opted for the second one as migration required significant effort. – Ashishkumar Singh Apr 27 '15 at 13:07
  • @AshishSingh So you think that migration to new version too expensive and make it even more expensive :) You can do it in only one case: if you 100% sure that you never ever will upgrade. Or if I rephrase this sentence: your software die earlier then their :) – talex Apr 27 '15 at 13:13