You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@tapestry.apache.org by Luther Baker <lu...@gmail.com> on 2009/02/17 02:25:14 UTC

rendering hibernate objects

Given two hibernate objects and a many-to-one relationship

school
{
  name
}

student
{
  firstname

  @ManyToOne
  school
}


I want to pass something like this into a BeanEditForm and have the it
invoke school.toString() or possibly, school.getName().

I know I can add a t:Parameter to t:BeanEditForm but it seems that I should
be able to somehow register the School type with Tapestry and have it simply
invoke school.toString() when required to render itself.

I've looked at
http://wiki.apache.org/tapestry/Tapestry5HowToCreateAPropertyEditBlock but
found it a bit confusing. At some high level, is there a brief synopsis of
the different players required to do this?

PropertyEditor
ValueEncoder
DataTypeAnalyzer
PropertyEditContext
@Environmental
the Model ... etc.

Now, on the other hand, is the BeanEditForm really considered just a starter
component and is generally not used for production code? In which case, is
it just fine to come up with custom solutions to determine types and how to
render them? Or is there a strong reason to go through all of this ... when
I want to render a nested Hibernate Entity with a toString().

Thanks,

-Luther

Re: rendering hibernate objects

Posted by "Thiago H. de Paula Figueiredo" <th...@gmail.com>.
Em Tue, 17 Feb 2009 16:48:05 -0300, Luther Baker <lu...@gmail.com>  
escreveu:

> Now consider List.tml:
>
> If I use a t:Grid out of the box, I get a runtime complaint when I try to
> display a Topic,
>     "does not contain a property named 'classification'"
>
> I assume this is because 'Classification' is not on the list of simple  
> types that Tapestry currently knows about. Strings, booleans, numbers,  
> etc.

Absolutely right. :)

> So, I add a defaultDataTypeAnalyzer:
>
>     public static void
> contributeDefaultDataTypeAnalyzer(MappedConfiguration<Class<?>, String>
> configuration)
>     {
>         configuration.add(Classification.class, "classification");
>     }
>
> I'm not sure why assigning the name "classification" Classification  
> suddenly makes this work ...

I guess it works because someone told Tapestry that it is a known type.

> but as soon as I do this, the t:Grid successfully
> displays a Classification column - and populates it by invoking
> Classification.toString(). Is that behavior overridable?

Yes. You would need to give Tapestry a block to render Classifications.  
There, you can do whatever you want.

> Is it safe to say I don't need any other moving parts for this to work  
> this way going forward?

You'll probably want an edition block when you edit Topics . ..

> is there a special way to explicitly control how Classification DISPLAY's
> itself (right now it invokes Classification.toString()) ? (ie: is there a
> group of classes that work together similar to t:BeanEditForm?)

Yes. You would need to give Tapestry a block to render Classifications.  
There, you can do whatever you want.
Grid, BeanEditForm, BeanDisplay, and BeanEditor all use the same  
BeanModel, view block and edit block infrastructure.

> In the t:BeanEditForm - one creates xhtml blocks - but it doesn't appear
> necessary for t:Grid. Is that because t:Grid is only DISPLAYing the
> property?

Yes. From now on, all your questions have already been answered. ;)

-- 
Thiago H. de Paula Figueiredo
Independent Java consultant, developer, and instructor
http://www.arsmachina.com.br/thiago

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


Re: rendering hibernate objects

Posted by "Thiago H. de Paula Figueiredo" <th...@gmail.com>.
Em Tue, 17 Feb 2009 16:55:03 -0300, Luther Baker <lu...@gmail.com>  
escreveu:

> If I am happy with using an Entities toString() method ... is this safe  
> to say:

I guess so.

-- 
Thiago H. de Paula Figueiredo
Independent Java consultant, developer, and instructor
http://www.arsmachina.com.br/thiago

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


Re: rendering hibernate objects

Posted by Luther Baker <lu...@gmail.com>.
If I am happy with using an Entities toString() method ... is this safe to
say:


For DISPLAYing an Entity via its "toString" method in something like t:Grid
or t:BeanDisplay

(1) add a line to AppModule.contributeDefaultDataTypeAnalyzer and
(2) implement toString() on the entity.

    /**
     * Add a PropertyEditor for the <code>Classification</code> data type.
     *
     * @param configuration
     */
    public static void
contributeDefaultDataTypeAnalyzer(MappedConfiguration<Class<?>, String>
configuration)
    {
        configuration.add(Classification.class, "classification");
    }

@Entity
public class Classification implements Serializable, Identifiable,
Comparable<Classification>
{
   ....

    private String name;

   ...

   @Override
    public String toString()
    {
        return this.name;
    }
}


-Luther




On Tue, Feb 17, 2009 at 1:48 PM, Luther Baker <lu...@gmail.com> wrote:

