You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@cxf.apache.org by Matteo Rulli <ma...@gmail.com> on 2019/01/11 13:05:14 UTC

JAX-RSSearch and FIQL: Beanspector throws (unecessary?) IllegalArgumentException with some POJOs structures

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

Re: JAX-RSSearch and FIQL: Beanspector throws (unecessary?) IllegalArgumentException with some POJOs structures

Posted by Matteo Rulli <ma...@gmail.com>.
Hello,

I created an issue (https://issues.apache.org/jira/browse/CXF-7966) and submitted a PR (https://github.com/apache/cxf/pull/510/).

Matteo

> On 22 Jan 2019, at 17:33, Colm O hEigeartaigh <co...@apache.org> wrote:
> 
> Hi,
> 
> Please create a pull request and we will review it in more detail.
> 
> Colm.
> 
> On Fri, Jan 11, 2019 at 1:28 PM Matteo Rulli <ma...@gmail.com> wrote:
> 
>> 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
> 
> 
> 
> -- 
> Colm O hEigeartaigh
> 
> Talend Community Coder
> http://coders.talend.com


Re: JAX-RSSearch and FIQL: Beanspector throws (unecessary?) IllegalArgumentException with some POJOs structures

Posted by Colm O hEigeartaigh <co...@apache.org>.
Hi,

Please create a pull request and we will review it in more detail.

Colm.

On Fri, Jan 11, 2019 at 1:28 PM Matteo Rulli <ma...@gmail.com> wrote:

> 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



-- 
Colm O hEigeartaigh

Talend Community Coder
http://coders.talend.com