-1

One of a method in my API, doesn't take Java.lang.Object type as an argument but it takes all the sub types of it as an argument (java.lang.Integer, java.lang.String etc).

Now, I want to store the DataType in a list by doing:

List<Object> listObjects = new ArrayList<Object>();
if(listObjects.get(0) instanceof Integer){
//then do
listDataTypesForCast.add(Integer);
}

so that, I can cast like this:

myMethod((listDataTypesForCast.get(0)"returning Java.lang.Object datatype"))

But, I don't know how to declare my List: listDataTypesForCast, so that I can use it for Casting. Please let me know if you know the answer?

PS: I'm using Apache POI library and setCellValue() method there can't have java.lang.Object as a DataType in arguments, and I can't check the DataType at the time of inserting the value in cell because it is in a loop and it will add too much of boiler plate code.

Jammy
  • 71
  • 2
  • 14
  • 1
    Please at least *try* to post valid Java code. `new List()` will not compile, since `List` is an interface. --- Also, why would you need to store type in a separate list? The object already knows it's type. It's how `instanceof` can check it. --- Anyway, what you are seeking to do won't work, because method overload resolution is done at *compile-time*, not run-time. – Andreas Jan 18 '17 at 23:47
  • 2
    What do you mean by "... doesn't take Java.lang.Object as an argument but it takes all the sub types of it ..."? I don't think it's possible in Java to declare a parameter like that. – Dawood ibn Kareem Jan 18 '17 at 23:49
  • 1
    @DavidWallace I read that as method overloads, e.g. class has `myMethod(Integer i)`, `myMethod(String s)`, `myMethod(Double d)`, ... – Andreas Jan 18 '17 at 23:50
  • 2
    Yeah, I thought that was probably what OP meant, but worth checking before I try to answer the question. And if they really mean "all the sub types of it", that's a LOT of overloads. – Dawood ibn Kareem Jan 19 '17 at 00:00
  • @Andreas I'm sorry, wrote it by mistake, corrected now. Do you know any work around this? workaround which I know is too lengthy because it will contain too many if elseif instanceof statements for each insertion in a excel cell. – Jammy Jan 19 '17 at 01:04

2 Answers2

1

If you want to call one of many overloads of a single-argument method, but don't know the argument type until run-time, you can do it using reflection.

Here is a helper method for doing that:

private static void call(Object obj, String methodName, Object arg) {
    Class<?> argClass = arg.getClass();

    // Try simple approach
    Method methodToCall;
    try {
        methodToCall = obj.getClass().getMethod(methodName, argClass);
    } catch (@SuppressWarnings("unused") NoSuchMethodException unused) {
        methodToCall = null;
    }

    // Search for method, if simple approach didn't work
    if (methodToCall == null) {
        List<Method> candidates = new ArrayList<>();
        for (Method method : obj.getClass().getMethods()) { // Note: Public methods only
            if (method.getParameterCount() == 1 && method.getName().equals(methodName)) {
                Parameter parameter = method.getParameters()[0];
                if (parameter.getType().isAssignableFrom(argClass))
                    candidates.add(method);
            }
        }
        if (candidates.isEmpty()) {
            throw new NoSuchMethodError(obj.getClass().getName() + '.' +
                                        methodName + '(' + argClass.getName() + ')');
        }
        if (candidates.size() > 1) {
            // Implement extended overload resolution logic, if needed
            throw new NoSuchMethodError("Multiple candidates found for parameter type " +
                                        argClass.getName() + ": " + candidates);
        }
        methodToCall = candidates.get(0);
    }

    // Call method
    try {
        methodToCall.invoke(obj, arg);
    } catch (IllegalAccessException e) {
        throw new IllegalAccessError(e.getMessage());
    } catch (InvocationTargetException e) {
        throw new RuntimeException("Checked exception: " + e.getCause(), e);
    }
}

Test

public static void main(String[] args) {
    Test obj = new Test();
    for (Object arg : Arrays.asList("Foo", 42, 42L, 42f, 42d))
        call(obj, "myMethod", arg);
}

public void myMethod(String s) {
    System.out.println("String: " + s);
}
public void myMethod(Number s) {
    System.out.println("Number: " + s);
}
public void myMethod(Long s) {
    System.out.println("Long: " + s);
}

Output

String: Foo
Number: 42
Long: 42
Number: 42.0
Number: 42.0
Andreas
  • 154,647
  • 11
  • 152
  • 247
0

However, my problem can be solved using Reflection (as suggested by Andreas) but, in this particular case I decided to not use reflection extensively because I've a lot of data to write to excel cells and therefore, I used the following approach:

  1. Find out the data type of each data (of type Object) using instanceof, for the first row cells and then saving the result to Enum. Because rest of the rows share the same datatype across the columns.

  2. Now, looping through the Enum and setting the cell values and data type.

I believe instaceof is also using reflection internally but, I just have to use it once.

Jammy
  • 71
  • 2
  • 14