> Thanks both of you for your explanations - if you've got a bit of patience
> with me, I need to walk through my thoughts to better understand the big
> picture here. Thanks in advance for your points and help - they are very
> helpful.
>
>
> Ok, to set the stage in a little more detail: consider a basic GRAILS or
> CRUD style app where my views are List.tml, Edit.tml and Show.tml.
>
>
> I've broken this up into a few posts - in this response, *I'll focus on
> List.tml, t:Grid and t:BeanDisplay* -- afterwhich, I'll try to segway into
> a post that leverages this information to discuss t:BeanEditForm.
>
> In this example, I'm using Topics and Classifications. Both are simple
> entities - a Topic has a @ManyToOne relationship to Classifications. Each
> Topic contains exactly one Classification. Many Topics can refer to the same
> Classification but again, any single Topic has exactly one Classification.
>
>
> @Entity
> public class Classification
> {
>     @Id
>     @GeneratedValue(strategy = GenerationType.TABLE)
>     private Integer id;
>
>     private String name;
> ...
> }
>
>
> @Entity
> public class Topic
> {
>     @Id
>     @GeneratedValue(strategy = GenerationType.TABLE)
>     private Integer id;
>
>     @ManyToOne
>     private Classification classification;
> ...
> }
>
>
> Now consider List.tml:
>
> If I use a t:Grid out of the box, I get a runtime complaint when I try to
> display a Topic,
>
>     "does not contain a property named 'classification'"
>
> I assume this is because 'Classification' is not on the list of simple
> types that Tapestry currently knows about. Strings, booleans, numbers, etc.
> So, I add a defaultDataTypeAnalyzer:
>
>     public static void
> contributeDefaultDataTypeAnalyzer(MappedConfiguration<Class<?>, String>
> configuration)
>     {
>         configuration.add(Classification.class, "classification");
>     }
>
> I'm not sure why assigning the name "classification" Classification
> suddenly makes this work ... but as soon as I do this, the t:Grid
> successfully displays a Classification column - and populates it by invoking
> Classification.toString(). Is that behavior overridable? Is it safe to say I
> don't need any other moving parts for this to work this way going forward?
>
> My next post will talk about BeanEditForm which I understand uses a
> BeanModel, PropertyEditor, blocks etc - but as far as t:Grid is concerned -
> is there a special way to explicitly control how Classification DISPLAY's
> itself (right now it invokes Classification.toString()) ? (ie: is there a
> group of classes that work together similar to t:BeanEditForm?)
>
> In the t:BeanEditForm - one creates xhtml blocks - but it doesn't appear
> necessary for t:Grid. Is that because t:Grid is only DISPLAYing the
> property?
>
> When I use t:BeanDisplay, the same thing happens, Classification.toString()
> is invoked. That all sounds good and reasonable - I am just curious how, in
> a DISPLAY scenario, if there is a programmatic way to override the behavior?
>
> And, as a side note, looking for a brief explanation as to why
> 'contributeDefaultDataTypeAnalyzer' makes this work.
>
> End of Part 1 :) DISPLAYing hibernate entities: t:Grid and t:BeanDisplay
> ... is it simpler than t:BeanEditForm? and can I override the toString
> invocation and why does contributeDefaultDataTypeAnalyzer have to happen
> here?
>
> Always happy to look at docs for this if you have any links to show.
>
> Thanks very much - I'm off to try some of the notes for t:BeanEditForm and
> I'll get back to you.
>
> -Luther
>
>
>
>
> On Tue, Feb 17, 2009 at 5:34 AM, Ulrich Stärk <ul...@spielviel.de> wrote:
>
>> Here is your overview (assuming that you want to render your list of
>> schools using a select component):
>>
>> SelectModel
>>
>> This is a model of the data you want to render. This could be backed by a
>> list or some other collection type (there is a type coercer from list to
>> selectmodel build into tapestry which automatically converts the one into
>> the other). In your case you will want to populate this model with the
>> available schools.
>>
>> ValueEncoder
>>
>> As Thiago already pointed out, this is needed to convert from object to
>> presentation and back.
>>
>> GenericSelectModel
>>
>> Search for it in the wiki. It's user-contributed and implements both the
>> SelectModel and the ValueEncoder interfaces. In its constructor, you pass it
>> the type you want to create a model/encoder for, the list of available items
>> (schools in your case), the name of the id property and the name of the
>> property used to display to the user (if null, toString() will be used).
>>
>> AppPropertyEditBlocks
>>
>> The name of a page where you define a block used for rendering your custom
>> type (school). This name is arbitrary and can be whatever you like it to be.
>> Here you wire up the select component with your model and encoder. In the
>> page template you define some block whith an explicit id (e.g. schoolBlock).
>>
>> AppModule
>>
>> In your AppModule you have to make contributions to the
>> DefaultDataTypeAnalyzer and the BeanBlockSource services.
>>
>> public static void contributeDefaultDataTypeAnalyzer(
>>            MappedConfiguration<Class, String> configuration)
>> {
>>    configuration.add(School.class, "school");
>> }
>>
>> This will assign the name school to your school type for use within
>> tapestry.
>>
>> With
>>
>> public static void
>> contributeBeanBlockSource(Configuration<BeanBlockContribution>
>> configuration)
>> {
>>    configuration.add(new BeanBlockContribution("school",
>> "AppPropertyEditBlocks", "schoolBlock",
>>                true));
>> }
>>
>> you tell Tapestry to render a property of type school with the block
>> "schoolBlock" inside the AppPropertyEditBlocks page.
>>
>> HTH,
>>
>> Uli
>>
>> Luther Baker schrieb:
>>
>>  Given two hibernate objects and a many-to-one relationship
>>>
>>> school
>>> {
>>>  name
>>> }
>>>
>>> student
>>> {
>>>  firstname
>>>
>>>  @ManyToOne
>>>  school
>>> }
>>>
>>>
>>> I want to pass something like this into a BeanEditForm and have the it
>>> invoke school.toString() or possibly, school.getName().
>>>
>>> I know I can add a t:Parameter to t:BeanEditForm but it seems that I
>>> should
>>> be able to somehow register the School type with Tapestry and have it
>>> simply
>>> invoke school.toString() when required to render itself.
>>>
>>> I've looked at
>>> http://wiki.apache.org/tapestry/Tapestry5HowToCreateAPropertyEditBlockbut
>>> found it a bit confusing. At some high level, is there a brief synopsis
>>> of
>>> the different players required to do this?
>>>
>>> PropertyEditor
>>> ValueEncoder
>>> DataTypeAnalyzer
>>> PropertyEditContext
>>> @Environmental
>>> the Model ... etc.
>>>
>>> Now, on the other hand, is the BeanEditForm really considered just a
>>> starter
>>> component and is generally not used for production code? In which case,
>>> is
>>> it just fine to come up with custom solutions to determine types and how
>>> to
>>> render them? Or is there a strong reason to go through all of this ...
>>> when
>>> I want to render a nested Hibernate Entity with a toString().
>>>
>>> Thanks,
>>>
>>> -Luther
>>>
>>>
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
>> For additional commands, e-mail: users-help@tapestry.apache.org
>>
>>
>

Re: rendering hibernate objects

Posted by Luther Baker <lu...@gmail.com>.
Whoa - stepping through a Tapestry request cycle, now that is alot of
dynamic code! It was a bit difficult to follow all that jit thread-specific
object creation ... especially since things were happening in placed I
didn't have breakcpoints ... but eventually, I think I got what I needed.

Basically, I built a translator for the t:TextField and added it to the
AppModule via contributeTranslatorSource.

Then, I changed the DISPLAY block Java code to use a Property*Output*Context
whilst the EDIT block code uses the Property*Edit*Context and whalah - it
seems to work.

I didn't have to mess with ValueEncoders or BeanModels at all - but I've not
implemented the SelectModel yet. That is tomorrow.

I do have one more question, my translator extends AbstractTranslator and
therefore must implement parseClient. My question is ... is it normal to
@Inject daos or hibernate services into something like a Translator? I'm not
sure how else to hydrate my Entity in the parseClient method ... but that
sounds like I'm adding alot of weight to that Translator. Is that normal? If
not, is there a better approach for that?

Thanks,

-Luther




On Tue, Feb 17, 2009 at 5:57 PM, Thiago H. de Paula Figueiredo <
thiagohp@gmail.com> wrote:

