Hi,

Further to previous discussions about issues using FIQL with interfaces, I've just come across another issue. I have a Task interface that has a getJob() method that returns a Job interface. This is implemented by the Task_Impl class that returns a Job_Impl interface.

Unfortunately I'm hitting this error:
Caused by: java.lang.IllegalArgumentException: Accessor 'job' type mismatch, getter type is Job while setter type is Job_Impl
(package names redacted)

The Task_Impl class, which is the one being worked on, returns Job_Impl from getJob(), so why is it wrong?

The answer lies here:
Beanspectors.init() {
        if (tclass == null) {
            tclass = (Class<T>)tobj.getClass();
        }
        for (Method m : tclass.getMethods()) {
            if (isGetter(m)) {
                getters.put(getPropertyName(m), m);
            } else if (isSetter(m)) {
                setters.put(getPropertyName(m), m);
            }
        }
        // check type equality for getter-setter pairs
        Set<String> pairs = new HashSet<String>(getters.keySet());
        pairs.retainAll(setters.keySet());
        for (String accessor : pairs) {
            Class<?> getterClass = getters.get(accessor).getReturnType();
Class<?> setterClass = setters.get(accessor).getParameterTypes()[0];
            if (!getterClass.equals(setterClass)) {
                throw new IllegalArgumentException(String
.format("Accessor '%s' type mismatch, getter type is %s while setter type is %s", accessor, getterClass.getName(), setterClass.getName()));
            }
        }
    }

It seems that Java puts two getJob methods in the class object - one from the interface and one from the class. And, for my Task_Impl class the abstract getJob comes after the concrete getJob. And whilst the order of the methods is consistent between runs it's not fixed for different classes - so whilst the trick of overriding the return type of getJob works some of the time it doesn't work in all cases.

For my situation it would work if the
                getters.put(getPropertyName(m), m);
checked for an existing method and only replaced it if the new method returned a more specific class. I think that would work in general because the actual class has to be actually returning the more specific class - but you might have to do some check on the setter too to ensure that you have consistency between the two, which is a bit nasty.

Jim

Jim

Reply via email to