0

I am trying to invoke a method through reflection on an EJB that has been looked up through its JNDI reference. It requires three arguments: a EndUser object (custom object), a Set (custom class) and a boolean. The first object causes the invocation to fail with a "Could not invoke method: java.lang.IllegalArgumentException: argument type mismatch". This occurs as long as the first argument is non-null. Setting it to null makes the error go away.

The actual call:

  public Relation createRelation(final Relation relation, final HashSet<Contact> contacts) {
        final EndUser user = new EndUser();
        Object[] args = new Object[]{user, contacts, false};

        try {
            return (Relation) EjbUtils.invoke("registerEndUser", REGISTRATION_SERVICE_JNDI, args);
        } catch (final Throwable throwable) {
            LOGGER.error("Could not invoke method", throwable);

            return null;
        }
}

The EjbUtils method:

 public static Object invoke(final String methodName, final String ejbName, final Object... args) throws Throwable {
        final String jndiName = getEjbJndi(ejbName);
        final Object remoteObject = lookup(jndiName);
        final Method[] methods = remoteObject.getClass().getMethods();

        for (final Method method : methods) {
            if (methodName.equals(method.getName()) && args.length == method.getParameterCount()) {
                try {
                    return method.invoke(remoteObject, args);
                } catch (IllegalAccessException e) {
                    final String message = String.format("Could not invoke method %s on %s: %s", methodName, ejbName, e.getMessage());
                    LOGGER.error(message);
                    throw new IllegalStateException(message, e);
                } catch (InvocationTargetException e) {
                    throw e.getCause();
                }
            }
        }

        throw new IllegalArgumentException("Method not found");
    }

The method I am trying to invoke:

    public Relation registerEndUser(final EndUser relation, final Set<Contact> contacts, boolean sendMail)
            throws RegistrationServiceException, RegistrationServiceWarning {
        return registerRelation(relation, contacts, sendMail);
    }

The weird part is: if I replace

final EndUser user = new EndUser();

with

final EndUser user = null;

No exception is thrown and the method is invoked, which should indicate the arguments are of the correct type.

When debugging I can see the correct method is found, and the required parameter types are identical to the ones I provide. Any thought on how to find out what the actual problem is?

Break point showing the required and provided method arguments

DennisV
  • 128
  • 1
  • 10
  • Check the fully qualified name of the class `EndUser`, both in `createRelation()` and `registerEndUser()`. Perhaps you imported the wrong class and they are actually two different classes. – Roger Gustavsson Aug 20 '19 at 12:51
  • I considered that option and verified both are the same fully-qualified name. See the package in the screenshot in args[0] and method.parameterTypes[0]. I have blurred the company and project name for privacy reason but believe me that they are the same :) – DennisV Aug 20 '19 at 13:13
  • I have been able to track down the cause. The reason I used a remote lookup and reflection was that I was invoking an EJB in another EAR. As a result, the EndUser class has been created by a different classloader and therefore not recognized as an instance of the required class. I will not delete my post in case it may be helpfull to anyone in the future :) – DennisV Aug 21 '19 at 08:37

1 Answers1

0

I have been able to track down the cause. The reason I used a remote lookup and reflection was that I was invoking an EJB in another EAR. As a result, the EndUser class has been created by a different classloader and therefore not recognized as an instance of the required class. See ClassCastException when casting to the same class for more information.

DennisV
  • 128
  • 1
  • 10