> Em Tue, 17 Feb 2009 20:25:49 -0300, Luther Baker <lu...@gmail.com>
> escreveu:
>
>  I had to strip a few parameters out and print literals for now. My next
>> question ... is how to get MY data into that class.
>>
>
> That's why @Environmental private PropertyEditContext context is there. ;)
> It is the bridge that takes you to the edited value.
>
>     @Property
>>    @Component(parameters =
>>    { "value=context.propertyValue" })
>>
>
>  Ah - (#1) I thought this was going to work - since only one or the other
>> block would be used at any given time. Since we are using the same java
>> class for either / or block ... it strikes me that I can't reuse t:id.
>>
>
> It doesn't matter if you use a component or not, they should have unique
> t:id's. If they're not unique, they aren't ids. ;) Don't forget that this is
> an ordinary page.
>
>  Does the corresponding Java class somehow discriminate and use my same
>> classification property object but with multiple ids? I think I'm
>> confusing
>> things - partly because I have little component writing experience.
>>
>
> When you inject a component in a page, you have to tell Tapestry what is
> its t:id. The name of the field is one way to do it. The other ones is
> @Component(id="someId").
>
>  but I'm not sure what to do to get that working. What is a 'translator'
>> and how do I write one ... and attach it to the context? And ... are those
>> appropriate questions?
>>
>
> Instead of trial and error, grap Tapestry's source code and read the
> PropertyEditBlocks class. It is where the Tapestry-provided blocks are
> declared. They should give you some hints. Use it as a starting point.
>
>  but that didn't turn out so well. "Could not convert '
>> context.propertyValue.name' into a component parameter binding
>>
>
> The return value of PropertyEditContext.getPropertyValue() is Object. By
> the way, it is exactly the property you're trying to edit, so there's no
> need to reference property names here.
>
>
> --
> Thiago H. de Paula Figueiredo
> Independent Java consultant, developer, and instructor
> http://www.arsmachina.com.br/thiago
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
> For additional commands, e-mail: users-help@tapestry.apache.org
>
>

Re: rendering hibernate objects

Posted by Luther Baker <lu...@gmail.com>.
>
> Ah - (#1) I thought this was going to work - since only one or the other
> block would be used at any given time. Since we are using the same java
> class for either / or block ... it strikes me that I can't reuse t:id.
>

> It doesn't matter if you use a component or not, they should have unique
t:id's. If they're not unique, they aren't ids. ;) Don't forget that this is
an ordinary page.


I'm with you here - what confused me is that in this case, my .tml file has
two blocks - of which only one will ever get used (depending on whether or
not we are editing). To mirror that, I guess the corresponding Java class
would likely have two properties, only one of which is used depending on the
behavior of that component.

Off to the source ...ahem, may the source be with you :)

Thanks.

-Luther




On Tue, Feb 17, 2009 at 5:57 PM, Thiago H. de Paula Figueiredo <
thiagohp@gmail.com> wrote:

> Em Tue, 17 Feb 2009 20:25:49 -0300, Luther Baker <lu...@gmail.com>
> escreveu:
>
>  I had to strip a few parameters out and print literals for now. My next
>> question ... is how to get MY data into that class.
>>
>
> That's why @Environmental private PropertyEditContext context is there. ;)
> It is the bridge that takes you to the edited value.
>
>     @Property
>>    @Component(parameters =
>>    { "value=context.propertyValue" })
>>
>
>  Ah - (#1) I thought this was going to work - since only one or the other
>> block would be used at any given time. Since we are using the same java
>> class for either / or block ... it strikes me that I can't reuse t:id.
>>
>
> It doesn't matter if you use a component or not, they should have unique
> t:id's. If they're not unique, they aren't ids. ;) Don't forget that this is
> an ordinary page.
>
>  Does the corresponding Java class somehow discriminate and use my same
>> classification property object but with multiple ids? I think I'm
>> confusing
>> things - partly because I have little component writing experience.
>>
>
> When you inject a component in a page, you have to tell Tapestry what is
> its t:id. The name of the field is one way to do it. The other ones is
> @Component(id="someId").
>
>  but I'm not sure what to do to get that working. What is a 'translator'
>> and how do I write one ... and attach it to the context? And ... are those
>> appropriate questions?
>>
>
> Instead of trial and error, grap Tapestry's source code and read the
> PropertyEditBlocks class. It is where the Tapestry-provided blocks are
> declared. They should give you some hints. Use it as a starting point.
>
>  but that didn't turn out so well. "Could not convert '
>> context.propertyValue.name' into a component parameter binding
>>
>
> The return value of PropertyEditContext.getPropertyValue() is Object. By
> the way, it is exactly the property you're trying to edit, so there's no
> need to reference property names here.
>
>
> --
> Thiago H. de Paula Figueiredo
> Independent Java consultant, developer, and instructor
> http://www.arsmachina.com.br/thiago
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
> For additional commands, e-mail: users-help@tapestry.apache.org
>
>

Re: rendering hibernate objects

Posted by "Thiago H. de Paula Figueiredo" <th...@gmail.com>.
Em Tue, 17 Feb 2009 20:25:49 -0300, Luther Baker <lu...@gmail.com>  
escreveu:

> I had to strip a few parameters out and print literals for now. My next
> question ... is how to get MY data into that class.

That's why @Environmental private PropertyEditContext context is there. ;)  
It is the bridge that takes you to the edited value.

>     @Property
>     @Component(parameters =
>     { "value=context.propertyValue" })

> Ah - (#1) I thought this was going to work - since only one or the other
> block would be used at any given time. Since we are using the same java
> class for either / or block ... it strikes me that I can't reuse t:id.

It doesn't matter if you use a component or not, they should have unique  
t:id's. If they're not unique, they aren't ids. ;) Don't forget that this  
is an ordinary page.

> Does the corresponding Java class somehow discriminate and use my same
> classification property object but with multiple ids? I think I'm  
> confusing
> things - partly because I have little component writing experience.

When you inject a component in a page, you have to tell Tapestry what is  
its t:id. The name of the field is one way to do it. The other ones is  
@Component(id="someId").

> but I'm not sure what to do to get that working. What is a 'translator'  
> and how do I write one ... and attach it to the context? And ... are  
> those
> appropriate questions?

Instead of trial and error, grap Tapestry's source code and read the  
PropertyEditBlocks class. It is where the Tapestry-provided blocks are  
declared. They should give you some hints. Use it as a starting point.

> but that didn't turn out so well. "Could not convert '
> context.propertyValue.name' into a component parameter binding

The return value of PropertyEditContext.getPropertyValue() is Object. By  
the way, it is exactly the property you're trying to edit, so there's no  
need to reference property names here.

-- 
Thiago H. de Paula Figueiredo
Independent Java consultant, developer, and instructor
http://www.arsmachina.com.br/thiago

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


Re: rendering hibernate objects

Posted by Luther Baker <lu...@gmail.com>.
Got it! I can see my blocks rendering appropriately for both editable and
non-editable fields.

To come full circle, I need to better understand AppPropertyEditBlock.java.

I had to strip a few parameters out and print literals for now. My next
question ... is how to get MY data into that class.

public class AppPropertyEditBlocks
{
    @Environmental
    private PropertyEditContext context;

    @Property
    @Component(parameters =
    { "value=literal:cool class" })
    private TextField classification;

    public PropertyEditContext getContext()
    {
        return context;
    }

    public FieldValidator<Classification> getClassificationValidator()
    {
        return context.getValidator(classification);
    }

    public FieldTranslator<Classification> getClassificationTranslator()
    {
        return context.getTranslator(classification);
    }
}


<div xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd">
    <t:block t:id="readableClassificationBlock">
        This came from AppPropertyEditBlocks.readableClassificationBlock ...

    </t:block>
    <t:block t:id="editableClassificationBlock">
        This came from AppPropertyEditBlocks.editableClassificationBlock ...
<t:textfield t:id="classification" size="10"/>
    </t:block>
</div>

This works - but obviously puts "cool class" into the textfield.

Incremental changes:

<div xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd">
    <t:block t:id="readableClassificationBlock">
        This came from AppPropertyEditBlocks.readableClassificationBlock ...

    </t:block>
    <t:block t:id="editableClassificationBlock">
        This came from AppPropertyEditBlocks.editableClassificationBlock ...
<t:textfield t:id="classification" size="10"/>
    </t:block>
</div>

Errors with: Component AppPropertyEditBlocks already contains a child
component with id 'classification'. Embedded component ids must be unique
(excluding case, which is ignored).

Ah - (#1) I thought this was going to work - since only one or the other
block would be used at any given time. Since we are using the same java
class for either / or block ... it strikes me that I can't reuse t:id. Does
the corresponding Java class somehow discriminate and use my same
classification property object but with multiple ids? I think I'm confusing
things - partly because I have little component writing experience.

(#2) mm ... how do I get ahold of my Classification value ;) I think it must
have something to do with the PropertyEditContext but changes like this

    @Property
    @Component(parameters =
    { "value=context.propertyValue",
"translate=prop:classificationTranslator" })
    private TextField classification;

aren't quite enough. the DISPLAY block works just fine (no property is in
that block) but when using the BeanEditForm, I get an error: "Parameter
'translate' of component AppPropertyEditBlocks:classification is bound to
null. This parameter is not allowed to be null." I think that error must be
related to the method

    public FieldTranslator<Classification> getClassificationTranslator()
    {
        return context.getTranslator(classification);
    }

but I'm not sure what to do to get that working. What is a 'translator' and
how do I write one ... and attach it to the context? And ... are those
appropriate questions?

As a side note, my guess is that PropertyEditContext magically encapsulates
the 'classification' object I am trying to render. I tried this

    @Component(parameters =
    { "value=context.propertyValue.*name*",
"translate=prop:classificationTranslator" })

but that didn't turn out so well. "Could not convert '
context.propertyValue.name' into a component parameter binding: Class
java.lang.Object does not contain a property named 'name' (within property
expression 'context.propertyValue.name'). Available properties: class."

Thoughts? Maybe how does my "Classification" object get here ... and how do
I access it's properties ... and how do I attach translator ... or even a
validator if I've not defined one?

Thanks again,

-Luther



On Tue, Feb 17, 2009 at 3:47 PM, Thiago H. de Paula Figueiredo <
thiagohp@gmail.com> wrote:

> Em Tue, 17 Feb 2009 18:42:22 -0300, Luther Baker <lu...@gmail.com>
> escreveu:
>
>  You guys are great! Making more sense all the time...
>>
>
> You have just said nonsense! :p
>
>  Create and Edit (uses editable block) pages - Tapestry can't seem to find:
>> AppPropertyEditBlocks.tml
>>
>
> AppPropertyEditBlocks, or any other name you fancy, is an ordinary page
> (besides the fact that it won't be used to render HTML), so it must be its
> own class, located at the *pages* package. It's tml file should be at the
> same place you put your 'real' page templates.
>
>
> --
> Thiago H. de Paula Figueiredo
> Independent Java consultant, developer, and instructor
> http://www.arsmachina.com.br/thiago
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
> For additional commands, e-mail: users-help@tapestry.apache.org
>
>

Re: rendering hibernate objects

Posted by "Thiago H. de Paula Figueiredo" <th...@gmail.com>.
Em Tue, 17 Feb 2009 18:42:22 -0300, Luther Baker <lu...@gmail.com>  
escreveu:

> You guys are great! Making more sense all the time...

You have just said nonsense! :p

> Create and Edit (uses editable block) pages - Tapestry can't seem to  
> find: AppPropertyEditBlocks.tml

AppPropertyEditBlocks, or any other name you fancy, is an ordinary page  
(besides the fact that it won't be used to render HTML), so it must be its  
own class, located at the *pages* package. It's tml file should be at the  
same place you put your 'real' page templates.

-- 
Thiago H. de Paula Figueiredo
Independent Java consultant, developer, and instructor
http://www.arsmachina.com.br/thiago

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


Re: rendering hibernate objects

Posted by Luther Baker <lu...@gmail.com>.
You guys are great! Making more sense all the time...

Ok, here is a small remaining problem and it is related to finding the
AppPropertyEditBlocks (tml and java) artifacts. I've included each step here
just to be sure I understand how the fit together. I intentionally left off
the SelectModel for this - as I want to understand that I can do that
'next'. That does mean that I hope the Textfield solution (from the
tutorial) just 'works' for me in this case. Trying to keep the things I'm
adding and changing as incremental as I can.


<shortVersion>
After adding the AppPropertyEdtBlocks.tml and corresponding entries
tocontributeBeanBlockSource, When I visit the List (uses readble block) or
Create and Edit (uses editable block) pages - Tapestry can't seem to find:
AppPropertyEditBlocks.tml

ERROR:

Render queue error in BeginRender[topic/Create:topic.editor.propertyeditor]:
Unable to locate a block to edit property 'classification' (with data type
'classification') of object { Topic { null }}: Unable to resolve
'AppPropertyEditBlocks' to a known page name

Right now - it is under the services directory (alongside AppModule and
AppPropertyEditBlocks.java) and I've confirmed that it is in indeed being
copied out to the target directory.
</shortVersion>



Ok, here we go with the Edit stuff :) To keep this simple, I am happy using
a TextField for now as the online tutorial has. Once I can get this wired up
and working - I can try it with the SelectModel.



1. added src/main/java/${app.home}/services/AppPropertyEditBlocks.java

public class AppPropertyEditBlocks
{
    @Environmental
    private PropertyEditContext context;

    @Component(parameters =
    { "value=context.name", "label=prop:context.label",
"translate=prop:classificationTranslator",
"validate=prop:classificationValidator", "clientId=prop:context.propertyId"
})
    private TextField classification;

    public PropertyEditContext getContext()
    {
        return context;
    }

    public FieldValidator<Classification> getClassificationValidator()
    {
        return context.getValidator(classification);
    }

    public FieldTranslator<Classification> getClassificationTranslator()
    {
        return context.getTranslator(classification);
    }
}

context.getTranslator and context.getValidator are not typed (so I get
warning in Eclipse) but otherwise - no errors. I don't exactly know how this
class works yet - or what role it plays but I know it ties in with the
corresponding tml file. I am fine with a simple example for now so I'm just
copying from the online tutorial - using Textfield - I hope 'classification'
works ok as a TextField ... but hoping at least the error can tell me what
to do next. Is there a page that focuses directly or indirectly on this
Class and what it does/needs, etc? For now - I copied. How does context get
all this info? I see the @Component annotation which I've seen docs for ...
I've just not needed it yet. Are those parameters well known and well
documented in places like this
http://tapestry.apache.org/tapestry5/guide/component-classes.html

I'm trying to abstractly match up the arguments to @Component and wondering
to myself "What is context.name ... and do I need a property called
context.label ... and what do I need a translator for ... ". At any rate -
don't spend too much time answering these questions as I will dig deeper for
this. These were just my initial thoughts and if there are some high level
guidelines, I'd appreciate those.



2. Added src/main/resources/${app.home}/services/AppPropertyEditBlocks.java

<div xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd">
    <t:block t:id="readableClassificationBlock">
        This came from AppPropertyEditBlocks.readableClassificationBlock ...
${classification.name}
    </t:block>
    <t:block t:id="editableClassificationBlock">
        This came from AppPropertyEditBlocks.editableClassificationBlock ...
<t:textfield t:id="classification" size="10"/>
    </t:block>
</div>



3. Add contributions to
src/main/resources/${app.home}/services/AppModule.java


    /**
     * Associate keys with data types.
     *
     * @param configuration
     */
    public static void
contributeDefaultDataTypeAnalyzer(MappedConfiguration<Class<?>, String>
config
    {
        config.add(Classification.class, "classification");
    }

    /**
     * Link custom data types to block ids.
     *
     * @param config
     */
    public void
contributeBeanBlockSource(Configuration<BeanBlockContribution> config)
    {
        config.add(new BeanBlockContribution("classification",
"AppPropertyEditBlocks", "readableClassificationBlock", true));
        config.add(new BeanBlockContribution("classification",
"AppPropertyEditBlocks", "editableClassificationBlock", false));
    }



4. Add the page with the t:BeanEditForm,
src/main/resources/${app.home}/pages/topic/CreateTopic.java

<t:Layout xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd">
    <ul class="links">
        <li><t:PageLink page="topic/ListTopics">List
Topics</t:PageLink></li>
        <li><t:PageLink page="topic/CreateTopic">Create
Topic</t:PageLink></li>
    </ul>
    <h2>Edit Topic</h2>
    <t:BeanEditForm t:id="topic" exclude="id,createdOn,modifiedOn"
reorder="name,details,comments,tags,classification" add="delete">
        <t:Parameter name="delete"><t:ActionLink t:Id="Delete" context="
topic.id">Delete</t:ActionLink></t:Parameter>
    </t:BeanEditForm>
</t:Layout>



5. Add another page with the t:BeanEditForm,
src/main/resources/${app.home}/pages/topic/EditTopic.java

<t:Layout xmlns:t="http://tapestry.apache.org/schema/tapestry_5_0_0.xsd">
    <ul class="links">
        <li><t:PageLink page="topic/ListTopics">List Topic</t:PageLink></li>
    </ul>
    <h2>Create Topic</h2>
    <t:BeanEditForm t:id="topic" exclude="id,createdOn,modifiedOn"
reorder="name,details,comments,tags,classification"/>
</t:Layout>



When I visit the CREATE or EDIT pages listed here - it gets closer but can't
seem to find: AppPropertyEditBlocks.tml

ERROR:

Render queue error in BeginRender[topic/Create:topic.editor.propertyeditor]:
Unable to locate a block to edit property 'classification' (with data type
'classification') of object { Topic { null }}: Unable to resolve
'AppPropertyEditBlocks' to a known page name

Right now - it is under the services directory (alongside AppModule and
AppPropertyEditBlocks.java) and I've confirmed that it is in the TARGET
directory.

I really think this is a trivial error ... but I've moved those two files
around to the pages dir, the components dir and the services dir ... but
always the same error. Seems to me my blocks pages isn't getting picked up
... Thoughts?

-Luther


On Tue, Feb 17, 2009 at 3:24 PM, Thiago H. de Paula Figueiredo <
thiagohp@gmail.com> wrote:

> Em Tue, 17 Feb 2009 18:13:51 -0300, Luther Baker <lu...@gmail.com>
> escreveu:
>
>  It trickie since it seems that Tapestry could call toString() on anything
>> without requiring this registration step. In this simplistic case,
>> registration didn't really tell it anything. But - given this registration
>> step - a few things make sense like ... before doing this, listing the
>> column name in the reorder clause of a t:grid was throwing an exception.
>>
>
> This exception happened because BeanModelSource didn't create a in a
> BeanModel property for Topic's classification property because it didn't
> know the Tapestry type for the Classification class. It's a very different
> issue.
>
>  :) One day - I hope to contribute BACK to Tapestry and than ... will have
>> arrived.
>>
>
> Everybody needs help and everybody can help. :)
> I didn't know that just providing a Tapestry type for a class would make
> BeanModelSource handle it. I learned something today. :)
>
>  Thanks for your timely input. One last post on the way.
>>
>
> You're welcome! :)
>
> --
> Thiago H. de Paula Figueiredo
> Independent Java consultant, developer, and instructor
> http://www.arsmachina.com.br/thiago
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
> For additional commands, e-mail: users-help@tapestry.apache.org
>
>

Re: rendering hibernate objects

Posted by "Thiago H. de Paula Figueiredo" <th...@gmail.com>.
Em Tue, 17 Feb 2009 18:13:51 -0300, Luther Baker <lu...@gmail.com>  
escreveu:

> It trickie since it seems that Tapestry could call toString() on anything
> without requiring this registration step. In this simplistic case,
> registration didn't really tell it anything. But - given this  
> registration
> step - a few things make sense like ... before doing this, listing the
> column name in the reorder clause of a t:grid was throwing an exception.

This exception happened because BeanModelSource didn't create a in a  
BeanModel property for Topic's classification property because it didn't  
know the Tapestry type for the Classification class. It's a very different  
issue.

> :) One day - I hope to contribute BACK to Tapestry and than ... will have
> arrived.

Everybody needs help and everybody can help. :)
I didn't know that just providing a Tapestry type for a class would make  
BeanModelSource handle it. I learned something today. :)

