Can Byte Buddy access local variable name of a method? - java

Suppose I have a method m:
public void m() {
String foo = "foo";
int bar = 0;
doSomething(foo, bar);
}
I want to use ByteBuddy to instrument the code so that when calling doSomething in m, it will automatically put the value of foo and bar into a HashMap, pretty much something looks like:
public void m() {
String foo = "foo";
int bar = 0;
context.put("foo", foo); // new code injected
context.put("bar", bar); // new code injected
doSomething(foo, bar);
}
Is there anyway to do this instrumentation via ByteBuddy?

There is built-in way in Byte Buddy to do redefine method m in this way. Byte Buddy is however voluntarily exposing the ASM API on top of which Byte Buddy is implemented. ASM offers quite extensive documentation which would show you how to do this. I can however tell you that it will be quite a lot of code. Note that you require to compile any method with debug symbols enabled, otherwise these internal variables are not available at run time.
Are you however sure you want to do this? Without knowing your exact use case, it feels like it is a bad idea. By implementing this solution, you make the names of local variables a part of your application instead of letting them be an implementation detail.
I would therefore suggest you to rather instrument the doSomething method. Would this suffice yourn what is easily done in Byte Buddy using an interceptor like the following:
class Interceptor {
void intercept(#Origin Method method, #AllArguments Object[] args) {
int index = 0;
for(Parameter p : method.getParameters()) {
context.add(p.getName(), args[index++]);
}
}
}
This interceptor could then be used as follows:
MethodDelegation.to(new Interceptor()).andThen(SuperMethodCall.INSTANCE);

Related

How to assert the number of assertions (or some other way to enforce that all members have been tested in an assertion)?

