You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@tapestry.apache.org by Bill Holloway <bi...@peoplepad.com> on 2008/05/26 07:47:38 UTC

T5: A problem with generics in data classes

Hi, I'm illustrating an interesting issue with generic classes in our
data model.  Here is the very simple page class and template used:

public class TestPageGenericProb
{
    @Property
    private List<Foo> _foos = new LinkedList<Foo>();

    void setupRender ()
    {
        Foo f1 = new Foo();
        _foos.add( f1 );
    }
}

TestPageGenericProb.tml:

<html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd">
<body>
    <t:grid source="foos" />
</body>
</html>

The data classes are

public class Foo extends Bla<String>
{
    private Long _id;
    public Long getId () { return _id; }
    public void setId (Long id) { _id = id; }
}

public abstract class Bla<U> extends Baz<U, Integer>
{
}

public abstract class Baz <V, W>
{
    private W _dealyBob;
    public W getDealyBob () { return _dealyBob; }
    public void setDealyBob (W dealyBob) { _dealyBob = dealyBob; }
}

On visiting the page, I get Render queue error in
SetupRender[TestPageGenericProb:grid]: Failure reading parameter
'model' of component TestPageGenericProb:grid:
java.lang.ArrayIndexOutOfBoundsException: 1.

The first several elements of the stack trace are:

# org.apache.tapestry.ioc.internal.util.GenericsUtils.extractGenericReturnType(GenericsUtils.java:75)
# org.apache.tapestry.ioc.internal.services.ClassPropertyAdapterImpl.<init>(ClassPropertyAdapterImpl.java:47)
# org.apache.tapestry.ioc.internal.services.PropertyAccessImpl.buildAdapter(PropertyAccessImpl.java:93)
# org.apache.tapestry.ioc.internal.services.PropertyAccessImpl.getAdapter(PropertyAccessImpl.java:65)
# org.apache.tapestry.internal.services.BeanModelSourceImpl.create(BeanModelSourceImpl.java:74)
# org.apache.tapestry.corelib.components.Grid$1.get(Grid.java:336)
# org.apache.tapestry.internal.structure.InternalComponentResourcesImpl.readParameter(InternalComponentResourcesImpl.java:233)
# org.apache.tapestry.internal.structure.InternalComponentResourcesImpl.readParameter(InternalComponentResourcesImpl.java:248)
# org.apache.tapestry.corelib.components.Grid._$read_parameter_model(Grid.java)
# org.apache.tapestry.corelib.components.Grid.setupDataSource(Grid.java:382)
# org.apache.tapestry.corelib.components.Grid.setupRender(Grid.java:367)
# org.apache.tapestry.corelib.components.Grid.setupRender(Grid.java)

It doesn't matter if I add data to my original foo instance for all
the fields, same result.   However, if I fold the implementation of
Baz into Bla, I render fine.  Thoughts?
-- 
Bill @ PeoplePad

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org


Re: T5: A problem with generics in data classes

Posted by Bill Holloway <bi...@peoplepad.com>.
I think the problem in
org.apache.tapestry.ioc.internal.util.GenericsUtils is that the
extractGenericReturnType only checks in the first generic super class
of the type.  But the type may have more than one superclass with
generics.  Here is an alternative that recursively searches up the
type hierarchy for a  TypeVariable match:

public static Class extractGenericReturnType (Class clazz, Method method)
    {
        Class returnType = method.getReturnType();

        Type methodReturnType = method.getGenericReturnType();

        if (methodReturnType instanceof TypeVariable)
        {
            TypeVariable methodTypeVariable = (TypeVariable) methodReturnType;
            return findTypeVariableClass( clazz.getSuperclass(),
clazz, methodTypeVariable );
        }

        return returnType;
    }

    private static Class findTypeVariableClass (Class clazz, Class
subClazz, TypeVariable methodTypeVariable)
    {
        if (clazz != null)
        {
            TypeVariable[] tvs = clazz.getTypeParameters();
            for (int i = 0; i < tvs.length; i++)
            {
                TypeVariable tv = tvs[i];
                if (tv.equals(methodTypeVariable))
                {
                    ParameterizedType ptype = (ParameterizedType)
subClazz.getGenericSuperclass();
                    Type actualType = ptype.getActualTypeArguments()[i];
                    if (actualType instanceof Class) return (Class) actualType;
                }
            }
            return findTypeVariableClass( clazz.getSuperclass(),
clazz, methodTypeVariable );
        }
        return null;
    }

On Mon, May 26, 2008 at 12:47 AM, Bill Holloway <bi...@peoplepad.com> wrote:
> Hi, I'm illustrating an interesting issue with generic classes in our
> data model.  Here is the very simple page class and template used:
>
> public class TestPageGenericProb
> {
>    @Property
>    private List<Foo> _foos = new LinkedList<Foo>();
>
>    void setupRender ()
>    {
>        Foo f1 = new Foo();
>        _foos.add( f1 );
>    }
> }
>
> TestPageGenericProb.tml:
>
> <html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd">
> <body>
>    <t:grid source="foos" />
> </body>
> </html>
>
> The data classes are
>
> public class Foo extends Bla<String>
> {
>    private Long _id;
>    public Long getId () { return _id; }
>    public void setId (Long id) { _id = id; }
> }
>
> public abstract class Bla<U> extends Baz<U, Integer>
> {
> }
>
> public abstract class Baz <V, W>
> {
>    private W _dealyBob;
>    public W getDealyBob () { return _dealyBob; }
>    public void setDealyBob (W dealyBob) { _dealyBob = dealyBob; }
> }
>
> On visiting the page, I get Render queue error in
> SetupRender[TestPageGenericProb:grid]: Failure reading parameter
> 'model' of component TestPageGenericProb:grid:
> java.lang.ArrayIndexOutOfBoundsException: 1.
>
> The first several elements of the stack trace are:
>
> # org.apache.tapestry.ioc.internal.util.GenericsUtils.extractGenericReturnType(GenericsUtils.java:75)
> # org.apache.tapestry.ioc.internal.services.ClassPropertyAdapterImpl.<init>(ClassPropertyAdapterImpl.java:47)
> # org.apache.tapestry.ioc.internal.services.PropertyAccessImpl.buildAdapter(PropertyAccessImpl.java:93)
> # org.apache.tapestry.ioc.internal.services.PropertyAccessImpl.getAdapter(PropertyAccessImpl.java:65)
> # org.apache.tapestry.internal.services.BeanModelSourceImpl.create(BeanModelSourceImpl.java:74)
> # org.apache.tapestry.corelib.components.Grid$1.get(Grid.java:336)
> # org.apache.tapestry.internal.structure.InternalComponentResourcesImpl.readParameter(InternalComponentResourcesImpl.java:233)
> # org.apache.tapestry.internal.structure.InternalComponentResourcesImpl.readParameter(InternalComponentResourcesImpl.java:248)
> # org.apache.tapestry.corelib.components.Grid._$read_parameter_model(Grid.java)
> # org.apache.tapestry.corelib.components.Grid.setupDataSource(Grid.java:382)
> # org.apache.tapestry.corelib.components.Grid.setupRender(Grid.java:367)
> # org.apache.tapestry.corelib.components.Grid.setupRender(Grid.java)
>
> It doesn't matter if I add data to my original foo instance for all
> the fields, same result.   However, if I fold the implementation of
> Baz into Bla, I render fine.  Thoughts?
> --
> Bill @ PeoplePad
>



-- 
Bill @ PeoplePad

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org