> Thanks for your timely input. One last post on the way.

You're welcome! :)

-- 
Thiago H. de Paula Figueiredo
Independent Java consultant, developer, and instructor
http://www.arsmachina.com.br/thiago

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


Re: rendering hibernate objects

Posted by Luther Baker <lu...@gmail.com>.
@Uli

false - that makes sense. I will apply it in my next post which actually
uses this method.


@Thiago

>> I'm not sure why assigning the name "classification" Classification
suddenly makes this work ...

> I guess it works because someone told Tapestry that it is a known type.

Yes - but doesn't every Java type have a toString method? And the trivial
registration did nothing (on appearance) but associate a key with a class.
It trickie since it seems that Tapestry could call toString() on anything
without requiring this registration step. In this simplistic case,
registration didn't really tell it anything. But - given this registration
step - a few things make sense like ... before doing this, listing the
column name in the reorder clause of a t:grid was throwing an exception. So
I gotcha, registration is required to tell Tapestry about this object -
plain and simple. Then, tweak as you like by using the blocks.

>> From now on, all your questions have already been answered. ;)

:) One day - I hope to contribute BACK to Tapestry and than ... will have
arrived.


Thanks for your timely input. One last post on the way.

-Luther



On Tue, Feb 17, 2009 at 2:04 PM, Ulrich Stärk <ul...@spielviel.de> wrote:

