RESTWS Resource Conversion Issue

0 views
Skip to first unread message

Wesley Brown

unread,
Jan 13, 2014, 3:49:47 PM1/13/14
to d...@openmrs.org
Greetings,

I am having trouble with the current REST WS version (v2.4) when attempting to convert classes that have generic superclasses. The issue I am running into is that when a property setter method is generic and defined in the base class, the type defined by the child class is not being used for the parameter type.  Instead, the TypeVariable (ie, <T>) is attempted to be used and failing. The issue appears to be in the BaseDelegatingResource.setProperty (lines 697-698) and the ConversionUtil.convert (lines 87-88) methods.

I have finally figured out what (I think) is going on and I only sort of understand that description above so here is a contrived example that shows what I mean. Given these classes:

public abstract class BaseClass<T> {
 
private T something;
 
public T getSomething() { return something; }
 
public void setSomething(T something) { this.something = something; }
}

public class ChildClass extends BaseClass<Integer> {
}

The type that should be found when attempting to set the 'setSomething' property for the ChildClass class should be Integer.  Instead, BaseDelegatingResource.setProperty will find the TypeVariable <T> and pass that as the toType  parameter of the ConversionUtil.convert method which then promptly blows up. 

From BaseDelegatingResource.setProperty (lines 697-698): 
Method setter = PropertyUtils.getPropertyDescriptor(instance, propertyName).getWriteMethod(); // Properly returns setSomething Method
value
= ConversionUtil.convert(value,setter.getGeneraticParameterTypes()[0]); // Bolded code returns TypeVariable, not ParameterizedType

The potential for this kind of problem is noted in this article along is a rather cumbersome solution but I wanted to check if this was a known issue and, if not, start the discussion about a fix.

Thanks,
-Wes Brown

Lluis Martinez

unread,
Jan 13, 2014, 7:42:50 PM1/13/14
to d...@openmrs.org
Have you tried getParameterTypes instead of getGenericParameterTypes ?
In core there are no entities using generics in this case both methods
are equivalent and the tests pass.

Cheers
> --
> OpenMRS Developers: http://go.openmrs.org/dev
> Post: d...@openmrs.org | Unsubscribe: dev+uns...@openmrs.org
> Manage your OpenMRS subscriptions at https://id.openmrs.org/
>
> To unsubscribe from this group and stop receiving emails from it, send an
> email to dev+uns...@openmrs.org.

Wesley Brown

unread,
Jan 14, 2014, 8:04:16 AM1/14/14
to d...@openmrs.org
Lluis,

I tried that but it returns Object (or the constrained class for the generic type).

-Wes

Lluis Martinez

unread,
Jan 14, 2014, 9:38:39 AM1/14/14
to d...@openmrs.org
A very hacky way:

        Method setter = PropertyUtils.getPropertyDescriptor(this, property).getWriteMethod();
        Type[] types = setter.getGenericParameterTypes();
        Class clazz = null;
        if (types[0].toString().equals("T")) {
            clazz = (Class) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
        } else {
            clazz = setter.getParameterTypes()[0];
        }


Lluis Martinez

unread,
Jan 14, 2014, 9:39:24 AM1/14/14
to d...@openmrs.org

Wesley Brown

unread,
Jan 15, 2014, 3:51:37 AM1/15/14
to d...@openmrs.org
Lluis,

I ended up doing something similar but also supporting walking the inheritance chain up until it finds the correct class with the specific generic type, similar to how the code in article I referenced works.  I also created RESTWS-403 and a pull request with a general fix. 

Thanks for looking into it!
-Wes
Reply all
Reply to author
Forward
0 new messages