Java, return method as reference - java

Im beginner JAVA developer. Here is a method:
private Method getSomething()
{
for (Method m : getClass().getDeclaredMethods())
{
return m;
}
return notFound;
}
private void notFound()
{
throw new Exception();
}
it doesnt matter what it does - if it finds something, then returns a Method - if not, the notFound() method itself should be returned. So the hot spot is at the return notFound; line: if I use return notFound(); then it returns its value, not the method itself. I want something like a reference/pointer. So getSomething() returns something what can be called, and if the returned method is used wrong, it should trigger that Exception - so its not an option to replace return notFound; with throw new Exception(); !
Or the 2nd option is to create a lambda method....

You need to call
this.getClass().getMethod("notFound")
to get the notFound method of the current/this object's class.
So just do this:
return this.getClass().getMethod("notFound");
More details here:
Class.getMethod
EDIT:
You can retrieve i.e. get and call private methods too via reflection.
Here is an example.
import java.lang.reflect.Method;
public class Test001 {
public static void main(String[] args) throws Exception {
Test002 obj = new Test002();
Method m = obj.getClass().getDeclaredMethod("testMethod", int.class);
m.setAccessible(true);
m.invoke(obj, 10);
m.invoke(obj, 20);
System.out.println(m.getName());
}
}
class Test002 {
private void testMethod(int x){
System.out.println("Hello there: " + x);
}
}

You need to use reflection to achieve this:
http://docs.oracle.com/javase/tutorial/reflect/
e.g. to get all methods of a given class:
Class aClass = ...//obtain class object
Method[] methods = aClass.getMethods();

Related

How to throw exception for a local object method call?

MyCode:
class LocalClass{
public getNumber(){
retunr 5;
}
}
class AnotherLocalClass{
public static getNumber(){
retunr 10;
}
}
public class A{
public int methodAa(Boolean flag, int paramValue){
return methodA(flag, paramValue);
}
private int methodA(Boolean flag, int paramValue){
int returnValue = 0;
try{
if(flag){
LocalClass localVariable = new LocalClass();
returnValue = localVariable.getNumber() + paramValue;
} else{
returnValue = AnotherLocalClass.getNumber() + paramValue;
}
return returnValue;
}catch(Exception e){
e.printStackTrace();
return 0;
}
}
}
public class ATest{
#InjectMocks
A a;
public void methodATest(){
//need help to write here
}
}
LocalClass and AnotherLocalClass are classes that contains a method that returns a value.
getNumber in AnotherLocalClass is a static method.
Class A is the main class for which I am writing ATest class.
I can only write code in methodATest. And cannot change anything in LocalClass, AnotherLocalClass or class A.
I want to write methodATest such that methodA throws an exception.
My mockito version is 1.19.10 and it cannot be changed.
And also I cannot use PowerMockito or any other new dependency.
What exceptions do you expected to occur on your code? Which parameter values will cause the exceptions? In those cases, what is the return value that you're expecting?
When you get the answers for those questions, then you gonna have to set the conditions for the exception to happen. Then your code is gonna look something like this:
public class ATest{
A a = new A();
#Test
public void methodATest(){
Boolean flag = ?;
int paramValue = ?;
int expectedReturnValue = ?;
int returnValue = a.methodAa(flag, paramValue);
assertEquals(expectedReturnValue, returnValue);
}
}
Look out for the mock method. We usually use it when we need to set a class that we don't exactly want it to run it's methods, so we mock then to return something that we need for our test to work.
You can learn more about tests with this tutorial: https://www.vogella.com/tutorials/JUnit/article.html#junittesting
----[Edit]----
If you wanted to mock the LocalClass, you were gonna need to do something like this:
#PrepareForTest({LocalClass.class, A.class})
#RunWith(PowerMockRunner.class)
public class ATest{
A a = new A();
#Test
public void methodATest(){
PowerMockito.mockStatic(LocalClass.class);
PowerMockito.when(LocalClass.getNumber()).thenThrow(new Exception());
...
}
}
But, the getNumber() method should be static for it to work.
And, since you can not use PowerMockito, it's not possible to mock the class.
----[Edit]----
#PrepareForTest({AnotherLocalClass.class, A.class})
#RunWith(PowerMockRunner.class)
public class ATest{
A a = new A();
#Test
public void methodATest(){
PowerMockito.mockStatic(AnotherLocalClass.class);
PowerMockito.when(AnotherLocalClass.getNumber()).thenThrow(new Exception());
a.methodAa(...);
...
}
}
But again, since static method belongs to the class, there is no way in Mockito to mock static methods.

