I have this chained method call
Integer.parseInt(A.get().getC().getD().toString());
I need to make this with reflection. I know that I can use Class.forName(String class) and then invoke methods, but how do I save method results so I can call that chain.
Classes:
public class A
{
public static B get() { return new B(); }
}
public class B
{
public C getC() { return new C();}
}
public class C
{
public C getD() { return new D();}
}
Suppose we have this classes:
public class A {
public B getB() { return new B(); }
public static B getBStatic() { return new B(); }
}
public class B { public C getC() { return new C();}}
public class C { public String getD() { return "done"}}
Example 1:
public static void main(String[] args) throws Exception {
Class<A> clazz = A.class;
Constructor<A> constructor = clazz.getConstructor();
A instance = constructor.newInstance();
Method getMethod = clazz.getDeclaredMethod("getB");
Object b = getMethod.invoke(instance);
Method getCMethod = b.getClass().getDeclaredMethod("getC");
Object c = getCMethod.invoke(b);
Method getDMethod = c.getClass().getDeclaredMethod("getD");
String d = (String) getDMethod.invoke(c);
System.out.println(d); // done
}
Example 2:
public static void main(String[] args) throws Exception {
reflection(new A(), "getB", "getC", "getD"); // invoke non static methods
reflection(new A(), "getBStatic", "getC", "getD"); // invoke static and nonstatic methods
reflection(A.getBStatic(), "getC", "getD"); // provide object from static method
reflection(invokeStaticMethod(A.class, "getBStatic"), "getC", "getD"); // invoke static method without instance
}
public static Object invokeStaticMethod(Class<?> clazz, String methodName) throws Exception {
return clazz.getMethod(methodName).invoke(clazz);
}
public static void reflection(Object instance, String... methods) throws Exception {
Object item = instance;
for (String methodName : methods) {
item = item.getClass().getDeclaredMethod(methodName).invoke(item);
}
System.out.println(item); // done
}
Related
How do I send the variable from main method to the Method A, and what Parameter should I pass within A(), in method B.
Code:
public class MethodCall {
public void A(String c) {
System.out.println(c);
}
public void B() {
A(); // What parameter do I pass here. method B is dependent on A
}
#Test
public void D() {
B();
MethodCall mc = new MethodCall();
mc.A("Hello");
}
}
In method A you expect one parameter of type String therefore you have to provide a parameter for String can be just an empty String "" or null.
Another option depending on your use case; you could use varargs:
public void a(String... varargs) {...}
In this case it's possible to give zero or multiple parameters of type String.
So this works:
a("Hello World");
this:
a();
But also this:
a("Hello", "World");
Or you could just pass all parameters necessary for A through B:
public class MethodCall {
public void A(String c) {
System.out.println(c);
}
public void B(String c) {
A(c);
}
#Test
public void D() {
MethodCall mc = new MethodCall();
mc.B("Hello World");
mc.A("Hello");
}
}
You should pass the String parameter for within A(), in method B.
public class MethodCall {
public void A(String c) {
System.out.println(c);
}
public void B() {
A("Pass the String parameter");
}
public static void main(String[] args) {
// TODO Auto-generated method stub
MethodCall mc = new MethodCall();
mc.A("Hello");
mc.B();
}
}
when you passing the String type as a parameter its mean you should use to same data type when you giving the value to the parameter. you cant use any other types like Integer, float etc. you just need to pass the String value to the given parameter.
When you are using non-static method it cannot call directly. so use
static keyword to call the method in directly.
ANSWER-
public class MethodCall {
public static void A(String c) {
System.out.println(c);
}
public static void B() {
A("HI "); //you can put `null` or `empty`
}
public static void main(String[] args) {
B();
MethodCall mc = new MethodCall();
mc.A("Hello");
}
}
I am not so sure about your question but here is my take:
public class MethodCall {
public void A(String c) {
System.out.println(c);
}
public void B(String s) {
A(s); //If you want to call A() here, then you would have to pass a variable in the parameters of A(), as A() is a parameterized method by definition.
}
public static void main(String[] args) {
// TODO Auto-generated method stub
MethodCall mc = new MethodCall();
mc.A("Hello"); //This part is right, that is how you pass value of a non static function through main method.
}
I'm trying to mock Class D constructor. yet, the mocked objects invokes the real function instead of just returning the value.
Read from bottom.
Main
public abstract class F
{
int hi()
{
throw new Exception("I always throw Exception. So don't execute me");
return 1;
}
}
public abstract class E extends F
{
int hi()
{
return super.hi();
}
}
public class D extends E
{
}
public class C
{
D d_object;
C()
{
d_object = new new D(); // will be mocked_d!
}
int hi()
{
d_object.hi();
}
}
public class B
{
void fun()
{
C object = new C();
int value = object.hi();
}`
}
Test
#RunWith(PowerMockRunner.class)
#PowerMockRunnerDelegate(SpringJunit4ClassRunner.class)
#PrepareForTest({C.class,D.class})
public class Test_B
{
#Autowired
A o_A;
#Test
public void test_method()
{
D mocked_D = mock(D.class);
PowerMockito.whenNew(D.class).withNoArguments().then(new Answer()
{
#Override
public Object answer(InvocationOnMock invocation) throws Throwable
{
return mocked_D;
}
});
PowerMockito.doReturn(2).when(mocked_d).hi();
Assert.assertEquals(2,o_A.fun()) // throws Exception. since method inside class F gets executed.
}
}
hi() method inside class F always gets invoked, hence it throws execution. I don't want to invoke that function. am I doing anything wrong?
When using #PrepareForTest I always use PowerMockito.mockStatic method inside tests.
I have the following code
public class A {
public class B {
}
public boolean wasCreatedFromMe(B obj) {
// I want to implement this method
}
}
public class Test {
public static void main(String[] args) {
A a1 = new A();
A a2 = new A();
B b1 = a1.new B();
a1.wasCreatedFromMe(b1); // true
a2.wasCreatedFromMe(b1); // false
}
}
I would like to implement that method above which determines if the object was created from this Outer Class instance. Is there a way to use instanceof or some type of Class<> magic to do that?
I do NOT want to do any of the following:
Use data structures
// inside class A
Set<B> childObjs = new HashSet<>();
public B() {
childObjs.add(this);
}
Ask inner class object
// inside class A
public boolean wasCreatedFromMe(B obj) {
return obj.parent() == this;
}
class B {
public A parent() {
return A.this;
}
}
I have some generated code (i.e. it cannot be changed) that looks something like this.
class Generated1 {
public String getA() {
return "1";
}
public void setB(String b) {
}
public void setC(String c) {
}
public void setD(String d) {
}
}
class Generated2 {
public String getA() {
return "2";
}
public void setB(String b) {
}
public void setC(String c) {
}
public void setD(String d) {
}
}
I am exploring these objects by reflection. None of them implement any common interface but there's many of them and I want to treat them as if they implement:
interface CommonInterface {
String getA();
void setB(String b);
void setC(String c);
void setD(String d);
}
It certainly should be possible. This is considered perfectly good code
class CommonInterface1 extends Generated1 implements CommonInterface {
// These are perfectly good classes.
}
class CommonInterface2 extends Generated2 implements CommonInterface {
// These are perfectly good classes.
}
I suppose what I'm looking for is something like:
private void doCommon(CommonInterface c) {
String a = c.getA();
c.setB(a);
c.setC(a);
c.setD(a);
}
private void test() {
// Simulate getting by reflection.
List<Object> objects = Arrays.asList(new Generated1(), new Generated2());
for (Object object : objects) {
// What is the simplest way to call `doCommon` with object here?
doCommon(object);
}
}
My question: How do I treat an object that doesn't implement an interface but actually has all the code to do so as if it does implement the interface.
I want to replace
private void doCommon(Generated1 c) {
String a = c.getA();
c.setB(a);
c.setC(a);
c.setD(a);
}
private void doCommon(Generated2 c) {
String a = c.getA();
c.setB(a);
c.setC(a);
c.setD(a);
}
...
with
private void doCommon(CommonInterface c) {
String a = c.getA();
c.setB(a);
c.setC(a);
c.setD(a);
}
I know I can use a Proxy like this but I'd really prefer to use something better.
private void test() {
// Simulate getting by reflection.
List<Object> objects = Arrays.asList(new Generated1(), new Generated2());
for (Object object : objects) {
// What is the simplest way to call `doCommon` with object here?
doCommon(adapt(object));
}
}
private CommonInterface adapt(Object o) {
return adapt(o, CommonInterface.class);
}
public static <T> T adapt(final Object adaptee,
final Class<T>... interfaceToImplement) {
return (T) Proxy.newProxyInstance(
adaptee.getClass().getClassLoader(),
interfaceToImplement,
// Call the equivalent method from the adaptee.
(proxy, method, args) -> adaptee.getClass()
.getMethod(method.getName(), method.getParameterTypes())
.invoke(adaptee, args));
}
If you're using reflection, you don't need the two CommonInterfaceX classes, you can use a proxy implementing CommonInterface:
public class Wrapper implements InvocationHandler {
private final Object delegate;
public static <T> T wrap(Object obj, Class<T> intf) {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
Object proxy = Proxy.newProxyInstance(cl, new Class<?>[] {intf},
new Wrapper(obj));
return intf.cast(proxy);
}
private Wrapper(Object delegate) {
this.delegate = delegate;
}
#Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Method dmethod = delegate.getClass().getMethod(
method.getName(), method.getParameterTypes());
return dmethod.invoke(delegate, args);
}
}
You can use this class as follows:
List<Object> objects = Arrays.asList(new Generated1(), new Generated2());
for (Object object : objects) {
CommonInterface proxy = Wrapper.wrap(object, CommonInterface.class);
doCommon(proxy);
}
UPDATE: note that the same Wrapper class works with any interface.
There's no way to achieve a static type relationship between Generated1 and Generated2.
Even if you created CommonInterface1 and CommonInterface2, you still wouldn't be able to statically use a Generated1 object as a CommonInterface1 because new Generated1() is not a CommonInterface1 (and will never become one)
By far the simplest solution is to change your code generation to add the CommonInterface to Generated1 and Generated2.
If that's absolutely impossible, the only other way to avoid this code duplication is to go for reflection.
You can do it manuallly by reflection.
public class Generated {
public String getA() {
return "A";
}
public String sayHello(String name) {
return "hello " + name;
}
}
public class Helper {
private static final String METHOD_NAME = "getA";
private static final String METHOD_WITH_PARAM_NAME = "sayHello";
public static void main(String[] args) throws Exception {
Generated generated = new Generated();
accessMethod(generated);
accessMethodWithParameter(generated);
}
private static void accessMethod(Generated g) throws Exception {
Method[] methods = g.getClass().getDeclaredMethods();
for(Method method : methods) {
if(isCommonMethod(method)) {
String result = (String) method.invoke(g);
System.out.println(METHOD_NAME + "() = " + result);
}
}
}
private static boolean isCommonMethod(Method m) {
return m.getName().equals(METHOD_NAME) && m.getReturnType().equals(String.class);
}
private static void accessMethodWithParameter(Generated g) throws Exception {
Method[] methods = g.getClass().getDeclaredMethods();
for(Method method : methods) {
if(isCommonMethodWithParameter(method)) {
String result = (String) method.invoke(g, "Max");
System.out.println(METHOD_WITH_PARAM_NAME + "(\"Max\") = " + result);
}
}
}
private static boolean isCommonMethodWithParameter(Method m) {
return m.getName().equals(METHOD_WITH_PARAM_NAME) &&
m.getReturnType().equals(String.class) &&
m.getParameterTypes().length == 1 &&
m.getParameterTypes()[0].equals(String.class);
}
}
Output is
getA() = A
sayHello("Max") = hello Max
If you want to replace as your comment. I think you can do it easily
First, you create interface CommonInterface
interface CommonInterface {
String getA();
void setB(String b);
void setC(String c);
void setD(String d);
}
After that, you create 2 class Generated1 and Generated2 inherited CommonInterface
class Generated1 implements CommonInterface {
#overide
public String getA() {
return "1";
}
#overide
public void setB(String b) {
}
#overide
public void setC(String c) {
}
#overide
public void setD(String d) {
}
}
class Generated2 implements CommonInterface {
#overide
public String getA() {
return "2";
}
#overide
public void setB(String b) {
}
#overide
public void setC(String c) {
}
#overide
public void setD(String d) {
}
}
I am using Mockito/PowerMockito APIs to mock some objects for junit cases.
In the example given below, I want to create a mock object of class C (returned by Utils.getC()). Also I want to use same mock object of C in B.execute(), and not a new object. Is there a way I can achieve this? Please help. [Update - Thanks Lino for answering this. I have edited the code given below.]
However, this works for static methods only. I am not able to mock instance method D.displayMessage() (invoked from A.execute() and B.execute()).
#PrepareForTest(mock.Utils.class)
#RunWith(PowerMockRunner.class)
public class TestMock {
private static C c;
private static D d;
#BeforeClass
public static void runOnceBeforeClass() {
try {
System.out.println("#BeforeClass - runOnceBeforeClass");
PowerMockito.mockStatic(Utils.class);
c = Mockito.mock(C.class);
System.out.println("c = " + c);
PowerMockito.doReturn("Hello!!").when(c).displayMessage();
Answer<Void> answer = new Answer() {
public Void answer(InvocationOnMock invocation) {
System.out.println("I can perform!");
return null;
}
};
PowerMockito.doAnswer(answer).when(c).perform();
PowerMockito.when(Utils.getC()).thenReturn(c);
Answer<Void> answer1 = new Answer() {
public Void answer(InvocationOnMock invocation) {
System.out.println("I can utilize!");
return null;
}
};
PowerMockito.doAnswer(answer1).when(Utils.class);
Utils.utilize();
Answer<Void> answer2 = new Answer() {
public String answer(InvocationOnMock invocation) {
System.out.println("I can run with params!");
return null;
}
};
PowerMockito.doAnswer(answer2).when(Utils.class);
Utils.runWithParams(Mockito.anyString(), Mockito.anyInt(), Mockito.any());
d = PowerMockito.mock(D.class);
PowerMockito.when(d.displayMessage()).thenReturn("D: I can display!");
PowerMockito.whenNew(D.class).withNoArguments().thenReturn(d);
} catch (Exception ex) {
ex.printStackTrace();
}
}
#AfterClass
public static void runOnceAfterClass() {
System.out.println("#AfterClass - runOnceAfterClass");
}
#Before
public void runBeforeTestMethod() {
System.out.println("#After - runBeforeTestMethod");
}
#After
public void runAfterTestMethod() {
System.out.println("#After - runAfterTestMethod");
}
#Test
public void testExecution() {
System.out.println(Utils.getC().displayMessage());
A a = new A();
a.execute();
}
}
class A {
public void execute() {
System.out.println("executing A");
B b = new B();
b.execute();
System.out.println(new D().displayMessage());
}
}
class B {
public void execute() {
System.out.println("executing B");
C c1 = Utils.getC();
System.out.println("c = " + c1.hashCode());
c1.perform();
Utils.utilize();
Utils.runWithParams("", 3, "2");
System.out.println(new D().displayMessage());
}
}
class C {
public String displayMessage() {
return "C: I can't display.";
}
public void perform() {
System.out.println("I can't perform.");
}
}
class D {
public String displayMessage() {
return "D: I can't display.";
}
}
class Utils {
public static C getC() {
return null;
}
public static void utilize() {
System.out.println("I can't unitilize.");
}
public static String runWithParams(String s, Integer i, Object o) {
System.out.println("I can't run with params.");
return "abc";
}
}
If you are trying to reuse the mocked object of C, for the static method call inside execute() method of B , the same mocked object can be reused.