In a certain unit test for my class, I want to assert that an assertion has been written for all member fields. That is, given
public class Foo {
int a;
int b;
String c;
}
I want to do something like
#Test
public void testFieldsAgainstExternalModel(Foo model, Bar externalModel) {
assertEquals(model.a, externalModel.getA());
assertEquals(model.b, externalModel.getSomethingNamedDifferently());
assertEquals(model.c, externalModel.getC().toString());
assertNumberOfAssertionsInThisTest(3); // <-- How do I do this?
}
Of course, counting the number of assertions doesn't ensure that they had anything to do with each field having an assertion. But, I'm just trying to write a test that fails if a developer adds a field to Foo and forgets to update this test.
Naivest approach: The simplest thing I can think of is to use reflection to assert the number of fields Foo has, e.g. assertEquals(3, Foo.getDeclaredFields().count()). But, I can easily see a programmer bumping up the number without actually adding an assertion.
Still a naive approach, but acceptable: I think if I can at least count the number of assertions, it would sufficiently guide programmers toward the intended need.
More exact approaches: Of course it seems to best approach is to actual keep a table of which fields have appeared in the assertion (e.g. through a wrapper method like assertEqualsWithCounters), but in reality my situation's a little more complicated. For example, my model is actually a generated class (#AutoMatter) and I'll be using getters on both sides of the assertion, so it'll be hard to infer truly which field has been "touched" by an assertion. That's why just counting assertions and remaining agnostic to actual types and counts, would be easiest for me.
But, I'm just trying to write a test that fails if a developer adds a
field to Foo and forgets to update this test.
My company uses a mapping framework to map beans from the db, fields are one to one with the database, to a model bean we return to the client that we can modify as needed. I believe this is a common use case and essentially what you are trying to get at. You should be less concerned with testing changes to Foo, and more concerned with ensuring nothing breaks with the mapping from Foo to Bar.
Class BeanDb{
private int a;
private int b;
...
}
Class Bean{
private int a;
private int b;
private String somethingElse;
...
}
Then we have have a proivder test that uses isEqualToComparingFieldByFieldRecursively to compare the two beans.
private Bean bean = new Bean();
private Bean beanDb = new BeanDb();
private BeanProvider provider = new BeanProvider();
#Before
public void setup(){
bean.setA(1);
bean.setB(2);
beanDb.setA(1);
beanDb.setB(2);
}
#Test
public void prepareForDatabase(){
BeanDb db = provider.prepareForDatabase(bean);
assertThat(beanDb).isEqualToComparingFieldByFieldRecursively(db);
}
#Test
public void populateFromDatabase(){
Bean model = provider.populateFromDatabase(beanDb);
assertThat(model).isEqualToComparingFieldByFieldRecursively(bean);
}
This actually catches a lot of bugs. If something changes in the model bean / db bean the test will break in our continuous integrations suite. The caveat here is that isEqualToComparingFieldByFieldRecursively will not catch newly added fields.
When I review code / pull requests and BeanDb or the provider has been updated I ask, "Did you update the provider test?"
I think you may need to use PowerMockito as Mockito does not support mocking static methods.
I haven't tested the code below - but my idea would be to do the following:
#RunWith(PowerMockRunner.class)
public class Tester {
public class Foo {
int a = 5;
int b = 6;
String c = "7";
}
class Bar {
public int getA() {
return 5;
}
public int getSomethingNamedDifferently() {
return 6;
}
public Integer getC() {
return 7;
}
}
#Test
public void testFieldsAgainstExternalModel() {
testFieldsAgainstExternalModel(new Foo(), new Bar());
}
public void testFieldsAgainstExternalModel(Foo model, Bar externalModel) {
Assert spiedAssert = PowerMockito.spy(Assert.class);
spiedAssert.assertEquals(model.a, externalModel.getA());
spiedAssert.assertEquals(model.b, externalModel.getSomethingNamedDifferently());
spiedAssert.assertEquals(model.c, externalModel.getC().toString());
PowerMockito.verify(spiedAssert, times(3)).assertEquals(any(), any());
}
}
I think that the answer to
assertNumberOfAssertionsInThisTest(3); // <-- How do I do this?
is: you do not do that. This test is close to useless.
If there are only 3 fields, you can see with your eyes that you are checking those three fields. You are probably thinking about 15 fields in that class, but then:
assertEquals(model.a, externalModel.getA());
assertEquals(model.b, externalModel.getSomethingNamedDifferently());
assertEquals(model.c, externalModel.getC().toString());
assertEquals(model.c, externalModel.getC().toString());
assertEquals(model.d, externalModel.getD().toString());
...
assertEquals(model.o, externalModel.getO().toString());
assertNumberOfAssertionsInThisTest(15);
would not help you. Guess what: when pulling together my faked example, I omitted property 14 (model.n), but instead I had a copy/paste error and checked model.c two times, leading to an overall count of 15.
Therefore I agree with user Phil, just suggesting yet another approach, like this:
ensure that the bean classes have reasonable equals() (and maybe hashCode() methods). Either by using Lombok, or by having a base bean class that makes use of an EqualsBuilder (we actually do the later in our projects)
then have test code either use a faked bean and simply compare if that faked bean is equal to the bean that your production code created from a (maybe faked) external model object.

Chain/transform method calls with ByteBuddy