Why getDeclaredMethod with Class as second param throws NoSuchMethodException?

I want to test a private method using reflection. In this case isEdible method from Food class.
public class Food {
private Boolean isEdible() {
return true;
}
}
When I'm using getDeclaredMethod without specifying Food class, it ran successfully.
#Test
public void foodTestOne() throws Exception {
Food food = new Food();
Method method = food.getClass().getDeclaredMethod("isEdible");
method.setAccessible(true);
boolean isEdible = (boolean) method.invoke(food);
assertTrue(isEdible);
}
But when I add Food Class on a second parameter I got NoSuchMethodException.
#Test
public void foodTestTwo() throws Exception {
Food food = new Food();
Method method = food.getClass().getDeclaredMethod("isEdible", Food.class);
// execution stop here
}
My questions are:
What should I put in second parameters to make it work? Changing getDeclaredMethod("isEdible", Boolean.class) still throws the same Exception.
It seems pretty basic and intuitive, why is this happening?
getDeclaredMethod needs to match the argument types that the method expects. When a method takes no arguments (such as isEdible()) you can pass null (or an empty Class[]), for example
public class Food {
private Boolean isEdible() {
return true;
}
public static void main(String[] args) {
Food food = new Food();
try {
Class<?>[] methodArgumentTypes = null; // {};
Object[] methodArguments = null; // new Object[0];
Method method = food.getClass().getDeclaredMethod("isEdible",
methodArgumentTypes);
System.out.println(method.invoke(food, methodArguments));
} catch (Exception e) {
e.printStackTrace();
}
}
}
Will actually invoke isEdible() and output true.
Can be done like this, if method has no parameters:
obj.getClass().getDeclaredMethod(methodName, (Class<?>[]) null).invoke(obj);
Read more...
The issue you are having is that in the line
Method method = food.getClass().getDeclaredMethod("isEdible", Food.class);
You specify Food as a parameter of the method; it is not. Instead, you should have
Method method = food.getClass().getDeclaredMethod("isEdible");
isEdible() is declared private, so you will not be able to access it in the current context, even with getDeclaredMethod. To allow for access, you can set it to accessible before invoking the method.
method.setAccessible(true);
method.invoke(food);

Can we get the value of any getter method by extracting it using Methods[]?

Methods[] method =classname.getClass().getDeclaredMethods();
In the above code, i want to get the value of particular method. Suppose above method will return some getter and setter methods. Can we get the value of any getter methods?
Like PeterMmm said, you can use invoke on Method, passing the object that you want the call to be made on, and any other arguments the method needs, as get methods usually don't have arguments, you can do like this:
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class MethodsTest {
public int getA() {
return 5;
}
public int getB() {
return 8;
}
public static void main(String[] args) {
MethodsTest obj = new MethodsTest();
Method[] methods = obj.getClass().getDeclaredMethods();
for (Method method: methods) {
if (method.getName().startsWith("get"))
try {
System.out.println(method.getName() + ": " + method.invoke(obj));
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
e.printStackTrace();
}
}
}
}
it will print:
getB: 8
getA: 5
hope it helps

How to call a method whose name is the value of a string variable in java?

