Invoke SET method in Java by given a String - java

I have a string variable which dependes on "i" variable, i want to call this string, like his method:
String nameSetClassifiedMethod= "setClassficationdesc" + i;
and i wanted something like this:
this.nameSetClassifiedMethod( some parametersIn);
I know this is not possible, because i can't invoke a method with a string like im doing, but i don't know any solutions for this.
I have some code that's whic is not mine, which is doing something like:
if (i == 0) {this.setClassficationdesc0(..)}
if (i == 1) {this.setClassficationdesc1(..)}
if (i == 2) {this.setClassficationdesc2(..)}
So i'm trying to invoke the method by string to reduce complexity

Well you could call the method from a string variable using reflection. But instead, I suggest the following workflow:
String i = "One";
switch (i) {
case "One":
// call setClassficationdescOne(...)
break;
case "Two":
// call setClassficationdescTwo(...)
break;
// ...
}

It is possible. Please search and read the topic "Reflection in Java". In particular look at class Class and in it look at method getMethod. so you can do:
Method method = this.getClass().getMethod(...);
Once you get the method you can invoke it. (See Javadoc for class Method)

In that case you would use reflection by doing something like the following:
String nameSetClassifiedMethod= "setClassficationdesc" + i;
Method method = Operations.class.getDeclaredMethod("nameSetClassifiedMethod", String.class); //here you should adapt it to your method's signature
method.setAccessible(true);
// and then
ClassWhichHoldsReflectedMethod instance = new ClassWhichHoldsReflectedMethod();
method.invoke(instance, params...);
Check this out for more.

If you have a limited number of setClassificationdesc#() methods and you know them upfront, try something like this:
public class YourClass
{
#FunctionalInterface
private interface ClassificationdescSetter
{
public void set( … );
}
private final ClassificationdescSetter [] m_CDSetters;
public YourClass( … )
{
…
m_CDSetters = new ClassificationdescSetters [] {this::setClassificationdesc1, this::setClassificationdesc2, this::setClassificationdesc3, … };
…
}
public final void doSomething( final int i )
{
m_CDSetters [i - 1].set( … );
}
}
Of course, all error handling is missing here!
The interface is obsolete (at least redundant) if the signature for setClassificationdesc#() matches an already existing functional interface. In that case, use the existing interface as the type for m_CDSetters; you may have to use another method as set(), too.

You could use method handles.
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
public class MthdHndl {
public static void main(String[] args) {
MethodHandles.Lookup lookup = MethodHandles.lookup();
int index = 0;
String name = "setClassficationdesc";
MethodType type = MethodType.methodType(String.class, int.class);
try {
MethodHandle mh = lookup.findVirtual(George.class, name + index, type);
int parameter = 2;
String result = (String) mh.invoke(new George(), parameter);
System.out.println(result);
}
catch (Throwable x) {
x.printStackTrace();
}
}
}
class George {
private static final String[] FORTUNE = new String[]{"Long live the revolution!",
"Have a nice day.",
"Behind every argument is someone's ignorance."};
public String setClassficationdesc0(int i) {
return FORTUNE[i];
}
}
Note that since the method being invoked (via MethodHandle) is an instance method, the first parameter to method invoke is the instance on which to invoke the method.

Maybe you're looking for Java 14 Switch Expressions:
int i = // initializing the variable
switch (i) {
case 0 -> this.setClassficationdesc0(..); // perform a side-effect
case 1 -> this.setClassficationdesc1(..); // perform a side-effect
case 2 -> this.setClassficationdesc2(..); // perform a side-effect
}

Related

How to mock according to the number of invocations of method using java and Mockito? [duplicate]