Using ByteBuddy, can I implement one instance method by calling another and transforming the result?
For instance (toy example):
public abstract class Foo {
public String bar() {
return "bar";
}
public abstract int baz();
}
Given the above, can I implement baz such that it calls bar() and returns the length of the returned string? I.e., as if it were:
public int baz() {
return bar().length();
}
Naively, I tried the following:
Method bar = Foo.class.getDeclaredMethod("bar");
Method baz = Foo.class.getDeclaredMethod("baz");
Method length = String.class.getDeclaredMethod("length");
Foo foo = new ByteBuddy()
.subclass(Foo.class)
.method(ElementMatchers.is(baz))
.intercept(
MethodCall.invoke(bar) // call bar()...
.andThen(MethodCall.invoke(length)) // ... .length()?
).make()
.load(Foo.class.getClassLoader())
.getLoaded()
.newInstance();
System.out.println(foo.baz());
However, it looks like I was wrong in thinking andThen() is invoked on the return value of the first invocation; it looks like it's invoked on the generated instance.
Exception in thread "main" java.lang.IllegalStateException:
Cannot invoke public int java.lang.String.length() on class Foo$ByteBuddy$sVgjXXp9
at net.bytebuddy.implementation.MethodCall$MethodInvoker$ForContextualInvocation
.invoke(MethodCall.java:1667)
I also tried an interceptor:
class BazInterceptor {
public static int barLength(#This Foo foo) {
String bar = foo.bar();
return bar.length();
}
}
with:
Foo foo = new ByteBuddy()
.subclass(Foo.class)
.method(ElementMatchers.is(baz))
.intercept(MethodDelegation.to(new BazInterceptor()))
// ...etc.
This ran, but produced the nonsensical result 870698190, and setting breakpoints and/or adding print statements in barLength() suggested it's never getting called; so clearly I'm not understanding interceptors or #This properly, either.
How can I get ByteBuddy to invoke one method and then invoke another on its return value?
Per k5_'s answer: BazInterceptor works if either:
we delegate to new BazInterceptor(), as above, but make barLength() an instance method, or:
we leave barLength() a class method, but delegate to BazInterceptor.class instead of to an instance.
I suspect the 870698190 was delegating to hashCode() of the BazInterceptor instance, though I didn't actually check.
There is not currently a good way in Byte Buddy but this would be an easy feature to add. You can track the progress on GitHub. I will add it once I find some time.
If you want to implement such chained calls today, you can implement them in Java code and inline this code using the Advice component. Alternatively, you can write the byte code more explicitly by creating your own ByteCodeAppender based on MethodInvocation instances where you have to load the arguments manually however.
You use an instance as interceptor, that means instance methods are prefered (maybe static method are not accepted at all). There is an instance method that matches the signature of your int baz() method, it is int hashCode(). The number you are getting is the hashcode of the new BazInterceptor() instance.
Options i am aware of:
Remove static from barLength that way it will actually be used for interception.
Add the class as interceptor .intercept(MethodDelegation.to(BazInterceptor.class))
I would prefer the second option as you are not using any fields/state of the BazInterceptor instance.

Java for loop optimizations

What sort of optimizations would Java Runtime perform on the follow snippet of code? The bytecode doesn't reveal any optimization however I feel that Java should take the last value of the for loop without running the entire for loop since String is a rudimentary Java class.
NOTE. this question was asked on a class test; however, I couldn't provide enough evidence to back my claim.
public class Main {
public static void main(String[] args) {
String str = null;
for (long i = 0; i < 10000000000L; i++) {
str = new String("T");
}
System.out.println(str);
}
}
While I can't speak to exactly what the jit compiler is doing, the optimization you are asking it to do (to determine that it is safe to skip the loop body entirely) is actually extremely difficult to do, and so I highly doubt it it is done. This is true regardless of String being a "rudimentary Java class".
To understand better, first let's assume that instead of String, we are creating instances of an arbitrary class Foo. It would only be safe to skip the creation of all those Foo objects if we knew two things: that calling new Foo() didn't have any observable side effects; and that no references to Foo "escaped" the loop body.
An observable side effect would be something like setting the value of a static member (e.g. if the Foo class kept a static count of all the times Foo() had been called). An example of a reference escaping would be if the this variable inside of Foo() was passed somewhere else.
Note that it isn't enough to just look at Foo(), you need to look at Foo's superclass' constructor (and all the way up the chain to Object). And then you need to look at all the code that gets executed upon initialization of each of those objects. And then look at all the code that gets called by that code. That would be a tremendous amount of analysis to do "just-in-time".
public class Foo extends Bazz{
static int count = 0;
public Foo(){
// Implicit call to Bazz() has side effect
count++; // side effect
Bazz.onNewFoo(this); // reference escaping
}
Bazz bazz = new Bazz(); // side effect
{
Bazz.onNewBazz(this.bazz); // reference escaping
}
}
class Bazz{
static int count = 0;
static List<Foo> fooList = new LinkedList<>();
static List<Bazz> bazzList = new LinkedList<>();
static void onNewFoo(Foo foo){
fooList.add(foo);
}
static void onNewBazz(Bazz bazz){
bazzList.add(bazz);
}
public Bazz(){
count++;
}
}
You might think we should just let javac do this analysis and optimization for us. The problem with that is, that there is no way to guarantee that the version of Foo() that was on the classpath at compile-time will be the same as that which is on the classpath at run-time. (Which is a very valuable feature of Java - it allows me to move my application from Glassfish to Tomcat without recompiling). So we can't trust analysis done at compile-time.
Finally, realize that String is no different from Foo. We'd still need to run that analysis, and there is no way to do that analysis in advance (which I why I can upgrade my JRE without recompiling my apps)