> If you want to specify a block for displaying your type, you just do the
> same as with the editor but instead you contribute it with
>
> public static void
> contributeBeanBlockSource(Configuration<BeanBlockContribution>
> configuration)
> {
>    configuration.add(new BeanBlockContribution("school",
> "AppPropertyEditBlocks", "schoolViewBlock",
>                false));
> }
>
> (notice the false parameter now)
>
> Cheers,
>
> Uli
>
> Luther Baker schrieb:
>
>  Thanks both of you for your explanations - if you've got a bit of patience
>> with me, I need to walk through my thoughts to better understand the big
>> picture here. Thanks in advance for your points and help - they are very
>> helpful.
>>
>>
>> Ok, to set the stage in a little more detail: consider a basic GRAILS or
>> CRUD style app where my views are List.tml, Edit.tml and Show.tml.
>>
>>
>> I've broken this up into a few posts - in this response, *I'll focus on
>> List.tml, t:Grid and t:BeanDisplay* -- afterwhich, I'll try to segway into
>> a
>> post that leverages this information to discuss t:BeanEditForm.
>>
>> In this example, I'm using Topics and Classifications. Both are simple
>> entities - a Topic has a @ManyToOne relationship to Classifications. Each
>> Topic contains exactly one Classification. Many Topics can refer to the
>> same
>> Classification but again, any single Topic has exactly one Classification.
>>
>>
>> @Entity
>> public class Classification
>> {
>>    @Id
>>    @GeneratedValue(strategy = GenerationType.TABLE)
>>    private Integer id;
>>
>>    private String name;
>> ...
>> }
>>
>>
>> @Entity
>> public class Topic
>> {
>>    @Id
>>    @GeneratedValue(strategy = GenerationType.TABLE)
>>    private Integer id;
>>
>>    @ManyToOne
>>    private Classification classification;
>> ...
>> }
>>
>>
>> Now consider List.tml:
>>
>> If I use a t:Grid out of the box, I get a runtime complaint when I try to
>> display a Topic,
>>
>>    "does not contain a property named 'classification'"
>>
>> I assume this is because 'Classification' is not on the list of simple
>> types
>> that Tapestry currently knows about. Strings, booleans, numbers, etc. So,
>> I
>> add a defaultDataTypeAnalyzer:
>>
>>    public static void
>> contributeDefaultDataTypeAnalyzer(MappedConfiguration<Class<?>, String>
>> configuration)
>>    {
>>        configuration.add(Classification.class, "classification");
>>    }
>>
>> I'm not sure why assigning the name "classification" Classification
>> suddenly
>> makes this work ... but as soon as I do this, the t:Grid successfully
>> displays a Classification column - and populates it by invoking
>> Classification.toString(). Is that behavior overridable? Is it safe to say
>> I
>> don't need any other moving parts for this to work this way going forward?
>>
>> My next post will talk about BeanEditForm which I understand uses a
>> BeanModel, PropertyEditor, blocks etc - but as far as t:Grid is concerned
>> -
>> is there a special way to explicitly control how Classification DISPLAY's
>> itself (right now it invokes Classification.toString()) ? (ie: is there a
>> group of classes that work together similar to t:BeanEditForm?)
>>
>> In the t:BeanEditForm - one creates xhtml blocks - but it doesn't appear
>> necessary for t:Grid. Is that because t:Grid is only DISPLAYing the
>> property?
>>
>> When I use t:BeanDisplay, the same thing happens,
>> Classification.toString()
>> is invoked. That all sounds good and reasonable - I am just curious how,
>> in
>> a DISPLAY scenario, if there is a programmatic way to override the
>> behavior?
>>
>> And, as a side note, looking for a brief explanation as to why
>> 'contributeDefaultDataTypeAnalyzer' makes this work.
>>
>> End of Part 1 :) DISPLAYing hibernate entities: t:Grid and t:BeanDisplay
>> ...
>> is it simpler than t:BeanEditForm? and can I override the toString
>> invocation and why does contributeDefaultDataTypeAnalyzer have to happen
>> here?
>>
>> Always happy to look at docs for this if you have any links to show.
>>
>> Thanks very much - I'm off to try some of the notes for t:BeanEditForm and
>> I'll get back to you.
>>
>> -Luther
>>
>>
>>
>> On Tue, Feb 17, 2009 at 5:34 AM, Ulrich Stärk <ul...@spielviel.de> wrote:
>>
>>  Here is your overview (assuming that you want to render your list of
>>> schools using a select component):
>>>
>>> SelectModel
>>>
>>> This is a model of the data you want to render. This could be backed by a
>>> list or some other collection type (there is a type coercer from list to
>>> selectmodel build into tapestry which automatically converts the one into
>>> the other). In your case you will want to populate this model with the
>>> available schools.
>>>
>>> ValueEncoder
>>>
>>> As Thiago already pointed out, this is needed to convert from object to
>>> presentation and back.
>>>
>>> GenericSelectModel
>>>
>>> Search for it in the wiki. It's user-contributed and implements both the
>>> SelectModel and the ValueEncoder interfaces. In its constructor, you pass
>>> it
>>> the type you want to create a model/encoder for, the list of available
>>> items
>>> (schools in your case), the name of the id property and the name of the
>>> property used to display to the user (if null, toString() will be used).
>>>
>>> AppPropertyEditBlocks
>>>
>>> The name of a page where you define a block used for rendering your
>>> custom
>>> type (school). This name is arbitrary and can be whatever you like it to
>>> be.
>>> Here you wire up the select component with your model and encoder. In the
>>> page template you define some block whith an explicit id (e.g.
>>> schoolBlock).
>>>
>>> AppModule
>>>
>>> In your AppModule you have to make contributions to the
>>> DefaultDataTypeAnalyzer and the BeanBlockSource services.
>>>
>>> public static void contributeDefaultDataTypeAnalyzer(
>>>           MappedConfiguration<Class, String> configuration)
>>> {
>>>   configuration.add(School.class, "school");
>>> }
>>>
>>> This will assign the name school to your school type for use within
>>> tapestry.
>>>
>>> With
>>>
>>> public static void
>>> contributeBeanBlockSource(Configuration<BeanBlockContribution>
>>> configuration)
>>> {
>>>   configuration.add(new BeanBlockContribution("school",
>>> "AppPropertyEditBlocks", "schoolBlock",
>>>               true));
>>> }
>>>
>>> you tell Tapestry to render a property of type school with the block
>>> "schoolBlock" inside the AppPropertyEditBlocks page.
>>>
>>> HTH,
>>>
>>> Uli
>>>
>>> Luther Baker schrieb:
>>>
>>>  Given two hibernate objects and a many-to-one relationship
>>>
>>>> school
>>>> {
>>>>  name
>>>> }
>>>>
>>>> student
>>>> {
>>>>  firstname
>>>>
>>>>  @ManyToOne
>>>>  school
>>>> }
>>>>
>>>>
>>>> I want to pass something like this into a BeanEditForm and have the it
>>>> invoke school.toString() or possibly, school.getName().
>>>>
>>>> I know I can add a t:Parameter to t:BeanEditForm but it seems that I
>>>> should
>>>> be able to somehow register the School type with Tapestry and have it
>>>> simply
>>>> invoke school.toString() when required to render itself.
>>>>
>>>> I've looked at
>>>>
>>>> http://wiki.apache.org/tapestry/Tapestry5HowToCreateAPropertyEditBlockbut
>>>> found it a bit confusing. At some high level, is there a brief synopsis
>>>> of
>>>> the different players required to do this?
>>>>
>>>> PropertyEditor
>>>> ValueEncoder
>>>> DataTypeAnalyzer
>>>> PropertyEditContext
>>>> @Environmental
>>>> the Model ... etc.
>>>>
>>>> Now, on the other hand, is the BeanEditForm really considered just a
>>>> starter
>>>> component and is generally not used for production code? In which case,
>>>> is
>>>> it just fine to come up with custom solutions to determine types and how
>>>> to
>>>> render them? Or is there a strong reason to go through all of this ...
>>>> when
>>>> I want to render a nested Hibernate Entity with a toString().
>>>>
>>>> Thanks,
>>>>
>>>> -Luther
>>>>
>>>>
>>>>  ---------------------------------------------------------------------
>>> To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
>>> For additional commands, e-mail: users-help@tapestry.apache.org
>>>
>>>
>>>
>>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
> For additional commands, e-mail: users-help@tapestry.apache.org
>
>

