Hello,

We use JAX-RSSearch and Fiql parser in a JAX-RS endpoint and we have a problem 
with org.apache.cxf.jaxrs.ext.search.Beanspector.

Let's consider the following pojos:

public class A {
        
        private String value;

        public String getValue(){ ... }
        public void setValue(String value) { ... }
}

public class B {
        
        private A aValue;

        public A getAValue(){ ... }
        public void setAValue(A avalue) { ... }
}

And assume one extends these pojos and decorates them with JPA annotations. 

To leverage CXF org.apache.cxf.jaxrs.ext.search.SearchContext and 
JPACriteriaQueryVisitor as explained in the docs 
(http://cxf.apache.org/docs/jax-rs-search.html#JAX-RSSearch-JPA2.0) and perform 
searches like

_s=aValue==*search token*

in OpenJPA one has to override the EntityB.getAValue as follows:

@Entity
// ... other JPA annotations are omitted
public class EntityB extends B {
        
        @Override
        // We need to specialize return type to EntityA to make SearchContext 
work
        public EntityA getAValue(){ ... }

        // This method definition is needed to avoid java.lang.VerifyError from 
JPA provider
        public void setAValue(EntityA avalue) { ... }
}

But with this scenario, the current implementation of 
org.apache.cxf.jaxrs.ext.search.Beanspector<T> fails, throwing 
IllegalArgumentException: Accessor 'aValue' type mismatch, getter type is X 
while setter type is Y, X and Y depending on the order of the EntityB's methods 
as returned by the Class.getMethods().

This is the current implementation of Beanspector where the exception is 
triggered:

@SuppressWarnings("unchecked")
private void 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<>(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()));
        }
    }
}

And this is how we patched it:

@SuppressWarnings("unchecked")
private void init() {
    if (tclass == null) {
        tclass = (Class<T>)tobj.getClass();
    }
    for (Method m : tclass.getMethods()) {
        if (isGetter(m)) {
                String pname = getPropertyName(m);
                if (!getters.containsKey(pname)) {
                        getters.put(getPropertyName(m), m);
                } else {
                        // Prefer the getter that has the most specialized 
class as a return type
                        Method _m = getters.get(pname);
                        if 
(_m.getReturnType().isAssignableFrom(m.getReturnType())) {
                                getters.put(pname, m);
                        }
                }
        } else if (isSetter(m)) {
                String pname = getPropertyName(m);
                if (!setters.containsKey(pname)) {
                        setters.put(getPropertyName(m), m);
                } else {
                        // Prefer the setter that has the most specialized 
class as a parameter
                        Method _m = setters.get(pname);
                        if 
(_m.getParameterTypes()[0].isAssignableFrom(m.getParameterTypes()[0])) {
                                setters.put(pname, m);
                        }
                }
        }
    }
    // check type equality for getter-setter pairs
    Set<String> pairs = new HashSet<>(getters.keySet());
    pairs.retainAll(setters.keySet());
    for (String accessor : pairs) {
        Class<?> getterClass = getters.get(accessor).getReturnType();
        Class<?> setterClass = setters.get(accessor).getParameterTypes()[0];
        if (!setterClass.isAssignableFrom(getterClass)) {
            throw new IllegalArgumentException(String
                .format("Accessor '%s' type mismatch, getter type is %s while 
setter type is %s",
                        accessor, getterClass.getName(), 
setterClass.getName()));
        }
    }
}

If you think this is OK we can create a pull request with this.

Thank you,
Matteo

Reply via email to