Does callee knows the caller?

I have a Java utility package, which can be used by multiple services(written in Java) for performing some utility tasks.
Lets say the Java utility package name is U and one of the Service be S. Now S calls a function F of U.
My question is, whether there is a way where function F of package U is able to determine which service S has called it ?
There can be multiple services S1, S2, ... , Sn calling F. I need to know upon a call, which Service Sx is calling that particular F.
You could use something like the following requiring you only to create a function findServiceContainingClass mapping class names to services (or null):
void callee() {
StackTraceElement[] st = new RuntimeException().getStackTrace();
for (int i = 1; i < st.length; i++) {
Service service = findServiceContainingClass(st[i].getClassName());
if (service != null) break;
}
// ... use service
}
However it is deemed bad practice to make code behave differently depending on the caller. I would use such code only as a last resort. (It would be okay to use it in a breakpoint condition during debugging. Maybe that is what you intend.)
Object Oriented programming in Java states that your service is scope for invocation, nothing else (forget static). So there is no normal way to find who is calling instance's method other than passing S instance as argument.
But that does not mean it is impossible.
If you only need to know what is the type of caller, you can use Thread.currentThread().getStackTrace():
StackTraceElement[] elements = Thread.currentThread().getStackTrace()
StackTraceElement caller = elements[elements.length - 2];
printLn(caller.getClassName());
As I said at the beginning it is totally counter objective Java code.
If you need to refer exact instance, you probably should add caller as call parameter. I assume that if you want to refer to caller, callee's code is written by you, so you are able to do it. As for me it would be best choice, because if you need caller in scope of callee, you should pass it directly. Other option is to set caller on ThreadLocal in U, but you don't have confidence that developer will do it each time.
If interface cannot be changed, and U is an interface, you could create U builder object:
public class UBuilder {
public U getS(final S caller) {
Proxy.newProxyInstance(getClass().getClassLoader(), U.class,
new InvocationHandler() {
public Object invoke(Object proxy, Method method,
Object[] args) throws Throwable {
// store caller value on some ThreadLocal variable
try {
method.invoke(proxy, args);
} finally {
// remove caller from ThreadLocal variable
}
}
}
}
}
After that you have additional invocation context (ThreadLocal) referring S instance.
If U is not interface, Javassist, CgLib or something similar would help, but only if invoked method is not static or final.
If F is static or final I see only dramatically hackish answers. Maybe creating own interface imitating U, and forwarding method invocations in InvocationHandler could be some way. Of course S should refer to this interface, not U directly.
Hope it helps.
If there needs to be some service-specific code that is executed by that utility method, I would declare an interface in the utility class and have the services pass in an instance of it to the method.
Here is a contrived example:
public class Utility {
public interface UtilityInterface {
public void specificBehavior( Object arg );
}
public void utilityMethodF( UtilityInterface utilityInterface, Object... args ) {
// perform work with args or whatever
utilityInterface.specificBehavior( null );
// perform work with args or whatever
}
}

Mockito - Feeling that I don't use its full potential

When using Mockito, I only use it to mock out dependencies, i.e. my workflow looks mostly like this:
I have a class with dependencies:
public class C {
public C (A a, B b) {
this.a = a;
this.b = b;
}
public String fooBar() {
return a.foo() + b.bar();
}
}
In my test class, I mock out those dependencies, and tell them which values to return when some specified methods are called:
public class CSpec {
private A a = mock(A.class);
private B b = mock(B.class);
#Test
public itShouldReturnFooBar() {
when(a.foo()).thenReturn("foo");
when(b.bar()).thenReturn("bar");
C c = new C(a, b);
assertThat(c.fooBar().isEqualTo("foobar"));
}
}
(I hope this example is not too simple or too derived ;-)). This works fine, it allows me to test classes (here: C) in isolation. Still, I never use Mockito's verify methods or any other of its features. Is it okay / sufficient to use Mockito this way?
Verify would be typically used to check that your C really calls the A.foo() and B.bar() methods. So you could add
verify(a).foo();
verify(b).foo();
before or after the assertThat. I don't think you need or should use them here but there are several situations where you would need that:
a or b does something that is not visible / reachable from c's public API (for example logging)
You are concerned with the order of execution
You want to make sure that only a.foo and b.bar methods are called, nothing else like a.foo2
You could use those mocks as spy's, so that call to a.foo would be then routed to the aReal.foo
The verify approach is particularly useful in a Tell Don't Ask style of programming.
Consider the following version of your class C:
public class C {
public C(A a, B b, CListener L) { ... }
...
public void foobar() {
String result = complexPrivateMethod(a, b);
L.fooBarred(result);
}
}
Thus, rather than just computing the result, you inform some interested party (e.g. a user interface) about the result.
To test foobar now, you'd want to verify that the listener is correctly invoked:
public class CTest {
#Mock CListener mockListener;
...
#Test itShouldTellCAboutFooBar() {
C c = new C(stubbedA, stubbedB, mockedListener);
...
verify(mockedListener).fooBarred("foobar");
}
}
This use of verify is typical for Test-Driven Development: See Freeman & Pryce's Growing Object-Oriented Software Guided by Tests.
Thus, if you want to use the full potential of Mockito (the question), you most of all need to adopt the corresponding design philosophy in your code.
Yeah, there's no problem with this test, it's perfectly fine. The simple fact the the stubs are being used make the test working, if you remove or change the stubs then the test won't work.
Adding verify statements will just make things redundant in this kind of tests.
However if you precisely want to verify arguments, the order or number of interactions or something else then you definitely want to add checks on the interactions between the tested object and his collaborators.
It is totally ok to use Mockito just this way. But if your code gets more complex you need to do some more things to get your code tested as simple as possible.
Another small example:
public void eitherAorB() {
if(somethingIsTrue) {
a.doSomething();
} else {
b.doSomethingElse();
}
}
You might want to make sure, that the expected method is called on the expected object.
#Test
public doSomethingShouldBeCalledOnA() {
A a = mock(A.class);
C c = new C(a, new B());
c.setSomeThingIsTrue(true);
eitherAorB();
verify(a).doSomething();
}
#Test
public doSomethingElseShouldBeCalledOnB() {
B b = mock(B.class);
C c = new C(new A(), b);
c.setSomeThingIsTrue(false);
eitherAorB();
verify(b).doSomethingElse();
}
In other cases you might want to know which paramater was passed into a method. For that you need an ArgumentCaptor.
Or in some cases you need to call the actual method or use an actual object (no mock), so it is time to spy on an object and capture arguments or verify behavior.
So there is a lot more to Mockito you might need once in a while.
The answers given so far are good, but there are additional features you didn't mention either. The #Mock, #Spy, #InjectMocks annotations are all very useful. Along with the verify(...) methods, there is also the InOrder class to help verify the order of method calls. And perhaps you use the matcher methods already (<T> any(T t), anyString(), etc), but you don't show that you use those facilities.

Categories

Resources