Is there a way to have a stubbed method return different objects on subsequent invocations? I'd like to do this to test nondeterminate responses from an ExecutorCompletionService. i.e. to test that irrespective of the return order of the methods, the outcome remains constant.
The code I'm looking to test looks something like this.
// Create an completion service so we can group these tasks together
ExecutorCompletionService<T> completionService =
new ExecutorCompletionService<T>(service);
// Add all these tasks to the completion service
for (Callable<T> t : ts)
completionService.submit(request);
// As an when each call finished, add it to the response set.
for (int i = 0; i < calls.size(); i ++) {
try {
T t = completionService.take().get();
// do some stuff that I want to test
} catch (...) { }
}
How about
when( method-call ).thenReturn( value1, value2, value3 );
You can put as many arguments as you like in the brackets of thenReturn, provided they're all the correct type. The first value will be returned the first time the method is called, then the second answer, and so on. The last value will be returned repeatedly once all the other values are used up.
You can do that using the thenAnswer method (when chaining with when):
when(someMock.someMethod()).thenAnswer(new Answer() {
private int count = 0;
public Object answer(InvocationOnMock invocation) {
if (count++ == 1)
return 1;
return 2;
}
});
Or using the equivalent, static doAnswer method:
doAnswer(new Answer() {
private int count = 0;
public Object answer(InvocationOnMock invocation) {
if (count++ == 1)
return 1;
return 2;
}
}).when(someMock).someMethod();
As previously pointed out almost all of the calls are chainable.
So you could call
when(mock.method()).thenReturn(foo).thenReturn(bar).thenThrow(new Exception("test"));
//OR if you're mocking a void method and/or using spy instead of mock
doReturn(foo).doReturn(bar).doThrow(new Exception("Test").when(mock).method();
More info in Mockito's Documenation.
Almost all of the calls are chainable:
doReturn(null).doReturn(anotherInstance).when(mock).method();
BDD style:
import static org.mockito.BDDMockito.given;
...
given(yourMock.yourMethod()).willReturn(1, 2, 3);
Classic style:
import static org.mockito.Mockito.when;
...
when(yourMock.yourMethod()).thenReturn(1, 2, 3);
Explicit style:
...
when(yourMock.yourMethod())
.thenReturn(1)
.thenReturn(2)
.thenReturn(3);
Depending on an arg
Suppose we have 2 args, and check the size of the 2nd (list) arg:
...
when(yourMock.yourMethod(any(), anyList()))
.thenAnswer(args -> ((List) args.getArgument(1)).size() < 2
? 1
: 3);
args are Objects, so we have to cast an arg to our type. I cast ^^^ to (List) in my case.
BDD
...
given(yourMock.yourMethod(any(), anyList()))
.willAnswer(args -> ((List) args.getArgument(1)).size() < 2
? 1
: 3);
I've implemented a MultipleAnswer class that helps me to stub different answers in every call. Here the piece of code:
private final class MultipleAnswer<T> implements Answer<T> {
private final ArrayList<Answer<T>> mAnswers;
MultipleAnswer(Answer<T>... answer) {
mAnswers = new ArrayList<>();
mAnswers.addAll(Arrays.asList(answer));
}
#Override
public T answer(InvocationOnMock invocation) throws Throwable {
return mAnswers.remove(0).answer(invocation);
}
}
doReturn( value1, value2, value3 ).when( method-call )
Related to #[Igor Nikolaev]'s answer from 8 years ago, using an Answer can be simplified somewhat using a lambda expression available in Java 8.
when(someMock.someMethod()).thenAnswer(invocation -> {
doStuff();
return;
});
or more simply:
when(someMock.someMethod()).thenAnswer(invocation -> doStuff());
If you have a dynamic list of values you can use AdditionalAnswers.returnsElementsOf:
import org.mockito.AdditionalAnswers;
when(mock.method()).thenAnswer(AdditionalAnswers.returnsElementsOf(myListOfValues));
Following can be used as a common method to return different arguments on different method calls. Only thing we need to do is we need to pass an array with order in which objects should be retrieved in each call.
#SafeVarargs
public static <Mock> Answer<Mock> getAnswerForSubsequentCalls(final Mock... mockArr) {
return new Answer<Mock>() {
private int count=0, size=mockArr.length;
public Mock answer(InvocationOnMock invocation) throws throwable {
Mock mock = null;
for(; count<size && mock==null; count++){
mock = mockArr[count];
}
return mock;
}
}
}
Ex. getAnswerForSubsequentCalls(mock1, mock3, mock2); will return mock1 object on first call, mock3 object on second call and mock2 object on third call.
Should be used like when(something()).doAnswer(getAnswerForSubsequentCalls(mock1, mock3, mock2));
This is almost similar to when(something()).thenReturn(mock1, mock3, mock2);
You can use a LinkedList and an Answer. Eg
MyService mock = mock(MyService.class);
LinkedList<String> results = new LinkedList<>(List.of("A", "B", "C"));
when(mock.doSomething(any())).thenAnswer(invocation -> results.removeFirst());
This is not directly related to the question. But wanted to put this in the same chain.
If trying to verify the same method call with multiple arguments, you can use the below times feature by Mockito. You don't need it if you are not verifying.
Mockito.verify(method, times(n)).methoscall();
Here is 'n' is the number of times the mock is invoked.
This might be basic/obvious, but if like me you are trying to mock multiple calls for a method that is called unknown number of times per call to method to be tested, for example:
public String method(String testArg) {
//...
while(condition) {
someValue = someBean.nestedMethod(); // This is called unknown number of times
//...
}
//...
}
You can do something like:
#Test
public void testMethod() {
mockNestedMethodForValue("value1");
assertEquals(method("arg"), "expected1");
mockNestedMethodForValue("value2");
assertEquals(method("arg"), "expected2");
mockNestedMethodForValue("value3");
assertEquals(method("arg"), "expected3");
}
private void mockNestedMethodForValue(String value) {
doReturn(value).when(someBeanMock).nestedMethod();
}
Here is working example in BDD style which is pretty simple and clear
given(carRepository.findByName(any(String.class))).willReturn(Optional.empty()).willReturn(Optional.of(MockData.createCarEntity()));

Refactoring Java8 code with Functional Interface

Input:
public BigDecimal getMaxValuation(ServiceData data) {
System.out.println("getMaxValuation()");
BigDecimal calculatedAmount;
//4 String returnValue = getReturnValue(data);
Function<ServiceData,String> returnValueFn = this::getReturnValue;
BigDecimal orderSize = getOrderSize(returnValueFn.apply(data),60);
Predicate<String> gasPredicate = "GAS"::equalsIgnoreCase;
Predicate<String> oilPredicate = "OIL"::equalsIgnoreCase;
if(gasPredicate.test(returnValueFn.apply(data)))
calculatedAmount = callA(data.getValuation())
else if(oilPredicate.test(returnValueFn.apply(data)))
calculatedAmount = callB(data.getValuation())
else
calculatedAmount = callC(data.getValuation())
return calculatedAmount;
}
public String getReturnValue(ServiceData data){
System.out.println("getReturnValue()");
return returnValue;
}
In the above function getMaxValuation(), when we comment line#4 and replace it with a Function<ServiceData,String>,
getReturnValue() is getting called 3 times during the execution. But when we uncomment the line #4 and remove all the
Function<ServiceData,String> related change the getReturnValue() is getting called only once.
When we use Function is there any way to achieve the same behavior ?
Whether you invoke a method directly or using a functional interface, the logic of invoking it once and storing the result in a local variable to avoid repeated evaluation doesn’t change.
So far, your rewriting of the direct invocations into uses of a functional interface looks like an end in itself, without actually improving anything but only making the code more complicated.
One way of using functional programming to improve your code would be using a map of functions to replace the if-else ladder by a single lookup:
static final Map<String, Function<Valuation,BigDecimal>> METHOD;
static {
Map<String, Function<Valuation,BigDecimal>> m
= new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
m.put("GAS", ContainingClass::callA);
m.put("OIL", ContainingClass::callB);
METHOD = Collections.unmodifiableMap(m);
}
public BigDecimal getMaxValuation(ServiceData data) {
// don't know how to incorporate this, as it was entirely unused
// BigDecimal orderSize = getOrderSize(getReturnValue(data), 60);
return METHOD.getOrDefault(getReturnValue(data), ContainingClass::callC)
.apply(data.getValuation());
}
Where Valuation refers to the return type of ServiceData.getValuation() and ContainingClass is the declaring class of callA, callB, and callC, assuming static methods.
If these methods are non-static, the code would have to look like
static final Map<String, BiFunction<ContainingClass,Valuation,BigDecimal>> METHOD;
static {
Map<String, BiFunction<ContainingClass,Valuation,BigDecimal>> m
= new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
m.put("GAS", ContainingClass::callA);
m.put("OIL", ContainingClass::callB);
METHOD = Collections.unmodifiableMap(m);
}
public BigDecimal getMaxValuation(ServiceData data) {
return METHOD.getOrDefault(getReturnValue(data), ContainingClass::callC)
.apply(this, data.getValuation());
}

Using Mockito with multiple calls to the same method with the same arguments

Is there a way to have a stubbed method return different objects on subsequent invocations? I'd like to do this to test nondeterminate responses from an ExecutorCompletionService. i.e. to test that irrespective of the return order of the methods, the outcome remains constant.
The code I'm looking to test looks something like this.
// Create an completion service so we can group these tasks together
ExecutorCompletionService<T> completionService =
new ExecutorCompletionService<T>(service);
// Add all these tasks to the completion service
for (Callable<T> t : ts)
completionService.submit(request);
// As an when each call finished, add it to the response set.
for (int i = 0; i < calls.size(); i ++) {
try {
T t = completionService.take().get();
// do some stuff that I want to test
} catch (...) { }
}
How about
when( method-call ).thenReturn( value1, value2, value3 );
You can put as many arguments as you like in the brackets of thenReturn, provided they're all the correct type. The first value will be returned the first time the method is called, then the second answer, and so on. The last value will be returned repeatedly once all the other values are used up.
You can do that using the thenAnswer method (when chaining with when):
when(someMock.someMethod()).thenAnswer(new Answer() {
private int count = 0;
public Object answer(InvocationOnMock invocation) {
if (count++ == 1)
return 1;
return 2;
}
});
Or using the equivalent, static doAnswer method:
doAnswer(new Answer() {
private int count = 0;
public Object answer(InvocationOnMock invocation) {
if (count++ == 1)
return 1;
return 2;
}
}).when(someMock).someMethod();
As previously pointed out almost all of the calls are chainable.
So you could call
when(mock.method()).thenReturn(foo).thenReturn(bar).thenThrow(new Exception("test"));
//OR if you're mocking a void method and/or using spy instead of mock
doReturn(foo).doReturn(bar).doThrow(new Exception("Test").when(mock).method();
More info in Mockito's Documenation.
Almost all of the calls are chainable:
doReturn(null).doReturn(anotherInstance).when(mock).method();
BDD style:
import static org.mockito.BDDMockito.given;
...
given(yourMock.yourMethod()).willReturn(1, 2, 3);
Classic style:
import static org.mockito.Mockito.when;
...
when(yourMock.yourMethod()).thenReturn(1, 2, 3);
Explicit style:
...
when(yourMock.yourMethod())
.thenReturn(1)
.thenReturn(2)
.thenReturn(3);
Depending on an arg
Suppose we have 2 args, and check the size of the 2nd (list) arg:
...
when(yourMock.yourMethod(any(), anyList()))
.thenAnswer(args -> ((List) args.getArgument(1)).size() < 2
? 1
: 3);
args are Objects, so we have to cast an arg to our type. I cast ^^^ to (List) in my case.
BDD
...
given(yourMock.yourMethod(any(), anyList()))
.willAnswer(args -> ((List) args.getArgument(1)).size() < 2
? 1
: 3);
I've implemented a MultipleAnswer class that helps me to stub different answers in every call. Here the piece of code:
private final class MultipleAnswer<T> implements Answer<T> {
private final ArrayList<Answer<T>> mAnswers;
MultipleAnswer(Answer<T>... answer) {
mAnswers = new ArrayList<>();
mAnswers.addAll(Arrays.asList(answer));
}
#Override
public T answer(InvocationOnMock invocation) throws Throwable {
return mAnswers.remove(0).answer(invocation);
}
}
doReturn( value1, value2, value3 ).when( method-call )
Related to #[Igor Nikolaev]'s answer from 8 years ago, using an Answer can be simplified somewhat using a lambda expression available in Java 8.
when(someMock.someMethod()).thenAnswer(invocation -> {
doStuff();
return;
});
or more simply:
when(someMock.someMethod()).thenAnswer(invocation -> doStuff());
If you have a dynamic list of values you can use AdditionalAnswers.returnsElementsOf:
import org.mockito.AdditionalAnswers;
when(mock.method()).thenAnswer(AdditionalAnswers.returnsElementsOf(myListOfValues));
Following can be used as a common method to return different arguments on different method calls. Only thing we need to do is we need to pass an array with order in which objects should be retrieved in each call.
#SafeVarargs
public static <Mock> Answer<Mock> getAnswerForSubsequentCalls(final Mock... mockArr) {
return new Answer<Mock>() {
private int count=0, size=mockArr.length;
public Mock answer(InvocationOnMock invocation) throws throwable {
Mock mock = null;
for(; count<size && mock==null; count++){
mock = mockArr[count];
}
return mock;
}
}
}
Ex. getAnswerForSubsequentCalls(mock1, mock3, mock2); will return mock1 object on first call, mock3 object on second call and mock2 object on third call.
Should be used like when(something()).doAnswer(getAnswerForSubsequentCalls(mock1, mock3, mock2));
This is almost similar to when(something()).thenReturn(mock1, mock3, mock2);
You can use a LinkedList and an Answer. Eg
MyService mock = mock(MyService.class);
LinkedList<String> results = new LinkedList<>(List.of("A", "B", "C"));
when(mock.doSomething(any())).thenAnswer(invocation -> results.removeFirst());
This is not directly related to the question. But wanted to put this in the same chain.
If trying to verify the same method call with multiple arguments, you can use the below times feature by Mockito. You don't need it if you are not verifying.
Mockito.verify(method, times(n)).methoscall();
Here is 'n' is the number of times the mock is invoked.
This might be basic/obvious, but if like me you are trying to mock multiple calls for a method that is called unknown number of times per call to method to be tested, for example:
public String method(String testArg) {
//...
while(condition) {
someValue = someBean.nestedMethod(); // This is called unknown number of times
//...
}
//...
}
You can do something like:
#Test
public void testMethod() {
mockNestedMethodForValue("value1");
assertEquals(method("arg"), "expected1");
mockNestedMethodForValue("value2");
assertEquals(method("arg"), "expected2");
mockNestedMethodForValue("value3");
assertEquals(method("arg"), "expected3");
}
private void mockNestedMethodForValue(String value) {
doReturn(value).when(someBeanMock).nestedMethod();
}
Here is working example in BDD style which is pretty simple and clear
given(carRepository.findByName(any(String.class))).willReturn(Optional.empty()).willReturn(Optional.of(MockData.createCarEntity()));

Pass derived object into method wanting superclass using java reflection?

EDIT: I wasn't clear. I have to use reflection because I am interpreting from a command line. I am doing the reflection equivalent of the code examples I have provided.
hope this isn't a duplicate since it seems like an everyday thing to want to do.
I have a class A, and a class B that extends A. If I have a method in class C like public void doSomething(A a), how can I use reflection to pass a B object into this function? I want to do the (reflection) equivalent of:
B b = new B(); //B inherits from A
C c = new C();
c.doSomething(b); // method signature is doSomething(A a);
What I have done (using reflection) is:
get the Objects which are the arguments to the function.
get the Classes of the arguments
look up the method based upon the classes of the arguments.
invoke the method, passing in the argument Objects.
This works great if I were going to pass an A object into C.doSomething(...). However, if I am trying to pass a B object into C.doSomething(...) it fails on step 3, with this error:
java.lang.NoSuchMethodException: C.doSomething(B)
What is the appropriate way to get C.doSomething to recognize that B is an A? (when looking up a method using getDeclaredMethod(String name, Class... parameterTypes) and passing B.class in as the parameter type)
EDIT:
I'll post my own solution in case somebody wants to see one quickly hacked way of doing what Roland Illig suggested. In this example I reference these pre-made variables:
String methodToken; //the name of the method
Object obj; //the object whose method we are trying to call
Object[] args; //the user given arguments for the method
Class[] argTypes; //the types of the args gotten by args[i].getClass();
so...
//*** try to get the specified method from the object
Method m = null;
// if we are looking for a no-arg version of the method:
if(null == args)
{
try
{
m = obj.getClass().getMethod(methodToken, argTypes);
}
catch ( /*errors*/ )
{
// do stuff
}
}
else // if we are looking for a version of the method that takes arguments
{
// we have to do this type of lookup because our user arguments could be
// subclasses of the arguments required by the method. getMethod will not
// find a match in that case.
try
{
boolean matchFound = false;
Class c = obj.getClass();
do
{ // for each level in the inheritance hierarchy:
// get all the methods with the right name
//(matching the name that the user supplied for the method)
Method[] methodList = c.getMethods();
ArrayList<Method> matchingMethods = new ArrayList<Method>();
for( Method meth : methodList)
{
if(meth.getName().equals(methodToken))
{
matchingMethods.add(meth);
}
}
// check for a matching method signature
for( Method meth : matchingMethods)
{
// get the types of the arguments the method under
// investigation requires.
Class[] paramList = meth.getParameterTypes();
// make sure the signature has the required number of
// elements. If not, this is not the correct method.
if(paramList.length != args.length)
{
continue;
}
// Now check if each method argument is assignable from the
// type given by the user's provided arguments. This means
// that we are checking to see if each of the user's
// arguments is the same as, or is a superclass or
// superinterface of the type found in the method signature
//(i.e. it is legal to pass the user arguments to this
// method.) If one does not match, then this is not the
// correct method and we continue to the next one.
boolean signatureMatch = false;
for ( int i = 0; i < paramList.length; ++i)
{
if(paramList[i].isAssignableFrom( argTypes[i] ) )
{
signatureMatch = true;
}
else
{
continue;
}
}
// if we matched the signature on a matchingly named
// method, then we set the method m, and indicate
// that we have found a match so that we can stop
// marching up the inheritance hierarchy. (i.e. the
// containing loop will terminate.
if(true == signatureMatch)
{
m = meth;
matchFound = true;
break;
}
}
// move up one level in class hierarchy.
c = c.getSuperclass();
}
while(null != c && false == matchFound);
}
catch( /*errors*/)
{
// do stuff
}
}
// check that m got assigned
if(null == m)
{
System.out.println("From DO: unable to match method");
return false;
}
// try to invoke the method !!!!
try
{
m.invoke(obj, args);
}
catch ( /* errors */ )
{
// do stuff
}
Hope it will help someone sometime!
You need to follow the same process as outlined in the Java Language Specification, section 15.12 "Method Invocation Expressions", for finding the same method that would be found at compile time. In short, it's more complicated than you think.
A simple variant would be to check all the methods with the correct name (and don't forget the methods of all superclasses). For each of these methods, check whether all of your arguments are assignment-compatible to the corresponding method parameter. That might not be perfect, but works in most cases.
[Update:] The "simple variant" fails when there are multiple overloaded methods in a class. Here is some example code that you can play with:
package so7691729;
import static org.junit.Assert.*;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.Set;
import org.junit.Test;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
public class MethodCaller {
private boolean isCompatible(Method m, Object... args) {
Class<?>[] parameterTypes = m.getParameterTypes();
if (parameterTypes.length == args.length) {
for (int i = 0; i < args.length; i++) {
if (args[i] != null) {
if (!parameterTypes[i].isAssignableFrom(args[i].getClass())) {
// TODO: make primitive types equivalent to their boxed types.
return false;
}
}
}
} else {
// TODO: maybe handle varargs methods here
return false;
}
return true;
}
public Object call1(String fullyQualifiedMethodName, Object obj, Object... args) throws ClassNotFoundException, IllegalAccessException,
InvocationTargetException {
int lastDot = fullyQualifiedMethodName.lastIndexOf(".");
String className = fullyQualifiedMethodName.substring(0, lastDot);
String methodName = fullyQualifiedMethodName.substring(lastDot + 1);
Class<?> clazz = Class.forName(className);
for (Class<?> c = clazz; c != null; c = c.getSuperclass()) {
Set<String> sameNameMethods = Sets.newTreeSet();
Map<String, Method> compatibleMethods = Maps.newTreeMap();
for (Method method : c.getDeclaredMethods()) {
if (method.getName().equals(methodName)) {
sameNameMethods.add(method.toString());
if (isCompatible(method, args)) {
compatibleMethods.put(method.toString(), method);
}
}
}
if (compatibleMethods.size() > 1) {
throw new IllegalArgumentException("Multiple candidates: " + compatibleMethods.keySet());
}
if (compatibleMethods.size() == 1) {
return compatibleMethods.values().iterator().next().invoke(obj, args);
}
if (!sameNameMethods.isEmpty()) {
throw new IllegalArgumentException("Incompatible types for " + sameNameMethods);
}
}
throw new IllegalArgumentException("No method found.");
}
public Object call(String fullyQualifiedMethodName, Object obj, Object... args) {
try {
return call1(fullyQualifiedMethodName, obj, args);
} catch (ClassNotFoundException e) {
throw new IllegalArgumentException(e);
} catch (IllegalAccessException e) {
throw new IllegalArgumentException(e);
} catch (InvocationTargetException e) {
throw new IllegalArgumentException(e);
}
}
public String str(Object obj) {
return "object " + obj;
}
public String str(String str) {
return "string " + str;
}
public int add(int a, int b) {
return a + b;
}
#SuppressWarnings("boxing")
public int addObj(Integer a, Integer b) {
return a + b;
}
private void assertCallingError(String msg, String methodName, Object obj, Object... args) {
try {
call(methodName, obj, args);
fail();
} catch (IllegalArgumentException e) {
assertEquals(msg, e.getMessage());
}
}
#SuppressWarnings("boxing")
#Test
public void test() {
MethodCaller dummy = new MethodCaller();
assertEquals("object 1", call("so7691729.MethodCaller.str", dummy, 1));
assertCallingError("Multiple candidates: " + //
"[public java.lang.String so7691729.MethodCaller.str(java.lang.Object), " + //
"public java.lang.String so7691729.MethodCaller.str(java.lang.String)]", //
"so7691729.MethodCaller.str", dummy, "str");
assertCallingError("Incompatible types for [public int so7691729.MethodCaller.add(int,int)]", "so7691729.MethodCaller.add", dummy, 3, 4);
assertEquals(7, call("so7691729.MethodCaller.addObj", dummy, 3, 4));
assertCallingError("Incompatible types for [public int so7691729.MethodCaller.addObj(java.lang.Integer,java.lang.Integer)]", "so7691729.MethodCaller.addObj", dummy, "hello", "world");
}
}
And maybe the Java Beans specification or implementation has something for you. They may have had the same problem to solve. Or look at Rhino, a JavaScript implementation in pure Java. It lets you call Java methods directly from JavaScript code, so that is very similar to your problem.
3) look up the method based upon the classes of the arguments
You are asking the class: "Do you have any method with exactly this signature?" The class says "No!" You are not asking "Class, do you have something I can call with these parameters?" As already mentioned, this is not easy to answer as soon as inheritance and overloaded methods are involved and so the complete Reflection API does not address this issue.
However: You are not the first who wants a usable answer to the second question. Perhaps the MethodUtils.invokeMethod or any sibling from the Apache Commons Beanutils project is suitable for you.

Check if enum exists in Java

Is there anyway to check if an enum exists by comparing it to a given string? I can't seem to find any such function. I could just try to use the valueOf method and catch an exception but I'v been taught that catching runtime exceptions is not good practice. Anybody have any ideas?
If I need to do this, I sometimes build a Set<String> of the names, or even my own Map<String,MyEnum> - then you can just check that.
A couple of points worth noting:
Populate any such static collection in a static initializer. Don't use a variable initializer and then rely on it having been executed when the enum constructor runs - it won't have been! (The enum constructors are the first things to be executed, before the static initializer.)
Try to avoid using values() frequently - it has to create and populate a new array each time. To iterate over all elements, use EnumSet.allOf which is much more efficient for enums without a large number of elements.
Sample code:
import java.util.*;
enum SampleEnum {
Foo,
Bar;
private static final Map<String, SampleEnum> nameToValueMap =
new HashMap<String, SampleEnum>();
static {
for (SampleEnum value : EnumSet.allOf(SampleEnum.class)) {
nameToValueMap.put(value.name(), value);
}
}
public static SampleEnum forName(String name) {
return nameToValueMap.get(name);
}
}
public class Test {
public static void main(String [] args)
throws Exception { // Just for simplicity!
System.out.println(SampleEnum.forName("Foo"));
System.out.println(SampleEnum.forName("Bar"));
System.out.println(SampleEnum.forName("Baz"));
}
}
Of course, if you only have a few names this is probably overkill - an O(n) solution often wins over an O(1) solution when n is small enough. Here's another approach:
import java.util.*;
enum SampleEnum {
Foo,
Bar;
// We know we'll never mutate this, so we can keep
// a local copy.
private static final SampleEnum[] copyOfValues = values();
public static SampleEnum forName(String name) {
for (SampleEnum value : copyOfValues) {
if (value.name().equals(name)) {
return value;
}
}
return null;
}
}
public class Test {
public static void main(String [] args)
throws Exception { // Just for simplicity!
System.out.println(SampleEnum.forName("Foo"));
System.out.println(SampleEnum.forName("Bar"));
System.out.println(SampleEnum.forName("Baz"));
}
}
I don't think there's a built-in way to do it without catching exceptions. You could instead use something like this:
public static MyEnum asMyEnum(String str) {
for (MyEnum me : MyEnum.values()) {
if (me.name().equalsIgnoreCase(str))
return me;
}
return null;
}
Edit: As Jon Skeet notes, values() works by cloning a private backing array every time it is called. If performance is critical, you may want to call values() only once, cache the array, and iterate through that.
Also, if your enum has a huge number of values, Jon Skeet's map alternative is likely to perform better than any array iteration.
One of my favorite lib: Apache Commons.
The EnumUtils can do that easily.
Following an example to validate an Enum with that library:
public enum MyEnum {
DIV("div"), DEPT("dept"), CLASS("class");
private final String val;
MyEnum(String val) {
this.val = val;
}
public String getVal() {
return val;
}
}
MyEnum strTypeEnum = null;
// test if String str is compatible with the enum
// e.g. if you pass str = "div", it will return false. If you pass "DIV", it will return true.
if( EnumUtils.isValidEnum(MyEnum.class, str) ){
strTypeEnum = MyEnum.valueOf(str);
}
I don't know why anyone told you that catching runtime exceptions was bad.
Use valueOf and catching IllegalArgumentException is fine for converting/checking a string to an enum.
Based on Jon Skeet answer i've made a class that permits to do it easily at work:
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* <p>
* This permits to easily implement a failsafe implementation of the enums's valueOf
* Better use it inside the enum so that only one of this object instance exist for each enum...
* (a cache could solve this if needed)
* </p>
*
* <p>
* Basic usage exemple on an enum class called MyEnum:
*
* private static final FailSafeValueOf<MyEnum> FAIL_SAFE = FailSafeValueOf.create(MyEnum.class);
* public static MyEnum failSafeValueOf(String enumName) {
* return FAIL_SAFE.valueOf(enumName);
* }
*
* </p>
*
* <p>
* You can also use it outside of the enum this way:
* FailSafeValueOf.create(MyEnum.class).valueOf("EnumName");
* </p>
*
* #author Sebastien Lorber <i>(lorber.sebastien#gmail.com)</i>
*/
public class FailSafeValueOf<T extends Enum<T>> {
private final Map<String,T> nameToEnumMap;
private FailSafeValueOf(Class<T> enumClass) {
Map<String,T> map = Maps.newHashMap();
for ( T value : EnumSet.allOf(enumClass)) {
map.put( value.name() , value);
}
nameToEnumMap = ImmutableMap.copyOf(map);
}
/**
* Returns the value of the given enum element
* If the
* #param enumName
* #return
*/
public T valueOf(String enumName) {
return nameToEnumMap.get(enumName);
}
public static <U extends Enum<U>> FailSafeValueOf<U> create(Class<U> enumClass) {
return new FailSafeValueOf<U>(enumClass);
}
}
And the unit test:
import org.testng.annotations.Test;
import static org.testng.Assert.*;
/**
* #author Sebastien Lorber <i>(lorber.sebastien#gmail.com)</i>
*/
public class FailSafeValueOfTest {
private enum MyEnum {
TOTO,
TATA,
;
private static final FailSafeValueOf<MyEnum> FAIL_SAFE = FailSafeValueOf.create(MyEnum.class);
public static MyEnum failSafeValueOf(String enumName) {
return FAIL_SAFE.valueOf(enumName);
}
}
#Test
public void testInEnum() {
assertNotNull( MyEnum.failSafeValueOf("TOTO") );
assertNotNull( MyEnum.failSafeValueOf("TATA") );
assertNull( MyEnum.failSafeValueOf("TITI") );
}
#Test
public void testInApp() {
assertNotNull( FailSafeValueOf.create(MyEnum.class).valueOf("TOTO") );
assertNotNull( FailSafeValueOf.create(MyEnum.class).valueOf("TATA") );
assertNull( FailSafeValueOf.create(MyEnum.class).valueOf("TITI") );
}
}
Notice that i used Guava to make an ImmutableMap but actually you could use a normal map i think since the map is never returned...
Most of the answers suggest either using a loop with equals to check if the enum exists or using try/catch with enum.valueOf(). I wanted to know which method is faster and tried it. I am not very good at benchmarking, so please correct me if I made any mistakes.
Heres the code of my main class:
package enumtest;
public class TestMain {
static long timeCatch, timeIterate;
static String checkFor;
static int corrects;
public static void main(String[] args) {
timeCatch = 0;
timeIterate = 0;
TestingEnum[] enumVals = TestingEnum.values();
String[] testingStrings = new String[enumVals.length * 5];
for (int j = 0; j < 10000; j++) {
for (int i = 0; i < testingStrings.length; i++) {
if (i % 5 == 0) {
testingStrings[i] = enumVals[i / 5].toString();
} else {
testingStrings[i] = "DOES_NOT_EXIST" + i;
}
}
for (String s : testingStrings) {
checkFor = s;
if (tryCatch()) {
++corrects;
}
if (iterate()) {
++corrects;
}
}
}
System.out.println(timeCatch / 1000 + "us for try catch");
System.out.println(timeIterate / 1000 + "us for iterate");
System.out.println(corrects);
}
static boolean tryCatch() {
long timeStart, timeEnd;
timeStart = System.nanoTime();
try {
TestingEnum.valueOf(checkFor);
return true;
} catch (IllegalArgumentException e) {
return false;
} finally {
timeEnd = System.nanoTime();
timeCatch += timeEnd - timeStart;
}
}
static boolean iterate() {
long timeStart, timeEnd;
timeStart = System.nanoTime();
TestingEnum[] values = TestingEnum.values();
for (TestingEnum v : values) {
if (v.toString().equals(checkFor)) {
timeEnd = System.nanoTime();
timeIterate += timeEnd - timeStart;
return true;
}
}
timeEnd = System.nanoTime();
timeIterate += timeEnd - timeStart;
return false;
}
}
This means, each methods run 50000 times the lenght of the enum
I ran this test multiple times, with 10, 20, 50 and 100 enum constants.
Here are the results:
10: try/catch: 760ms | iteration: 62ms
20: try/catch: 1671ms | iteration: 177ms
50: try/catch: 3113ms | iteration: 488ms
100: try/catch: 6834ms | iteration: 1760ms
These results were not exact. When executing it again, there is up to 10% difference in the results, but they are enough to show, that the try/catch method is far less efficient, especially with small enums.
Since Java 8, we could use streams instead of for loops. Also, it might be apropriate to return an Optional if the enum does not have an instance with such a name.
I have come up with the following three alternatives on how to look up an enum:
private enum Test {
TEST1, TEST2;
public Test fromNameOrThrowException(String name) {
return Arrays.stream(values())
.filter(e -> e.name().equals(name))
.findFirst()
.orElseThrow(() -> new IllegalArgumentException("No enum with name " + name));
}
public Test fromNameOrNull(String name) {
return Arrays.stream(values()).filter(e -> e.name().equals(name)).findFirst().orElse(null);
}
public Optional<Test> fromName(String name) {
return Arrays.stream(values()).filter(e -> e.name().equals(name)).findFirst();
}
}
Just use valueOf() method.
If the value doesn't exist, it throws IllegalArgumentException and you can catch it like that:
boolean isSettingCodeValid = true;
try {
SettingCode.valueOf(settingCode.toUpperCase());
} catch (IllegalArgumentException e) {
// throw custom exception or change the isSettingCodeValid value
isSettingCodeValid = false;
}
You can also use Guava and do something like this:
// This method returns enum for a given string if it exists, otherwise it returns default enum.
private MyEnum getMyEnum(String enumName) {
// It is better to return default instance of enum instead of null
return hasMyEnum(enumName) ? MyEnum.valueOf(enumName) : MyEnum.DEFAULT;
}
// This method checks that enum for a given string exists.
private boolean hasMyEnum(String enumName) {
return Iterables.any(Arrays.asList(MyEnum.values()), new Predicate<MyEnum>() {
public boolean apply(MyEnum myEnum) {
return myEnum.name().equals(enumName);
}
});
}
In second method I use guava (Google Guava) library which provides very useful Iterables class. Using the Iterables.any() method we can check if a given value exists in a list object. This method needs two parameters: a list and Predicate object. First I used Arrays.asList() method to create a list with all enums. After that I created new Predicate object which is used to check if a given element (enum in our case) satisfies the condition in apply method. If that happens, method Iterables.any() returns true value.
Using java 8, you can do something like the below to check if it is valid.
Stream.of(MyEnum.values())
.map(MyEnum::name)
.collect(Collectors.toList()).contains(<STRING_YOU_WANT_TO_VALIDATE>)
Here is what I use to check if an enum constant with given name exists:
java.util.Arrays.stream(E.values()).map(E::name).toList().contains("");
(Suppose your enum is called E.) Here inside "" you should put a name of an enum constant for which you wish to check if it is defined in the enum or not.
This is certainly not the best possible solution since it converts an array into Stream and then again into List, but is nice and short and it works fine for me.
As other people mentioned, since you asked this question in 2009., this will not work in your case (unless you migrated to a newer version of Java) since in 2009. Java did not support features used in this answer. But I am posting anyway in case someone with newer version of Java wants to do this.

Categories

Resources