This is the code of the method that I want to simplify. The method name I call of SerializedExpFamMixture class is exactly the value of "model", my question is how to assign the value of "model" directly as the name of the method instead of using "if" to determine which method I should call. Since by using "if", I need to list all the possible values of "model" and judge which method I should use.
Thank you very much for help. I am new to java.
public static SerializedExpFamMixture RateMtxModel(String model)
{
SerializedExpFamMixture result=new SerializedExpFamMixture();
if(model=="kimura1980()")
result=SerializedExpFamMixture.kimura1980();
if(model=="accordance()")
result=SerializedExpFamMixture.accordance();
if(model=="pair()")
result=SerializedExpFamMixture.pair();
return result;
}
One way you can approach this is to use Reflection:
Method method = myClass.getClass().getMethod("doSomething", null);
method.invoke(myClass, null);
Since you are new to Java, it's time for some general pointers:
In Java, we usually name our methods with camelCase, so the first letter is lower case.
Also, in Java we usually leave the opening curly-bracket on the same line as the code (no newline).
Always use final on your variables. At least your parameters. That way you won't overwrite it, and thus won't have to try to figure out which value it actually has at runtime.
Use curly-brackets! Please!
The result variable is not actually needed.
Use the equals-method to compare Strings.
If you only want one result, use else-if
Fixing these things, your method looks like this:
public static SerializedExpFamMixture rateMtxModel(String model) {
if (model.equals("kimura1980()")) {
return SerializedExpFamMixture.kimura1980();
} else if (model.equals("accordance()")) {
return SerializedExpFamMixture.accordance();
} else if(model.equals("pair()")) {
return SerializedExpFamMixture.pair();
}
return new SerializedExpFamMixture();
}
Next, let's look at what you are actually trying to do here. You want to pass some Strings around, and use them as a basis for creating objects. And now, with the advice given here, you will do this using reflection. This does not sound like a very good idea to me. Say you were to go through with this, and this happened:
rateMtxModel("kinura1980");
Small typo, hard to spot, will give unexpected results. If you were actually calling a method the compiler would let you know that you messed up, now you will get no warning (btw did you see both errors in that method call?). The same if someone were to delete the accordance()-method, the compiler would not alert them that this will break the program.
If it was up to be I would just use the static factory-methods in SerializedExpFamMixture directly, but if you have to do it like this (if the task at hand is using a String input to create an object) I would do something like this:
public enum Something {
KIMURA1980("kimura1980()"),
ACCORDANCE("accordance()"),
PAIR("pair()");
private final String stringValue;
private Something(final String stringValue) {
this.stringValue = stringValue;
}
public static Something fromString(final String string) {
for (final Something something : values()) {
if (something.stringValue.equals(string)) {
return something;
}
}
return null;
}
}
public static SerializedExpFamMixture rateMtxModel(final String model) {
if (model == null) {
throw new IllegalArgumentException("model is null!");
}
final Something something = Something.fromString(model);
if (something == null) {
return new SerializedExpFamMixture();
}
switch(something) {
case KIMURA1980:
return SerializedExpFamMixture.kimura1980();
case ACCORDANCE:
return SerializedExpFamMixture.accordance();
case PAIR:
return SerializedExpFamMixture.pair();
default:
return new SerializedExpFamMixture();
}
}
This way, the one place where you will use the Strings is in the enum, the rest of the code will use the enum constants and thus have the safety of the compiler to rely on.
One could also leave the linking between operation and String to the enum, like this:
interface Operation<T> {
public T run();
}
public enum Something {
KIMURA1980("kimura1980()", new Operation<SerializedExpFamMixture>() {
public SerializedExpFamMixture run() {
return SerializedExpFamMixture.kimura1980();
}
}) ,
ACCORDANCE("accordance()", new Operation<SerializedExpFamMixture>() {
public SerializedExpFamMixture run() {
return SerializedExpFamMixture.accordance();
}
}),
PAIR("pair()", new Operation<SerializedExpFamMixture>() {
public SerializedExpFamMixture run() {
return SerializedExpFamMixture.pair();
}
}),
DEFAULT(null, new Operation<SerializedExpFamMixture>() {
public SerializedExpFamMixture run() {
return new SerializedExpFamMixture();
}
});
private final String stringValue;
private final Operation<SerializedExpFamMixture> operation;
private Something(final String stringValue, final Operation<SerializedExpFamMixture> operation) {
this.stringValue = stringValue;
this.operation = operation;
}
public static Something fromString(final String string) {
if (string != null) {
for (final Something something : values()) {
if (string.equals(something.stringValue)) {
return something;
}
}
}
return DEFAULT;
}
public SerializedExpFamMixture getCorrespondingSerializedExpFamMixture() {
return operation.run();
}
}
With this setup in the enum (I think the Operation-part can be trimmed out with Java8), the method will be as simple as:
public static SerializedExpFamMixture rateMtxModel(String model) {
return Something.fromString(model).getCorrespondingSerializedExpFamMixture();
}
Use reflection, but you need to consider a few things:
Bug alert! Comparing Strings using == doesn't work as expected in java - use .equals() instead. However, the solution below bypasses that problem
For the general case, which includes methods not visible to the invoker, you need to consider accessibility, both in finding the method and invoking it
You don't need the result variable, and even if using your code, don't need to initialize it
Try this:
String methodName = model.replace("(", "").replace(")", "");
try {
// getMethod() returns only public methods, getDeclaredMethod() returns any visibility
Method method = SerializedExpFamMixture.class.getDeclaredMethod(methodName);
// if the method is not guaranteed to be visible (eg public) you need this:
method.setAccessible(true);
return (SerializedExpFamMixture) method.invoke(null); // how to invoke on the class object
} catch (Exception forBrevity) {
return new SerializedExpFamMixture();
}