Re: rendering hibernate objects

Posted by Ulrich Stärk <ul...@spielviel.de>.
If you want to specify a block for displaying your type, you just do the 
same as with the editor but instead you contribute it with

public static void 
contributeBeanBlockSource(Configuration<BeanBlockContribution> 
configuration)
{
     configuration.add(new BeanBlockContribution("school", 
"AppPropertyEditBlocks", "schoolViewBlock",
                 false));
}

(notice the false parameter now)

Cheers,

Uli

Luther Baker schrieb:
> Thanks both of you for your explanations - if you've got a bit of patience
> with me, I need to walk through my thoughts to better understand the big
> picture here. Thanks in advance for your points and help - they are very
> helpful.
> 
> 
> Ok, to set the stage in a little more detail: consider a basic GRAILS or
> CRUD style app where my views are List.tml, Edit.tml and Show.tml.
> 
> 
> I've broken this up into a few posts - in this response, *I'll focus on
> List.tml, t:Grid and t:BeanDisplay* -- afterwhich, I'll try to segway into a
> post that leverages this information to discuss t:BeanEditForm.
> 
> In this example, I'm using Topics and Classifications. Both are simple
> entities - a Topic has a @ManyToOne relationship to Classifications. Each
> Topic contains exactly one Classification. Many Topics can refer to the same
> Classification but again, any single Topic has exactly one Classification.
> 
> 
> @Entity
> public class Classification
> {
>     @Id
>     @GeneratedValue(strategy = GenerationType.TABLE)
>     private Integer id;
> 
>     private String name;
> ...
> }
> 
> 
> @Entity
> public class Topic
> {
>     @Id
>     @GeneratedValue(strategy = GenerationType.TABLE)
>     private Integer id;
> 
>     @ManyToOne
>     private Classification classification;
> ...
> }
> 
> 
> Now consider List.tml:
> 
> If I use a t:Grid out of the box, I get a runtime complaint when I try to
> display a Topic,
> 
>     "does not contain a property named 'classification'"
> 
> I assume this is because 'Classification' is not on the list of simple types
> that Tapestry currently knows about. Strings, booleans, numbers, etc. So, I
> add a defaultDataTypeAnalyzer:
> 
>     public static void
> contributeDefaultDataTypeAnalyzer(MappedConfiguration<Class<?>, String>
> configuration)
>     {
>         configuration.add(Classification.class, "classification");
>     }
> 
> I'm not sure why assigning the name "classification" Classification suddenly
> makes this work ... but as soon as I do this, the t:Grid successfully
> displays a Classification column - and populates it by invoking
> Classification.toString(). Is that behavior overridable? Is it safe to say I
> don't need any other moving parts for this to work this way going forward?
> 
> My next post will talk about BeanEditForm which I understand uses a
> BeanModel, PropertyEditor, blocks etc - but as far as t:Grid is concerned -
> is there a special way to explicitly control how Classification DISPLAY's
> itself (right now it invokes Classification.toString()) ? (ie: is there a
> group of classes that work together similar to t:BeanEditForm?)
> 
> In the t:BeanEditForm - one creates xhtml blocks - but it doesn't appear
> necessary for t:Grid. Is that because t:Grid is only DISPLAYing the
> property?
> 
> When I use t:BeanDisplay, the same thing happens, Classification.toString()
> is invoked. That all sounds good and reasonable - I am just curious how, in
> a DISPLAY scenario, if there is a programmatic way to override the behavior?
> 
> And, as a side note, looking for a brief explanation as to why
> 'contributeDefaultDataTypeAnalyzer' makes this work.
> 
> End of Part 1 :) DISPLAYing hibernate entities: t:Grid and t:BeanDisplay ...
> is it simpler than t:BeanEditForm? and can I override the toString
> invocation and why does contributeDefaultDataTypeAnalyzer have to happen
> here?
> 
> Always happy to look at docs for this if you have any links to show.
> 
> Thanks very much - I'm off to try some of the notes for t:BeanEditForm and
> I'll get back to you.
> 
> -Luther
> 
> 
> 
> On Tue, Feb 17, 2009 at 5:34 AM, Ulrich Stärk <ul...@spielviel.de> wrote:
> 
>> Here is your overview (assuming that you want to render your list of
>> schools using a select component):
>>
>> SelectModel
>>
>> This is a model of the data you want to render. This could be backed by a
>> list or some other collection type (there is a type coercer from list to
>> selectmodel build into tapestry which automatically converts the one into
>> the other). In your case you will want to populate this model with the
>> available schools.
>>
>> ValueEncoder
>>
>> As Thiago already pointed out, this is needed to convert from object to
>> presentation and back.
>>
>> GenericSelectModel
>>
>> Search for it in the wiki. It's user-contributed and implements both the
>> SelectModel and the ValueEncoder interfaces. In its constructor, you pass it
>> the type you want to create a model/encoder for, the list of available items
>> (schools in your case), the name of the id property and the name of the
>> property used to display to the user (if null, toString() will be used).
>>
>> AppPropertyEditBlocks
>>
>> The name of a page where you define a block used for rendering your custom
>> type (school). This name is arbitrary and can be whatever you like it to be.
>> Here you wire up the select component with your model and encoder. In the
>> page template you define some block whith an explicit id (e.g. schoolBlock).
>>
>> AppModule
>>
>> In your AppModule you have to make contributions to the
>> DefaultDataTypeAnalyzer and the BeanBlockSource services.
>>
>> public static void contributeDefaultDataTypeAnalyzer(
>>            MappedConfiguration<Class, String> configuration)
>> {
>>    configuration.add(School.class, "school");
>> }
>>
>> This will assign the name school to your school type for use within
>> tapestry.
>>
>> With
>>
>> public static void
>> contributeBeanBlockSource(Configuration<BeanBlockContribution>
>> configuration)
>> {
>>    configuration.add(new BeanBlockContribution("school",
>> "AppPropertyEditBlocks", "schoolBlock",
>>                true));
>> }
>>
>> you tell Tapestry to render a property of type school with the block
>> "schoolBlock" inside the AppPropertyEditBlocks page.
>>
>> HTH,
>>
>> Uli
>>
>> Luther Baker schrieb:
>>
>>  Given two hibernate objects and a many-to-one relationship
>>> school
>>> {
>>>  name
>>> }
>>>
>>> student
>>> {
>>>  firstname
>>>
>>>  @ManyToOne
>>>  school
>>> }
>>>
>>>
>>> I want to pass something like this into a BeanEditForm and have the it
>>> invoke school.toString() or possibly, school.getName().
>>>
>>> I know I can add a t:Parameter to t:BeanEditForm but it seems that I
>>> should
>>> be able to somehow register the School type with Tapestry and have it
>>> simply
>>> invoke school.toString() when required to render itself.
>>>
>>> I've looked at
>>> http://wiki.apache.org/tapestry/Tapestry5HowToCreateAPropertyEditBlockbut
>>> found it a bit confusing. At some high level, is there a brief synopsis of
>>> the different players required to do this?
>>>
>>> PropertyEditor
>>> ValueEncoder
>>> DataTypeAnalyzer
>>> PropertyEditContext
>>> @Environmental
>>> the Model ... etc.
>>>
>>> Now, on the other hand, is the BeanEditForm really considered just a
>>> starter
>>> component and is generally not used for production code? In which case, is
>>> it just fine to come up with custom solutions to determine types and how
>>> to
>>> render them? Or is there a strong reason to go through all of this ...
>>> when
>>> I want to render a nested Hibernate Entity with a toString().
>>>
>>> Thanks,
>>>
>>> -Luther
>>>
>>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
>> For additional commands, e-mail: users-help@tapestry.apache.org
>>
>>
> 


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


