I would like some help on this matter,
Example:
public class A {
private void foo() {
//Who invoked me?
}
}
public class B extends A {}
public class C extends A {}
public class D {
C.foo();
}
This is basically the scenario. My question is how can method foo() know who is calling it?
EDIT: Basically I am trying to do a database Layer, and in class A I will create a method that will generate SQL statements. Such statements are dynamically generated by getting the values of all the public properties of the calling class.
Easiest way is the following:
String className = new Exception().getStackTrace()[1].getClassName();
But in real there should be no need for this, unless for some logging purposes, because this is a fairly expensive task. What is it, the problem for which you think that this is the solution? We may come up with -much- better suggestions.
Edit: you commented as follows:
basically i'am trying to do a database Layer, and in Class A i will create a method that will generate sql statements, such statements are dynamically generated by getting the values of all the public properties of the calling class.
I then highly recommend to look for an existing ORM library, such as Hibernate, iBatis or any JPA implementation to your taste.
Java 9: Stack Walking API
JEP 259 provides an efficient standard API for stack walking that allows easy filtering of, and lazy access to, the information in stack traces. First off, you should obtain an instance of StackWalker:
import static java.lang.StackWalker.Option.RETAIN_CLASS_REFERENCE;
// other imports
StackWalker walker = StackWalker.getInstance(RETAIN_CLASS_REFERENCE);
After that you can call the getCallerClass() method:
Class<?> callerClass = walker.getCallerClass();
Regardless of how you configured the StackWalker instance, the getCallerClass method will ignore the reflection frames, hidden frames and those are related to MethodHandles. Also, this method shouldn't be called on the first stack frame.
Perhaps for your use case it would make sense to pass the class of the caller into the method, like:
public class A { public void foo(Class<?> c) { ... } }
And call it something like this:
public class B { new A().foo(getClass() /* or: B.class */ ); }
foo() is private, so the caller will always be in class A.
if you using slf4j as your application logging system.
you can using:
Class<?> source = org.slf4j.helpers.Util.getCallingClass();
I think it's faster than new Exception().getStackTrace(), since getStackTrace() alaways doing clone stacktrace.
I would use StackWalker
private static Class<?> getCallingClass(int skip) {
StackWalker walker = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE);
Optional<? extends Class<?>> caller = walker.walk(frames ->
frames.skip(skip).findFirst().map(StackWalker.StackFrame::getDeclaringClass)
);
return caller.get();
}
If you need the class of the calling method use skip=1.
From a stack trace: http://www.javaworld.com/javaworld/javatips/jw-javatip124.html
A hacky solution is sun.reflect.Reflection.getCallerClass.
public void foo() {
Class<?> caller = sun.reflect.Reflection.getCallerClass();
// ...
}
It is hacky because you have to ensure that the class that calls Reflection.getCallerClass() is loaded on the bootstrap ClassLoader for the annotation #CallerSensitive (which getCallerClass is tagged with) to work. As such, it probably isn't the best solution for a project unless your project happens to use a Java Agent to add your classes to the bootstrap ClassLoader search.
With the following code, you obtain the first class which generated the stack of calls:
public String getInvonkingClassName(boolean fullClassNameNeeded){
StackTraceElement[] stack = new Exception().getStackTrace();
String className = stack[stack.length-1].getClassName();
if(!fullClassNameNeeded){
int idx = className.lastIndexOf('.');
className = className.substring(idx+1);
}
return className;
}
Boolean argument is used to get the full name including package name, or just class name.
StackFrame
The state of one method invocation on a thread's call stack. As a thread executes, stack frames are pushed and popped from its call stack as methods are invoked and then return. A StackFrame mirrors one such frame from a target VM at some point in its thread's execution.
JVM Stack: From Frame 1 get Frame 2 details
| |
| |
| Class2.function1() [FRAME 1] |
| executing the instructions |
|-------------------------------------------|
|Class1.method1() [FRAME 2] |
| called for execution Class2.function1() |
|-------------------------------------------|
Throwable::getStackTrace and Thread::getStackTrace return an array of StackTraceElement objects, which contain the class name and method name of each stack-trace element.
Throwable::getStackTrace contains the Stack with frames as Frame1(Top Frame) Current method, Frame2 calls Frame1 method for execution.
StackTraceElement[] stackTraceElements = (new Throwable()).getStackTrace();
// Frame1:Log4J.log(), Frame2:CallerClass
Thread::getStackTrace contains the stack with Frames:
Frame1:Thread.getStackTrace(), Frame2:Current Method, Frame3:Caller Method
StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace(); //
sun.misc.SharedSecrets.getJavaLangAccess()
sun.misc.JavaLangAccess javaLangAccess = sun.misc.SharedSecrets.getJavaLangAccess();
StackTraceElement frame = javaLangAccess.getStackTraceElement((new Throwable()), callerFrame-1 ); // Frame0:Log4J.log(), Frame1:CallerClass
System.out.format("SUN - Clazz:%s, Method:%s, Line:%d\n", frame.getClassName(), frame.getMethodName(), frame.getLineNumber());
Throwable throwable = new Throwable();
int depth = javaLangAccess.getStackTraceDepth(new Throwable());
System.out.println("\tsun.misc.SharedSecrets : "+javaLangAccess.getClass() + " - StackTraceDepth : "+ depth);
for (int i = 0; i < depth; i++) {
StackTraceElement frame = javaLangAccess.getStackTraceElement(throwable, i);
System.out.format("Clazz:%s, Method:%s, Line:%d\n", frame.getClassName(), frame.getMethodName(), frame.getLineNumber());
}
JDK-internal sun.reflect.Reflection::getCallerClass method. It is deprecated, removed in Java9 JDK-8021946
Any way by using Reflection API we can't find the Line Number of Function which it get called.
System.out.println("Reflection - Called from Clazz : "+ Reflection.getCallerClass( callerFrame )); // Frame1:Log4J.log(), Frame2:CallerClass
Example:
static boolean log = false;
public static void log(String msg) {
int callerFrame = 2; // Frames [Log4J.log(), CallerClass.methodCall()]
StackTraceElement callerFrameStack = null;
StackTraceElement[] stackTraceElements = (new Throwable()).getStackTrace(); // Frame1:Log4J.log(), Frame2:CallerClass
//StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();// Frame1:Thread.getStackTrace(), Frame2:Log4J.log(), Frame3:CallerClass
int callerMethodFrameDepth = callerFrame; // Caller Class Frame = Throwable:2(callerFrame), Thread.currentThread:2(callerFrame+1)
for (int i = 0; i < stackTraceElements.length; i++) {
StackTraceElement threadFrame = stackTraceElements[i];
if (i+1 == callerMethodFrameDepth) {
callerFrameStack = threadFrame;
System.out.format("Called form Clazz:%s, Method:%s, Line:%d\n", threadFrame.getClassName(), threadFrame.getMethodName(), threadFrame.getLineNumber());
}
}
System.out.println(msg);
if (!log){
Logger logger = Logger.getLogger(callerFrameStack.getClass());
logger.info(msg);
}
}
public static void main(String[] args) {
Log4J.log("Log4J, main");
Clazz1.mc1();
Clazz21.mc12();
Clazz21.mc11();
Clazz21.mc21();
}
}
class Clazz1 {
public static void mc1() {
Log4J.log("Clazz1 - mc1");
}
}
class Clazz11 {
public static void mc11() {
Log4J.log("Clazz11 - mc11");
}
public static void mc12() {
Log4J.log("Clazz11 - mc12");
Clazz1.mc1();
}
}
class Clazz21 extends Clazz11 {
public static void mc21() {
Log4J.log("Clazz21 - mc21");
}
}
For Java 9 use Stack Walking API
I'm just answering this because for some reason the above answers started referring to exception handling - the original question had nothing to do with exceptions.
So, instead of trying to determine the caller of the method in question, and specifically to give more information dealing with the creation of a base class that generates SQL statements for its derived classes, here is an OO solution...
Make the base class abstract and include abstract methods that return the data it needs to build a sql statement.
This would include methods like...
getColumnList()
getFromTable()
getJoinedTables()
getFilterColumns()
The base class then does not care who is calling it because it is going to call up to the derived class for all the details it needs to create the SQL statement.
The base class knows the derived classes are going to provide the implementation of these methods because they are abstract.
Another way to implement this would be to have a SQLGenerator class that receives an interface with the methods described above and operates on the instances passed to it via those methods. For this, you would want to have the abstract methods described above moved into the interface, which all of your SQL related classes would implement.
List item
I tried this and it works well. It is because each Java Object has access to getClass() method which returns the class caller and the method name.
public Logger logger() {
return Logger.getLogger(getClass().toString());
}
example usage:
public DBTable(String tableName) {
this.tableName = tableName;
loadTableField();
this.logger().info("done");
}
sample output log using java.util.logging.Logger
Feb 01, 2017 11:14:50 PM rmg.data.model.DBTable (init) INFO: done
Maybe an answer is
public class CallerMain {
public void foo(){
System.out.println("CallerMain - foo");
System.out.println(this.getClass()); //output- callerMain
}
public static void main(String[] args) {
A a = new A();
CallerMain cm = new CallerMain();
cm.foo();
}
}
class A{
public void foo(){
System.out.println("A - foo");
System.out.println(this.getClass());//output- A
}
}
Related
I'm trying to override a private method on a Java class using meta programming. The code looks something like this:
// Java class
public class MyClass{
private ClassOfSomeSort property1;
private ClassOfSomeOtherSort property2;
public void init(){
property1 = new ClassOfSomeSort();
property2 = new ClassOfSomeOtherSort();
doSomethingCrazyExpensive();
}
private void doSomethingCrazyExpensive(){
System.out.println("I'm doing something crazy expensive");
}
}
// Groovy class
public class MyClassTest extends Specification{
def "MyClass instance gets initialised correctly"(){
given:
ExpandoMetaClass emc = new ExpandoMetaClass( MyClass, false )
emc.doSomethingCrazyExpensive = { println "Nothing to see here..." }
emc.initialize()
def proxy = new groovy.util.Proxy().wrap( new MyClass() )
proxy.setMetaClass( emc )
when:
proxy.init()
then:
proxy.property1 != null
proxy.property2 != null
}
}
The problem is that the overridden implementation of doSomethingCrazyExpensive isn't called - I think that this is because the private method is called by the init() method internally and not called through the metaClass. If I call myProxy.doSomethingCrazyExpensive() directly, the overridden method is invoked, so the meta-programming does work to some degree.
Is there a way to use meta programming to override a method on a Java class (or instance) in such a way that the overridden implementation is called when it is invoked internally?
Groovy as operator is quite powerful, and can create proxies out of concrete types whose changes are visible in Java. Sadly, seems like it can't override private methods, though i managed to change a public method:
Java class:
public class MyClass{
public void init(){
echo();
doSomethingCrazyExpensive();
}
public void echo() { System.out.println("echo"); }
private void doSomethingCrazyExpensive(){
System.out.println("I'm doing something crazy expensive");
}
}
Groovy test:
class MyClassTest extends GroovyTestCase {
void "test MyClass instance gets initialised correctly"(){
def mock = [
doSomethingCrazyExpensive: { println 'proxy crazy' },
echo: { println 'proxy echo' }
] as MyClass
mock.init()
mock.doSomethingCrazyExpensive()
}
}
It prints:
proxy echo
I'm doing something crazy expensive
proxy crazy
So the public method got intercepted and changed, even when being called from Java, but not the private one.
You cannot override a method called from Java code in Groovy using metaClass.
That's why you won't be able to "mock" the call to this private method in Java: it is being called by the Java class itself, not from Groovy.
This limitation wouldn't apply, of course, if your class was written in Groovy.
I would suggest that you refactor the Java class if you can so that you can use normal means to mock the expensive method call. Or even make the method protected, then override it in a sub-class.
I stumbled on this question and thought I should provide a different answer: Yes you can override an existing method - you just have to change the meta class to ExpandoMetaClass.
This happens automatically when you add your first method, for example.
Here's an example:
println ""
class Bob {
String name
String foo() { "foo" }
void print() { println "$name = ${foo()} ${fum()} metaclass=${Bob.metaClass}"}
def methodMissing(String name, args) { "[No method ${name}]" }
}
new Bob(name:"First ").print()
Bob.metaClass.fum = {-> "fum"}
new Bob(name:"Second").print()
Bob.metaClass.fum = {-> "fum"}
new Bob(name:"Third ").print()
Bob.metaClass.foo = {-> "Overriden Foo"}
new Bob(name:"Fourth").print()
The results are:
First = foo [No method fum] metaclass=org.codehaus.groovy.runtime.HandleMetaClass#642a7222[groovy.lang.MetaClassImpl#642a7222[class Bob]]
Second = foo fum metaclass=groovy.lang.ExpandoMetaClass#21be3395[class Bob]
Third = foo fum metaclass=groovy.lang.ExpandoMetaClass#21be3395[class Bob]
Fourth = Overriden Foo fum metaclass=groovy.lang.ExpandoMetaClass#21be3395[class Bob]
You can see after the fum method was added the meta class changed to an expando. Now when the attempt is made to override the original foo - it works.
It seems you can't use Groovy metaprogramming to replace methods of Java classes - even public methods - try the following in the Groovy console to confirm:
ArrayList.metaClass.remove = { obj ->
throw new Exception('remove')
}
ArrayList.metaClass.remove2 = { obj ->
throw new Exception('remove2')
}
def a = new ArrayList()
a.add('it')
// returns true because the remove method defined by ArrayList is called,
// i.e. our attempt at replacing it above has no effect
assert a.remove('it')
// throws an Exception because ArrayList does not define a method named remove2,
// so the method we add above via the metaClass is invoked
a.remove2('it')
If you can modify the source code of MyClass, I would either make doSomethingCrazyExpensive protected, or preferably, refactor it so that it's more test-friendly
public class MyClass {
private ClassOfSomeSort property1;
private ClassOfSomeOtherSort property2;
private CrazyExpensive crazyExpensive;
public MyClass(CrazyExpensive crazyExpensive) {
this.crazyExpensive = crazyExpensive;
}
public void init(){
property1 = new ClassOfSomeSort();
property2 = new ClassOfSomeOtherSort();
crazyExpensive.doSomethingCrazyExpensive();
}
}
public interface CrazyExpensive {
public void doSomethingCrazyExpensive();
}
After making the changes above, when testing MyClass you can easily instantiate it with a mock/stub implementation of CrazyExpensive.
This is a question from this book: https://www.cl.cam.ac.uk/teaching/0506/ConcSys/cs_a-2005.pdf page 28
Can you write an additional Java class which creates an
object that, when passed to the test method causes it to
print “Here!”? As I say in the code, editing the class A
itself, or using library features like reflection, serialization,
or native methods are considered cheating! I’ll provide
some hints in lectures if nobody can spot it in a week or
so. None of the PhD students has got it yet.
public class A {
// Private constructor tries to prevent A
// from being instantiated outside this
// class definition
//
// Using reflection is cheating :-)
private A() {
}
// ’test’ method checks whether the caller has
// been able to create an instance of the ’A’
// class. Can this be done even though the
// constructor is private?
public static void test(Object o) {
if (o instanceof A) {
System.out.println("Here!");
}
}
}
I know the question is a lot unclear. I can think of many different 'hack-ish' solutions but not sure if they will be counted as 'cheating' or not :)
I can't find the official answer so asking you for what would be a good answer.
If we consider that nesting class A does not "modify it" (as, technically, all lines of code are intact) then this solution is probably the only valid option:
class B
{
static
public class A {
// Private constructor tries to prevent A
// from being instantiated outside this
// class definition
//
// Using reflection is cheating :-)
private A() {
}
// ’test’ method checks whether the caller has
// been able to create an instance of the ’A’
// class. Can this be done even though the
// constructor is private?
public static void test(Object o) {
if (o instanceof A) {
System.out.println("Here!");
}
}
}
public static void main (String[] args) throws java.lang.Exception
{
A.test(new A());
}
}
What I mean is, technically it follows all the rules:
Can you write an additional Java class which creates an object that, when passed to the test method causes it to print “Here!”? - Done
As I say in the code, editing the class A itself ... considered cheating! - Technically, the class is unedited. I copy pasted it into my code.
... or using library features like reflection, serialization, or native methods are considered cheating! - Done
If, however, you decide that nesting class A should not be allowed, then I believe there is no proper solution to the problem given the current definition. Also, given the section of the book this task is given in, I bet that the author wanted to make the constructor protected but not private.
Somehow, I don't like this sort of questions. It's from a lecture back in 2005, and according to websearches, it seems that nobody has found "the" solution until now, and no solution has been published.
The constraints are clear, but the question of what is allowed or not is somewhat fuzzy. Every solution could be considered as "cheating", in one or the other way, because a class with a private constructor is not meant to be subclassed. That's a critical security mechanism, and the responsible engineers are working hard to make sure that this security mechanism cannot be trivially circumvented.
So of course, you have to cheat in order to solve this.
Nevertheless, I spent quite a while with this, and here's how I eventually cheated it:
1.) Download the Apache Bytecode Engineering Library, and place the bcel-6.0.jar in one directory.
2.) Create a file CreateB.java in the same directory, with the following contents:
import java.io.FileOutputStream;
import org.apache.bcel.Const;
import org.apache.bcel.generic.*;
public class CreateB
{
public static void main(String[] args) throws Exception
{
ClassGen cg = new ClassGen("B", "A", "B.java",
Const.ACC_PUBLIC | Const.ACC_SUPER, new String[] {});
ConstantPoolGen cp = cg.getConstantPool();
InstructionList il = new InstructionList();
MethodGen method = new MethodGen(Const.ACC_PUBLIC, Type.VOID,
Type.NO_ARGS, new String[] {}, "<init>", "B", il, cp);
il.append(InstructionFactory.createReturn(Type.VOID));
method.setMaxStack();
method.setMaxLocals();
cg.addMethod(method.getMethod());
il.dispose();
cg.getJavaClass().dump(new FileOutputStream("B.class"));
}
}
3.) Compile and execute this class:
javac -cp .;bcel-6.0.jar CreateB.java
java -cp .;bcel-6.0.jar CreateB
(note: On linux, the ; must be a :). The result will be a file B.class.
4.) Copy the class that was given in the question (verbatim - without any modification) into the same directory and compile it.
5.) Create the following class in the same directory, and compile it:
public class TestA
{
public static void main(String[] args)
{
A.test(new B());
}
}
6.) The crucial step: Call
java -Xverify:none TestA
The output will be Here!.
The key point is that the CreateB class creates a class B that extends A, but does not invoke the super constructor. (Note that an implicit super constructor invocation would normally be added by the compiler. But there's no compiler involved here. The bytecode is created manually). All this would usually fail with a VerifyError when the class is loaded, but this verification can be switched off with -Xverify:none.
So in summary:
The class A itself is not edited (and also its byte code is not edited, I hope this is clear!)
No reflection
No serialization
No custom native methods
There are a few options here:
Create a class:
public class Y extends A {
public static void main(String[] args) throws Exception {
X.test(new Y());
}
}
And then edit the bytecode and remove the call to X.. Of course this violates the JVM specification and has to be run with -Xverify:none as said above. This is essentially the same as the one #Marco13.
Option 2:
import sun.misc.Unsafe;
public class Y extends A {
public static void main(String[] args) throws Exception {
Unsafe uf = Unsafe.getUnsafe();
X.test((X) uf.allocateInstance(X.class));
}
}
Compile the code and run it by putting your classpath in the sysloader (otherwise it won't work):
$ java -Xbootclasspath/p:. Y
Both work for me :) Of course, they are both cheating. The first option isn't Java. The second is, well, evil :)
If I find out another way, I'll post it :)
In any case this can't be done without low-level tricks. The JVM Specification explicitly prohibits the creation of an object without calling the constructor as the object in the stack is uninitialized. And the JVM Specification explicitly prohibits not calling the super constructor. And the JVM Specification explicitly requires verification of access protection.
Still funny, though :)
Java can support unicode class name:)
The A in "if (o instanceof A)" could be different from the A in "public class A"
For example, the code below will print "Here!" instead of "bad".
A.java
public class A {
// Private constructor tries to prevent A
// from being instantiated outside this
// class definition
//
// Using reflection is cheating :-)
private A() {
// A: U+0041
}
// ’test’ method checks whether the caller has
// been able to create an instance of the ’A’
// class. Can this be done even though the
// constructor is private?
public static void test(Object o) {
if (o instanceof А) {
System.out.println("Here!");
}
}
}
А.java
public class А {
// A: U+0410, not A: U+0041
}
Main.java
public class Main {
public static void main(String[] args) {
A.test(new А());
}
}
I have a question. I have multiple classes in a package: Let's say package is
com.myPackage.first
And this package has the following classes:
firstGood
secondGood
thirdBad
fourthGood
Each of these classes have a method with the same name but different implementation. So say each have a one particular function called:
public void runMe(){
}
For now I want to come up with a way to given a class name, it'll go inside the class and run that particular method.
So conceptually, my method will look like those:
ArrayList<Class> classList ; // where classList is a list of classes I want to run
public void execute(){
for(Class c : classList){
// Go inside that class, (maybe create an intance of that class) and run the method called run me
}
}
or
public void execute(Class c, String methodToRun){
for(Class c : classList){
// Go inside that class, (maybe create an intance of that class) and run the method called run me
}
}
For now. what I have been able to do is get the name of the classes I want to run the
runMe()
method. So I have been able to come with a way to get the arraylist of classes I want to run. So what I need help with is coming up with a method such that it takes a class name and run the method I want it to. Any help is appreciated. Thanks
I suggest having a look at Class.forName ( ... ) to get the class object, Class.newInstance(); if your classes have a default constructor (or Class.getDeclaredConstructor(...) otherwise) to create a new instance and then Class.getDeclaredMethod( ... ) to find the method and invoke it.
All of this without any regard if your idea is really a good one, since I really didn't quite understand WHY you want to do what you want to do...
interface Me {
void runMe();
}
Then let all classes implement Me.
And have a list of Mes
List<Class<Me>> ...
Then
void test(Class<Me> cl) {
Me me = cl.newInstance();
me.runMe();
}
My adage is always use reflection to solve a problem - now you have two problems. In view of that have you considered a simple pattern like this:
interface Runner {
public void runMe();
}
static abstract class BaseRunner implements Runner {
public BaseRunner() {
// Automagically register all runners in the RunThem class.
RunThem.runners.add(this);
}
}
class FirstGood extends BaseRunner implements Runner {
#Override
public void runMe() {
System.out.println(this.getClass().getSimpleName() + ":runMe");
}
}
class SecondGood extends BaseRunner implements Runner {
#Override
public void runMe() {
System.out.println(this.getClass().getSimpleName() + ":runMe");
}
}
static class RunThem {
static final Set<Runner> runners = new HashSet<>();
static void runThem() {
for (Runner r : runners) {
r.runMe();
}
}
}
public void test() {
Runner f = new FirstGood();
Runner s = new SecondGood();
RunThem.runThem();
}
Here all of your runMe objects extend a base class whose constructor installs the object in a Set held by the class that calls their runMe methods.
inline
void execute() throws Exception{
for (Class<?> c : classesList)
{
//If you don't already have an instance then you need one
//note if the method is static no need for any existing instance.
Object obj = Class.forName(c.getName());
// name of the method and list of arguments to pass
Method m = c.getDeclaredMethod(methodName,null);
//method accessibility check
if(!m.isAccessible())
m.setAccessible(true);
//invoke method if method with arguements then pass them as new Object[]{arg0...} instead of null
//if method is static then m.innvoke(null,null)
m.invoke(obj, null);
}
}
I would recommend using an Interface that defines the runMe() method and then have all your classes implement that interface. Then you would have a list of this Interface:
List<MyInterface> classes = new ArrayList<MyInterface>();
Then you could easily iterate over it and invoke "runMe()" on all of them or if you only want to invoke it for instances of a certain class you could do it like this:
public void execute(Class classForWhichToExecute) {
for (MyInterface myInterface : classes) {
if (classForWhichToExecute.isAssignableForm(myInterface)) {
myInterface.runMe();
}
}
}
Of course this wouldn't work if your method is a static method - so adding more information from your side would help.
I would suggest to use an interface with a common method to override in each class. So that any class can be casted to interface and use its method to execute the method.
interface GoodAndBad{
public void runMe();
}
Implemented class
class FirstGood implements GoodAndBad{
#override
public void runMe(){
// Code to be executed
}
}
You can use execute() method as follows
public void execute(List<GoodAndBad> classList){
for(GoodAndBad c : classList){
c.runMe();
// Go inside that class, (maybe create an intance of that class) and
// run the method called run me
}
}
Change the Class to GoodAndBad interface to change the other method too.
This is loosely coupling objects to support favor over composition in Java Object Oriented Design Patterns.
Never use Strings of method names to execute a method at anytime. There are plenty of other cool solutions for that using design patterns.
I am writing a JUnit test for code submitted to a competition. The rules of the competition require that certain methods not be called from other methods. (I unfortunately can not change the rules.)
The contestants are all implementing an interface we supplied which includes an add(K key, V value) method and a delete(K key) method. We need to test that entries do not implement delete by adding every other element to a new object and return that object.
We are also trying to avoid adding dependencies outside of the Java core since we are using a lot of automated tools (like the Marmoset Project) to test the hundreds of submissions.
I read through the documentation for Java Reflection and Instrumentation and nothing jumped out at me.
We are using Java 8 if it makes a difference.
AspectJ compile time weaving will probably be your best bet.
You will need to recompile the code with aspectj compiler and add advice to intercept the call.
If you give me more details I can show some example code.
You probably want a mocking library, and to use a "spy" test object. Using Mockito it might look something like this.
eg.
import static org.mockito.Mockito.*;
public class Test {
#Spy
ClassUnderTest classUnderTest;
#Before
public void init() {
MockitoAnnotations.initMocks(this);
}
#Test
public void deleteNeverCalled() {
// given
String key = randomString();
String value = randomString();
// when
classUnderTest.add(key, value)
// then
verify(classUnderTest, never()).delete(any());
}
}
This was my solution in the end. It looks like in the original question, I did not mention that this was a binary tree, so the compareTo function would be used constantly.
I created an Exception we could throw in our test framework and then detect.
public static class NotAllowedException extends RuntimeException
I created a new type that would have a flag that could be set to true by the testing framework before calling delete.
/**
* This class uses reflection to check whether {#link compareTo()} is being
* called inside the add method after the test decides it is done with the
* add method.
* It will throw a {#link NotAllowedException}.
*
* #author yakatz <email#domain.com>
*/
private class MyIntWrapper {
private boolean doneAdding = false;
public void doneAdding() {
this.doneAdding(true);
}
public void doneAdding(boolean b) {
this.doneAdding = b;
}
private class MyInteger implements Comparable<MyInteger> {
private Integer value;
public MyInteger(int value) {
this.value = value;
}
#Override
public int compareTo(MyInteger o) {
if (MyIntWrapper.this.doneAdding) {
StackTraceElement[] causes = Thread.currentThread().getStackTrace();
for (StackTraceElement cause : causes) {
if (cause.getClassName().equals("tree.Node") && cause.getMethodName().equals("add")) {
throw new NotAllowedException();
}
}
}
return this.value.compareTo(o.value);
}
}
}
I can then use the class in tests like this:
MyIntWrapper mir = new MyIntWrapper();
Tree<MyIntWrapper.MyInteger, String> tree = new Tree();
// Add stuff to the tree
mir.doneAdding();
MyIntWrapper.MyInteger mi = mir.new MyInteger(1);
tree = tree.delete(mi); // Will throw NotAllowedException if add() is called
I'm trying to override a private method on a Java class using meta programming. The code looks something like this:
// Java class
public class MyClass{
private ClassOfSomeSort property1;
private ClassOfSomeOtherSort property2;
public void init(){
property1 = new ClassOfSomeSort();
property2 = new ClassOfSomeOtherSort();
doSomethingCrazyExpensive();
}
private void doSomethingCrazyExpensive(){
System.out.println("I'm doing something crazy expensive");
}
}
// Groovy class
public class MyClassTest extends Specification{
def "MyClass instance gets initialised correctly"(){
given:
ExpandoMetaClass emc = new ExpandoMetaClass( MyClass, false )
emc.doSomethingCrazyExpensive = { println "Nothing to see here..." }
emc.initialize()
def proxy = new groovy.util.Proxy().wrap( new MyClass() )
proxy.setMetaClass( emc )
when:
proxy.init()
then:
proxy.property1 != null
proxy.property2 != null
}
}
The problem is that the overridden implementation of doSomethingCrazyExpensive isn't called - I think that this is because the private method is called by the init() method internally and not called through the metaClass. If I call myProxy.doSomethingCrazyExpensive() directly, the overridden method is invoked, so the meta-programming does work to some degree.
Is there a way to use meta programming to override a method on a Java class (or instance) in such a way that the overridden implementation is called when it is invoked internally?
Groovy as operator is quite powerful, and can create proxies out of concrete types whose changes are visible in Java. Sadly, seems like it can't override private methods, though i managed to change a public method:
Java class:
public class MyClass{
public void init(){
echo();
doSomethingCrazyExpensive();
}
public void echo() { System.out.println("echo"); }
private void doSomethingCrazyExpensive(){
System.out.println("I'm doing something crazy expensive");
}
}
Groovy test:
class MyClassTest extends GroovyTestCase {
void "test MyClass instance gets initialised correctly"(){
def mock = [
doSomethingCrazyExpensive: { println 'proxy crazy' },
echo: { println 'proxy echo' }
] as MyClass
mock.init()
mock.doSomethingCrazyExpensive()
}
}
It prints:
proxy echo
I'm doing something crazy expensive
proxy crazy
So the public method got intercepted and changed, even when being called from Java, but not the private one.
You cannot override a method called from Java code in Groovy using metaClass.
That's why you won't be able to "mock" the call to this private method in Java: it is being called by the Java class itself, not from Groovy.
This limitation wouldn't apply, of course, if your class was written in Groovy.
I would suggest that you refactor the Java class if you can so that you can use normal means to mock the expensive method call. Or even make the method protected, then override it in a sub-class.
I stumbled on this question and thought I should provide a different answer: Yes you can override an existing method - you just have to change the meta class to ExpandoMetaClass.
This happens automatically when you add your first method, for example.
Here's an example:
println ""
class Bob {
String name
String foo() { "foo" }
void print() { println "$name = ${foo()} ${fum()} metaclass=${Bob.metaClass}"}
def methodMissing(String name, args) { "[No method ${name}]" }
}
new Bob(name:"First ").print()
Bob.metaClass.fum = {-> "fum"}
new Bob(name:"Second").print()
Bob.metaClass.fum = {-> "fum"}
new Bob(name:"Third ").print()
Bob.metaClass.foo = {-> "Overriden Foo"}
new Bob(name:"Fourth").print()
The results are:
First = foo [No method fum] metaclass=org.codehaus.groovy.runtime.HandleMetaClass#642a7222[groovy.lang.MetaClassImpl#642a7222[class Bob]]
Second = foo fum metaclass=groovy.lang.ExpandoMetaClass#21be3395[class Bob]
Third = foo fum metaclass=groovy.lang.ExpandoMetaClass#21be3395[class Bob]
Fourth = Overriden Foo fum metaclass=groovy.lang.ExpandoMetaClass#21be3395[class Bob]
You can see after the fum method was added the meta class changed to an expando. Now when the attempt is made to override the original foo - it works.
It seems you can't use Groovy metaprogramming to replace methods of Java classes - even public methods - try the following in the Groovy console to confirm:
ArrayList.metaClass.remove = { obj ->
throw new Exception('remove')
}
ArrayList.metaClass.remove2 = { obj ->
throw new Exception('remove2')
}
def a = new ArrayList()
a.add('it')
// returns true because the remove method defined by ArrayList is called,
// i.e. our attempt at replacing it above has no effect
assert a.remove('it')
// throws an Exception because ArrayList does not define a method named remove2,
// so the method we add above via the metaClass is invoked
a.remove2('it')
If you can modify the source code of MyClass, I would either make doSomethingCrazyExpensive protected, or preferably, refactor it so that it's more test-friendly
public class MyClass {
private ClassOfSomeSort property1;
private ClassOfSomeOtherSort property2;
private CrazyExpensive crazyExpensive;
public MyClass(CrazyExpensive crazyExpensive) {
this.crazyExpensive = crazyExpensive;
}
public void init(){
property1 = new ClassOfSomeSort();
property2 = new ClassOfSomeOtherSort();
crazyExpensive.doSomethingCrazyExpensive();
}
}
public interface CrazyExpensive {
public void doSomethingCrazyExpensive();
}
After making the changes above, when testing MyClass you can easily instantiate it with a mock/stub implementation of CrazyExpensive.