Java and avoid if statements for objects with similar methods

I have 2 classes e.g. A and B.
These classes have a couple of getter/setter methods with the same name.
Now in the code I do the following:
if(obj.getClassName().equals(A.class.getName())){
A a = (A) obj;
String result = a.getInfo();
}
else if(obj.getClassName().equals(B.class.getName())){
B a = (B) obj;
String result = a.getInfo();
}
I was wondering if there is a way to call the getInfo avoiding the if statements.
Note: I can not refactor the classes to use inheritence or something else.
I was just interested if there is a trick in java to avoid the if statements.
Unless you want to use reflection, no. Java treats two types which happen to declare the same method (getInfo()) as entirely separate, with entirely separate methods.
If you've got commonality, you should be using a common superclass or a common interface that both of them inherit. You've tagged the question "design-patterns" - the pattern is to use the tools that the language provides to show commonality.
As Eng.Fouad shows, using instanceof is simpler anyway - and better, as it means your code will still work with subclasses of A or B.
You can isolate this ugliness, of course, by putting it in a single place - either with a facade class which can be constructed from either an A or a B, or by having a single method which performs this check, and then calling that from multiple places.
If you can't use inheritance and want to avoid if statements (even using instanceof)... well... the best you can do is wrap the check, cast and call in a function to avoid code duplication... otherwise there's no way to do this.
You need reflection. here is my complete example.
Class A
package a;
public class A {
String info;
public String getInfo() {
System.out.println("A getInfo");
return info;
}
public void setInfo(String info) {
this.info = info;
}
}
Class B
package a;
public class B {
String info;
public String getInfo() {
System.out.println("B getInfo");
return info;
}
public void setInfo(String info) {
this.info = info;
}
}
Test Class
package a;
import java.lang.reflect.Method;
public class TestAB {
public static void main(String[] args) {
A a= new A();
doSth(a);
}
private static void doSth(Object obj) {
Class c = obj.getClass();
Method m;
try {
m = c.getMethod("getInfo", new Class[] { });
String result = (String) m.invoke(obj);
} catch (Exception e) {
e.printStackTrace();
}
}
}
See this line :
Class c = obj.getClass();
and
m = c.getMethod("getInfo", new Class[] { });
and
String result = (String) m.invoke(obj);
There is no if statements
If obj is declared as either A or B, you can use overloaded methods. (A good argument for type safety.) Here's a test that illustrates this:
import static org.junit.Assert.*;
import org.junit.Test;
public class FooTest {
class A {
public String getInfo() {
return "A";
}
}
class B {
public String getInfo() {
return "B";
}
}
public String doBarFor(A a) {
return a.getInfo();
}
public String doBarFor(B b) {
return b.getInfo();
}
public String doBarFor(Object obj) {
throw new UnsupportedOperationException();
}
#Test
public void shouldDoBarForA() {
A a = new A();
assertEquals("A", doBarFor(a));
}
#Test
public void shouldDoBarForB() {
B b = new B();
assertEquals("B", doBarFor(b));
}
#Test(expected = UnsupportedOperationException.class)
public void shouldFailIfDeclaredAsObject() {
Object a = new A();
assertEquals("A", doBarFor(a)); // exception thrown
}
}
How about:
String result = null;
if(obj instanceof A)
{
result = ((A) obj).getInfo();
}
else if(obj instanceof B)
{
result = ((B) obj).getInfo();
}
Refer to : this tutorial if this is what you were trying to achieve.
If obj is an Object, you'll need to check. If you don't want to use an if-statement, you can try just casting and catch the exception:
String result = null;
try {
result = ((A)obj).getInfo();
}
catch(ClassCastException e1) {
try {
result = ((B)obj).getInfo();
}
catch(ClassCastException e2) {
// do something else
}
}
Another thing you can do is make both classes implement an Interface then check for just that Interface, something like:
public interface HasInfo
{
public String getInfo();
}
Then add implements HasInfo in the class definition for A and B. Then you can just check (or cast) to HasInfo.
In Java you can use a dot as a scope resolution operator with static methods. Try something like this:
String a_info = A.getInfo();
String b_info = B.getInfo();
With objects, if two interfaces really have the same method with the same parameters and the same return type, why must they be treated differently? Take a look here for some more insight into the problem.
Good luck.

Categories