Re: rendering hibernate objects

Posted by Luther Baker <lu...@gmail.com>.
Thanks both of you for your explanations - if you've got a bit of patience
with me, I need to walk through my thoughts to better understand the big
picture here. Thanks in advance for your points and help - they are very
helpful.


Ok, to set the stage in a little more detail: consider a basic GRAILS or
CRUD style app where my views are List.tml, Edit.tml and Show.tml.


I've broken this up into a few posts - in this response, *I'll focus on
List.tml, t:Grid and t:BeanDisplay* -- afterwhich, I'll try to segway into a
post that leverages this information to discuss t:BeanEditForm.

In this example, I'm using Topics and Classifications. Both are simple
entities - a Topic has a @ManyToOne relationship to Classifications. Each
Topic contains exactly one Classification. Many Topics can refer to the same
Classification but again, any single Topic has exactly one Classification.


@Entity
public class Classification
{
    @Id
    @GeneratedValue(strategy = GenerationType.TABLE)
    private Integer id;

    private String name;
...
}


@Entity
public class Topic
{
    @Id
    @GeneratedValue(strategy = GenerationType.TABLE)
    private Integer id;

    @ManyToOne
    private Classification classification;
...
}


Now consider List.tml:

If I use a t:Grid out of the box, I get a runtime complaint when I try to
display a Topic,

    "does not contain a property named 'classification'"

I assume this is because 'Classification' is not on the list of simple types
that Tapestry currently knows about. Strings, booleans, numbers, etc. So, I
add a defaultDataTypeAnalyzer:

    public static void
contributeDefaultDataTypeAnalyzer(MappedConfiguration<Class<?>, String>
configuration)
    {
        configuration.add(Classification.class, "classification");
    }

I'm not sure why assigning the name "classification" Classification suddenly
makes this work ... but as soon as I do this, the t:Grid successfully
displays a Classification column - and populates it by invoking
Classification.toString(). Is that behavior overridable? Is it safe to say I
don't need any other moving parts for this to work this way going forward?

My next post will talk about BeanEditForm which I understand uses a
BeanModel, PropertyEditor, blocks etc - but as far as t:Grid is concerned -
is there a special way to explicitly control how Classification DISPLAY's
itself (right now it invokes Classification.toString()) ? (ie: is there a
group of classes that work together similar to t:BeanEditForm?)

In the t:BeanEditForm - one creates xhtml blocks - but it doesn't appear
necessary for t:Grid. Is that because t:Grid is only DISPLAYing the
property?

When I use t:BeanDisplay, the same thing happens, Classification.toString()
is invoked. That all sounds good and reasonable - I am just curious how, in
a DISPLAY scenario, if there is a programmatic way to override the behavior?

And, as a side note, looking for a brief explanation as to why
'contributeDefaultDataTypeAnalyzer' makes this work.

End of Part 1 :) DISPLAYing hibernate entities: t:Grid and t:BeanDisplay ...
is it simpler than t:BeanEditForm? and can I override the toString
invocation and why does contributeDefaultDataTypeAnalyzer have to happen
here?

Always happy to look at docs for this if you have any links to show.

Thanks very much - I'm off to try some of the notes for t:BeanEditForm and
I'll get back to you.

-Luther



On Tue, Feb 17, 2009 at 5:34 AM, Ulrich Stärk <ul...@spielviel.de> wrote:

