Well I am diligently trying to find a solution to scenario(2). I made
http://forum.springframework.org/showthread.php?t=44525 this post over at
forum.springframework.org. If anyone has ever implemented an initBinder() /
PropertyEditor for a many-to-many relation, represented as hiddens or texts
in the jsp (rather than multi-select) I would love to know how you managed
it!
Thanks,
Bob
syg6 wrote:
>
> Well I am plugging away at scenario(2) ... as I figured, not trivial.
>
> I looked at some of the examples of the <spring:bind> tag. It seems to be
> the way to go. In my jsp I have the following:
>
> <c:forEach var="ec" items="${establishment.establishmentContainers}"
> varStatus="loopStatus">
> <tr>
> <td>
> <spring:bind
> path="establishment.establishmentContainers[${loopStatus.index}].establishment.id">
> <input type="text" name="${status.expression}"
> value="${status.value}">
> </spring:bind>
> </td>
> <td>
> <spring:bind
> path="establishment.establishmentContainers[${loopStatus.index}].container.id">
> <input type="text" name="${status.expression}"
> value="${status.value}">
> </spring:bind>
> </td>
> <td>
> <spring:bind
> path="establishment.establishmentContainers[${loopStatus.index}].quantity">
> <input type="text" name="${status.expression}"
> value="${status.value}">
> </spring:bind>
> </td>
> </tr>
> </c:forEach>
>
> This creates a table full of indexed <input type="text"> elements in html:
>
> establishmentContainers[0].establishment.id
> establishmentContainers[0].container.id
> establishmentContainers[0].quantity
> establishmentContainers[1].establishment.id
> establishmentContainers[1].container.id
> establishmentContainers[1].quantity
>
> ... just as it should. And I can change the container and the quantity
> (the establishment id doesn't change ...) But when I add a new row,
> fuggedaboudit:
>
> org.springframework.web.util.NestedServletException: Request processing
> failed; nested exception is
> org.springframework.beans.InvalidPropertyException: Invalid property
> 'establishmentContainers[2]' of bean class
> [com.myco.myapp.model.Establishment]: Index of out of bounds in property
> path 'establishmentContainers[2]'; nested exception is
> java.lang.IndexOutOfBoundsException: Index: 2, Size: 2
>
> Not good. I created an EstablishmentContainerPropertyEditor and was
> debugging setAsText(), but it never calls that method. It should because
> in my EstablishmentFormController I am binding to it.
>
> At any rate, I am not sure what I am doing wrong, if anyone has done this
> before I'd appreciate the help. I can see that managing the deletion of
> these objects is going to be a pain as well. I hope to be able to just
> wipe the table for the current idEstablishment and just do inserts.
> Otherwise it's going to be a nightmare.
>
> Thanks in advance!
> Bob
>
>
> syg6 wrote:
>>
>> Hello again.
>>
>> Well I guess I'll deal with scenario (1) for now. The deal is that when
>> you create a new Application you at least have to assign streetSection1.
>> You can also assign streetSection2 and place but they are not obligatory.
>> (You never create NEW StreetSections or Places ...) This is what I have.:
>>
>> @Entity
>> public class Application
>> ...
>> private StreetSection streetSection1;
>> private StreetSection streetSection2;
>> private Place place;
>> ...
>> public Application()
>> {
>> this.streetSection1 = new StreetSection();
>> this.streetSection2 = new StreetSection();
>> this.place = new Place();
>> }
>> ...
>> @ManyToOne
>> @JoinColumn(name="idStreetSection1", nullable=false)
>> public StreetSection getStreetSection1() ...
>>
>> @ManyToOne
>> @JoinColumn(name="idStreetSection2", nullable=false)
>> public StreetSection getStreetSection2() ...
>>
>> @ManyToOne
>> @JoinColumn(name="idPLace", nullable=false)
>> public Place getPlace() ...
>>
>> In the jsp I have the following:
>>
>> <form:hidden path="streetSection1" id="streetSection1" />
>> <form:hidden path="streetSection2" id="streetSection2" />
>> <form:hidden path="place" id="place" />
>>
>> I used to have it as 'streetSection1.id', 'streetSection2.id', etc. and
>> had to put an <c:if> to check if streetSecion1.id was null or not. but
>> now I have implemented getAsText() in the StreetSectionPropertyEditor and
>> PlacePropertyEditor (I already had setAsText()):
>>
>> public void setAsText(String id)
>> {
>> StreetSection streetSection = streetSectionManager.get(new Long(id));
>> setValue(streetSection);
>> }
>>
>> public String getAsText()
>> {
>> StreetSection streetSection = (StreetSection) getValue();
>> if (streetSection == null) return "";
>> else return (streetSection.getId() == null) ? "" :
>> streetSection.getId().toString();
>> }
>>
>> PlacePropertyEditor is exactly the same. getAsText() returns the id of
>> the existing StreetSection or Place, when loading an existing
>> Application. If it's a new Application (and thus a new StreetSection and
>> Place) it returns an empty string.
>>
>> And this is my ApplicationFormController initBinder():
>>
>> protected void initBinder()
>> {
>> StreetSectionPropertyEditor sspe = new StreetSectionPropertyEditor();
>> sspe.setStreetSectionManager(streetSectionManager);
>> binder.registerCustomEditor(StreetSection.class, "streetSection1",
>> sspe);
>> binder.registerCustomEditor(StreetSection.class, "streetSection2",
>> sspe);
>>
>> PlacePropertyEditor ppe = new PLacePropertyEditor();
>> ppe.setPlaceManager(placeManager);
>> binder.registerCustomEditor(Place.class, "place", ppe);
>> }
>>
>> This works for existing Applications. And it also works when creating a
>> new Application if I fill in all three fields - streetSection1,
>> streetSection2 and place. But when I create a new Application, and only
>> assign streetSection1 or streetSection1 and streetSection2 I get this
>> error:
>>
>> object references an unsaved transient instance - save the transient
>> instance before flushing: com.myco.myapp.model.Place; nested exception is
>> org.hibernate.TransientObjectException: object references an unsaved
>> transient instance - save the transient instance before flushing:
>> com.myco.myapp.model.Place
>>
>> Whew! And that's just scenario (1). I think I must be overlooking
>> something simple, something that's implemented for StreetSection that is
>> not implemented for Place. Since it only craps out when I send a null
>> Place, it must be that it's not handling 'null' well. But in the jsp when
>> I don't assign a Place I make sure the 'place' hidden is disabled (null)
>> before submitting. Interestingly, setTextAs() is NOT called when a null
>> value is sent. I guess this is correct. But it must mean that the
>> PropertyEditor is not the problem because it's not even making it that
>> far ...
>>
>> As far as scenario (2) goes I am looking into it ... unfortunately it
>> doesn't seem a trivial thing to do. I thought that the <spring:bind> tag
>> had been surpassed by the <form> tags for binding lists. In fact for
>> simpler objects I am using <form:select>. But for the
>> EstablishmentContainer objects I am going to have to add a 'row' to an
>> html table with some <hidden> and text tags for each
>> EstablishmentContainer added, and somehow get a PropertyEditor to assign
>> them correctly. I will look into using the <bind> tag and a
>> PropertyEditor. It's not going to be easy I think, but preferable to
>> picking out all of the values from the request, manually instantiating
>> and populating every EstablishmentContainer object and adding it to the
>> List.
>>
>> I'll keep you posted!
>>
>> Bob
>>
>>
>>
>>
>>
>> or objects
>>
>> Mike Horwitz wrote:
>>>
>>> On 10/2/07, syg6 <[EMAIL PROTECTED]> wrote:
>>>
>>>>
>>>> Thanks for your response Mike. I think you must have copy-pasted from
>>>> another
>>>> post or something, I am not working with a Country object. But I think
>>>> your
>>>> idea applies to both of my scenarios.
>>>
>>>
>>> Correct. It is a copy and paste from the relevant post on the thread.
>>>
>>>
>>>
>>>> In scenario (1) I already have a PropertyEditor defined for
>>>> StreetSection.
>>>> It looks like this:
>>>>
>>>> public class StreetSectionPropertyEditor extends PropertyEditorSupport
>>>> {
>>>> public void setAsText(String id) {
>>>> StreetSection streetSection = streetSectionManager.get(new
>>>> Long(id));
>>>> setValue(streetSection);
>>>> }
>>>
>>>
>>> Please be careful about handling null values - you may/may not need this
>>> depending on the details of your implementation. You do need a getAsText
>>> method to ensure the field gets properly populated with the id for an
>>> existing establishment.
>>>
>>>
>>>
>>>> And it seems to work fine. I don't have a getAsText() defined and it
>>>> has
>>>> worked until now. But I am unsure of what I should use in the
>>>> establishmentform.jsp. Should I use:
>>>>
>>>> <form:hidden path="streetSection" id="streetSection" /> or
>>>
>>>
>>> This is the one you should use as it will use your property editor to
>>> correctly bind your object to the existing instance in your database.
>>>
>>>
>>>
>>>> <form:hidden path="streetSection.id" id="streetSection.id" /> ?
>>>
>>>
>>> This will create a new StreetSection and attempt to save it. Presumably
>>> this
>>> is not what you want?
>>>
>>>
>>>
>>>> It was working ok using 'streetSection' instead of 'streetSection.id'
>>>> but
>>>> I
>>>> had problems when saving a NEW establishment (it worked fine when
>>>> saving
>>>> an
>>>> existing Establishment curiously enough ...), 'can't save a transient
>>>> object' error. Could this be because I don't have getAsText() defined?
>>>
>>>
>>> Probably due to a cascade being set on the establishment object. Try
>>> without
>>> cascading save on the relationship. Judging by your jsp code this should
>>> always be null for a new establishment object?
>>>
>>> Perhaps you could post the details of the error and we can try and help?
>>>
>>>
>>>
>>>> In scenario (2), how would I go about creating an
>>>> EstablishmentContainerPropertyEditor? What I would need to do is tell
>>>> Spring, 'Hey! Create an EstablishmentContainer object with '1' for
>>>> idEstablishment, '2' for idContainer and '50' for quantity, and add it
>>>> to
>>>> the list of EstablishmentContainers, using values from the .jsp, either
>>>> a
>>>> multi-select or hiddens. But the setAsText() method takes only one
>>>> string,
>>>> usually an id. Do I need to override some other method in
>>>> PropertyEditorSupport?
>>>
>>>
>>> Property editors only do one thing: Text -> Object and Object -> Text.
>>> So
>>> they are useful if you want to build up one or more relationships
>>> between
>>> the object you are editing in the form and existing objects in the
>>> database.
>>> If what you are talking about is creating a new set of objects, then
>>> your
>>> form needs to address that -> your form would create new
>>> EstablishmentContainer objects and use property editors to build the
>>> relationship between EstablishmentContainer -> Establishment and
>>> EstablishmentContainer -> Container. Exactly how to go about this
>>> largely
>>> depends on how you want to manage the whole lot on the jsp page. If you
>>> have
>>> something that works, then that is the best way!
>>>
>>> Spring does have the ability to bind to elements in an ordered list by
>>> using
>>> [index] type syntax, e.g. establishmentContainer[1]. Doing a Google
>>> search
>>> on 'Spring MVC bind list' will bring up a whole list of sites that
>>> discuss
>>> this in more detail.
>>>
>>> Mike.
>>>
>>>
>>>> I think this is the way to go though, just not sure how to do it.
>>>>
>>>> Thanks!
>>>> Bob
>>>>
>>>>
>>>>
>>>>
>>>> Mike Horwitz wrote:
>>>> >
>>>> > I believe you could resolve both cases by registering custom editors
>>>> in
>>>> > your
>>>> > controllers - this would allow Spring MVC to automatically convert
>>>> between
>>>> > the object and its string representation. See the thread on this
>>>> > discussion
>>>> > for more details http://tinyurl.com/3yghfd:
>>>> >
>>>> > You are going to need to provide *Spring* *MVC* with a way to get
>>>> from
>>>> an
>>>> > id
>>>> > to a country and vice-versa. As you correctly point out this is done
>>>> by
>>>> > registering a custom property editor in your controller. To do this
>>>> you
>>>> > need
>>>> > to:
>>>> >
>>>> > 1) Extend the class *PropertyEditorSupport* to create the property
>>>> editor:
>>>> >
>>>> http://java.sun.com/j2se/1.5.0/docs/api/java/beans/*PropertyEditorSupport*.html
>>>> > <
>>>> http://java.sun.com/j2se/1.5.0/docs/api/java/beans/PropertyEditorSupport.html
>>>> >
>>>> >
>>>> > You need to override the getAsText() and setAsText() methods. The
>>>> first
>>>> > should call getValue() and return the id as text, and the second
>>>> should
>>>> > accept a text id and call setValue() on the editor with the
>>>> corresponding
>>>> > country object.
>>>> >
>>>> > 2) You then register this custom editor using one of the appropriate
>>>> > methods
>>>> > on your controller: initBinder() see api on http://tinyurl.com/2sutrm
>>>> >
>>>> > And it should all work like magic....
>>>> >
>>>> > Mike.
>>>> >
>>>> >
>>>> > On 10/2/07, syg6 <[EMAIL PROTECTED]> wrote:
>>>> >>
>>>> >>
>>>> >> I have a couple scenarios, one typical the other not so much, that I
>>>> am
>>>> >> trying to implement as quickly and easily as possible.
>>>> >>
>>>> >> The first is pretty straight-forward:
>>>> >>
>>>> >> @Entity
>>>> >> public class Application
>>>> >> ...
>>>> >> private StreetSection streetSecion;
>>>> >> ...
>>>> >> @ManyToOne(cascade = { CascadeType.PERSIST, CascadeType.MERGE })
>>>> >> @JoinColumn(name="streetSection", nullable=false)
>>>> >> public StreetSection getStreetSection()
>>>> >> {
>>>> >> return streetSection;
>>>> >> }
>>>> >>
>>>> >> In my form, which is the correct way to do the input?
>>>> >>
>>>> >> <form:hidden path="streetSection" id="streetSection" />
>>>> >>
>>>> >> or
>>>> >>
>>>> >> <form:hidden path="streetSection.id" id="streetSection.id" />
>>>> >>
>>>> >> In my testing I have found that they both work but each one has its
>>>> own
>>>> >> little quirks. For example, if I use 'streetSection.id', when it's a
>>>> new
>>>> >> Application the page crashes because streetSection.id is null. So I
>>>> have
>>>> >> to
>>>> >> put a <c:if> in there and if it's null just use a normal <input
>>>> >> type='hidden'> tag.
>>>> >>
>>>> >> If I use 'streetSection' I believe (I've done so many tests I forget
>>>> ...)
>>>> >> that Hibernate is giving me 'can't save transient object' errors.
>>>> Anyway,
>>>> >> just curious what the best practice is.
>>>> >>
>>>> >> The other scenario is more complicated. I have an object,
>>>> Establishment,
>>>> >> and
>>>> >> another, Container, and they both have a list of
>>>> EstablishmentContainer
>>>> >> objects, which saved in a join table that has an attribute,
>>>> quantity.
>>>> So
>>>> >> each POJO, Establishment and Container, have a OneToMany
>>>> relationship
>>>> >> with
>>>> >> EstablishmentContainer, and EstablishmentContainer has a ManyToOne
>>>> >> relationship with both Establishment and Container. This is
>>>> apparently
>>>> >> the
>>>> >> best way to map join tables with attributes.
>>>> >>
>>>> >> @Entity
>>>> >> public class Establishment
>>>> >> ...
>>>> >> private List<EstablishmentContainers> establishmentContainers;
>>>> >> ...
>>>> >> @OneToMany(mappedBy="establishment", fetch = FetchType.EAGER,
>>>> cascade =
>>>> {
>>>> >> CascadeType.PERSIST, CascadeType.MERGE })
>>>> >> public List<EstablishmentContainer> getEstablishmentContainers()
>>>> >> {
>>>> >> return establishmentContainer;
>>>> >> }
>>>> >>
>>>> >> @Entity
>>>> >> public class Container
>>>> >> ...
>>>> >> @OneToMany(mappedBy="container")
>>>> >> public List<EstablishmentContainer> getEstablishmentContainers ()
>>>> >> {
>>>> >> return establishmentContainers;
>>>> >> }
>>>> >>
>>>> >> @Entity
>>>> >> public class EstablishmentContainer extends
>>>> >> {
>>>> >> private Long id;
>>>> >> private Establishment establishment;
>>>> >> private Container container;
>>>> >>
>>>> >> private int quantity;
>>>> >> ...
>>>> >> @ManyToOne
>>>> >> @JoinColumn(name="idEstablishment")
>>>> >> public Establishment getEstablishment()
>>>> >> {
>>>> >> return establishment;
>>>> >> }
>>>> >>
>>>> >> @ManyToOne
>>>> >> @JoinColumn(name="idContainer")
>>>> >> public Cubo getContainer()
>>>> >> {
>>>> >> return container;
>>>> >> }
>>>> >>
>>>> >> @Column(name="quantity")
>>>> >> public int getQuantity()
>>>> >> {
>>>> >> return quantity;
>>>> >> }
>>>> >>
>>>> >> In my EstablishmentFormController do I have to do the following for
>>>> each
>>>> >> EstablishmentContainer created in the page:
>>>> >>
>>>> >> 1. instantiate an EstablishmentContainer object
>>>> >> 2. fill it it request parameters by hand
>>>> >> 3. add it to a List
>>>> >> 4. assign that list to my Establishment object
>>>> >>
>>>> >> ... for the EstablishmentContainers list to be properly saved when I
>>>> do
>>>> >> an
>>>> >> establishmentManager.save()?
>>>> >> This is what I am doing currently and it works but it seems to me
>>>> that
>>>> if
>>>> >> I
>>>> >> put the following in my jsp:
>>>> >>
>>>> >> input type="text" id="establishmentContainers.container.id"
>>>> >> input type="text" id="establishmentContainers.establihsment.id"
>>>> >> input type="text" id="establishmentContainers.quantity"
>>>> >>
>>>> >> Spring should be able to populate the List of EstablishmentObjects
>>>> >> automatically, just as in the first example it populates my
>>>> >> Application.StreetSection object when I put a
>>>> >>
>>>> >> input type="text" id="application.streetSection"
>>>> >>
>>>> >> element in the page. If it's not possible I can keep doing it the
>>>> way I
>>>> >> currently do, I just don't want to reinvent the wheel.
>>>> >>
>>>> >> Sorry for the long post. I look forward to any and all responses.
>>>> >> Bob
>>>> >>
>>>> >> --
>>>> >> View this message in context:
>>>> >>
>>>> http://www.nabble.com/Best-way-to-save-ManyToOne-relationships-with-Hibernate-and-Spring-MVC-tf4553758s2369.html#a12995187
>>>> >> Sent from the AppFuse - User mailing list archive at Nabble.com.
>>>> >>
>>>> >>
>>>> ---------------------------------------------------------------------
>>>> >> To unsubscribe, e-mail: [EMAIL PROTECTED]
>>>> >> For additional commands, e-mail: [EMAIL PROTECTED]
>>>> >>
>>>> >>
>>>> >
>>>> >
>>>>
>>>> --
>>>> View this message in context:
>>>> http://www.nabble.com/Best-way-to-save-ManyToOne-relationships-with-Hibernate-and-Spring-MVC-tf4553758s2369.html#a12996194
>>>> Sent from the AppFuse - User mailing list archive at Nabble.com.
>>>>
>>>> ---------------------------------------------------------------------
>>>> To unsubscribe, e-mail: [EMAIL PROTECTED]
>>>> For additional commands, e-mail: [EMAIL PROTECTED]
>>>>
>>>>
>>>
>>>
>>
>>
>
>
--
View this message in context:
http://www.nabble.com/Best-way-to-save-ManyToOne-relationships-with-Hibernate-and-Spring-MVC-tf4553758s2369.html#a13021880
Sent from the AppFuse - User mailing list archive at Nabble.com.
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]