> Here is your overview (assuming that you want to render your list of
> schools using a select component):
>
> SelectModel
>
> This is a model of the data you want to render. This could be backed by a
> list or some other collection type (there is a type coercer from list to
> selectmodel build into tapestry which automatically converts the one into
> the other). In your case you will want to populate this model with the
> available schools.
>
> ValueEncoder
>
> As Thiago already pointed out, this is needed to convert from object to
> presentation and back.
>
> GenericSelectModel
>
> Search for it in the wiki. It's user-contributed and implements both the
> SelectModel and the ValueEncoder interfaces. In its constructor, you pass it
> the type you want to create a model/encoder for, the list of available items
> (schools in your case), the name of the id property and the name of the
> property used to display to the user (if null, toString() will be used).
>
> AppPropertyEditBlocks
>
> The name of a page where you define a block used for rendering your custom
> type (school). This name is arbitrary and can be whatever you like it to be.
> Here you wire up the select component with your model and encoder. In the
> page template you define some block whith an explicit id (e.g. schoolBlock).
>
> AppModule
>
> In your AppModule you have to make contributions to the
> DefaultDataTypeAnalyzer and the BeanBlockSource services.
>
> public static void contributeDefaultDataTypeAnalyzer(
>            MappedConfiguration<Class, String> configuration)
> {
>    configuration.add(School.class, "school");
> }
>
> This will assign the name school to your school type for use within
> tapestry.
>
> With
>
> public static void
> contributeBeanBlockSource(Configuration<BeanBlockContribution>
> configuration)
> {
>    configuration.add(new BeanBlockContribution("school",
> "AppPropertyEditBlocks", "schoolBlock",
>                true));
> }
>
> you tell Tapestry to render a property of type school with the block
> "schoolBlock" inside the AppPropertyEditBlocks page.
>
> HTH,
>
> Uli
>
> Luther Baker schrieb:
>
>  Given two hibernate objects and a many-to-one relationship
>>
>> school
>> {
>>  name
>> }
>>
>> student
>> {
>>  firstname
>>
>>  @ManyToOne
>>  school
>> }
>>
>>
>> I want to pass something like this into a BeanEditForm and have the it
>> invoke school.toString() or possibly, school.getName().
>>
>> I know I can add a t:Parameter to t:BeanEditForm but it seems that I
>> should
>> be able to somehow register the School type with Tapestry and have it
>> simply
>> invoke school.toString() when required to render itself.
>>
>> I've looked at
>> http://wiki.apache.org/tapestry/Tapestry5HowToCreateAPropertyEditBlockbut
>> found it a bit confusing. At some high level, is there a brief synopsis of
>> the different players required to do this?
>>
>> PropertyEditor
>> ValueEncoder
>> DataTypeAnalyzer
>> PropertyEditContext
>> @Environmental
>> the Model ... etc.
>>
>> Now, on the other hand, is the BeanEditForm really considered just a
>> starter
>> component and is generally not used for production code? In which case, is
>> it just fine to come up with custom solutions to determine types and how
>> to
>> render them? Or is there a strong reason to go through all of this ...
>> when
>> I want to render a nested Hibernate Entity with a toString().
>>
>> Thanks,
>>
>> -Luther
>>
>>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
> For additional commands, e-mail: users-help@tapestry.apache.org
>
>

Re: rendering hibernate objects

Posted by Ulrich Stärk <ul...@spielviel.de>.
Here is your overview (assuming that you want to render your list of 
schools using a select component):

SelectModel

This is a model of the data you want to render. This could be backed by 
a list or some other collection type (there is a type coercer from list 
to selectmodel build into tapestry which automatically converts the one 
into the other). In your case you will want to populate this model with 
the available schools.

ValueEncoder

As Thiago already pointed out, this is needed to convert from object to 
presentation and back.

GenericSelectModel

Search for it in the wiki. It's user-contributed and implements both the 
SelectModel and the ValueEncoder interfaces. In its constructor, you 
pass it the type you want to create a model/encoder for, the list of 
available items (schools in your case), the name of the id property and 
the name of the property used to display to the user (if null, 
toString() will be used).

AppPropertyEditBlocks

The name of a page where you define a block used for rendering your 
custom type (school). This name is arbitrary and can be whatever you 
like it to be.
Here you wire up the select component with your model and encoder. In 
the page template you define some block whith an explicit id (e.g. 
schoolBlock).

AppModule

In your AppModule you have to make contributions to the 
DefaultDataTypeAnalyzer and the BeanBlockSource services.

public static void contributeDefaultDataTypeAnalyzer(
             MappedConfiguration<Class, String> configuration)
{
     configuration.add(School.class, "school");
}

This will assign the name school to your school type for use within 
tapestry.

With

public static void 
contributeBeanBlockSource(Configuration<BeanBlockContribution> 
configuration)
{
     configuration.add(new BeanBlockContribution("school", 
"AppPropertyEditBlocks", "schoolBlock",
                 true));
}

you tell Tapestry to render a property of type school with the block 
"schoolBlock" inside the AppPropertyEditBlocks page.

HTH,

Uli

Luther Baker schrieb:
> Given two hibernate objects and a many-to-one relationship
> 
> school
> {
>   name
> }
> 
> student
> {
>   firstname
> 
>   @ManyToOne
>   school
> }
> 
> 
> I want to pass something like this into a BeanEditForm and have the it
> invoke school.toString() or possibly, school.getName().
> 
> I know I can add a t:Parameter to t:BeanEditForm but it seems that I should
> be able to somehow register the School type with Tapestry and have it simply
> invoke school.toString() when required to render itself.
> 
> I've looked at
> http://wiki.apache.org/tapestry/Tapestry5HowToCreateAPropertyEditBlock but
> found it a bit confusing. At some high level, is there a brief synopsis of
> the different players required to do this?
> 
> PropertyEditor
> ValueEncoder
> DataTypeAnalyzer
> PropertyEditContext
> @Environmental
> the Model ... etc.
> 
> Now, on the other hand, is the BeanEditForm really considered just a starter
> component and is generally not used for production code? In which case, is
> it just fine to come up with custom solutions to determine types and how to
> render them? Or is there a strong reason to go through all of this ... when
> I want to render a nested Hibernate Entity with a toString().
> 
> Thanks,
> 
> -Luther
> 


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


Re: rendering hibernate objects

Posted by "Thiago H. de Paula Figueiredo" <th...@gmail.com>.
Em Mon, 16 Feb 2009 22:25:14 -0300, Luther Baker <lu...@gmail.com>  
escreveu:

> I want to pass something like this into a BeanEditForm and have the it
> invoke school.toString() or possibly, school.getName().

Is not that simple. Besides the label, you need to map from object to  
value (option HTML tag) and value to object. That's exactly what the  
ValueEncoder does.

> I've looked at  
> http://wiki.apache.org/tapestry/Tapestry5HowToCreateAPropertyEditBlock  
> but found it a bit confusing. At some high level, is there a brief  
> synopsis of the different players required to do this?
> PropertyEditor
> ValueEncoder
> DataTypeAnalyzer
> PropertyEditContext
> @Environmental
> the Model ... etc.

Take a look at their Javadocs and the BeanEditForm tutorial:  
http://tapestry.apache.org/tapestry5/guide/beaneditform.html.

> Now, on the other hand, is the BeanEditForm really considered just a  
> starter component and is generally not used for production code?

I haven't used it in production yet, but I'll do it soon.

> In which case, is it just fine to come up with custom solutions to  
> determine types and how to render them? Or is there a strong reason to  
> go through all of this ... when I want to render a nested Hibernate  
> Entity with a toString().

It depends on how many times, in different places of your application,  
you'll need to edit a collection of a given class. If it's just one, use a  
t:parameter block. Otherwise, do the right thing: reuse code. ;)

-- 
Thiago H. de Paula Figueiredo
Independent Java consultant, developer, and instructor
http://www.arsmachina.com.br/thiago

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