Does anybody know why the Flex 4(.6) SOAP decoder adds the decoded arraycollection in the first element of the array(collection)based-property in the object?
BarCollection extends from ArrayCollection
Expected:
Object
-- someProperty:BarCollection
--[0] item:Foo
--[1] item:Foo
Got:
Object
-- someProperty:BarCollection
-- [0] ArrayCollection
--[0] item:Foo
--[1] item:Foo
The collection is registered via the
SchemaTypeRegistry.getInstance().registerCollectionClass -method
SchemaTypeRegistry.getInstance().registerCollectionClass(new QName("http://www.world.com/Foo", "BarCollection"), BarCollection);
Thanks for your answer!
Making the property a public variable of type ArrayCollection seems to work.
I did not managed to make it work with instantiating the field in the getter.
You did mean something like this?
private var _collection:CustomCollection;
public function get collection():CustomCollection {
if(!_collection)
_collection = new CustomCollection()
return _collection;
}
public function set collection(value:CustomCollection):void {
_collection = value;
}
But it seems that this only works on pure ArrayCollections.
My CustomCollection extends CollectionBase, which extends ArrayCollection.
If I switch to the custom collection, instead of the ArrayCollection, the tricks listed above doesn't seem to work.
If I have some time, I'll run trough the XML decoder again.
JoriDor,
I retraced my steps and found that a second difference between what I created and what I got from the sample cited below appears to be the true cause.
My ArrayCollection instance variable was created by getter/setter functions. When I changed it to a public variable, like the sample code, it worked! This is very disappointing as I must now consider altering my VO classes.
Not to give up too easily, I imagine that the mx.rpc.xml classes are using reflection (describeType()), so maybe I can see what can be done about changing the handling of <accessor> versus <variable> tags.
...30 minutes later, and thanking Adobe for open-sourcing Flex... I found XMLDecoder.getExistingValue() uses describeType and does account for getter/setter (aka "accessor"). My constructor created an empty ArrayCollection. Well, XMLDecoder.setValue does not know whether to replace this AC or to add items to it. It does the latter. Moved the AC instantiation until the first call to the getter (checking for null of course), and now it works!
I hope that fixes it for you. Key parts of XML Decoder to visit if you're inclined: setValue(), getExistingValue(), and then the problem issue performed by promoteValueToArray().
Retracted portion starts...
I too am finding this same behavior. I don't know if this would count as an answer, but I have code that does work, taken from this site. The key difference that I can discern between my code/data and what is posted at that site is the manner in which I declare my collection/array in the schema.
In my schema, I had declared a collection in this way:
<complexType name="Things">
<sequence>
<element name="thing" type="ids:Thing" minOccurs="0" maxOccurs="unbounded"/>
</sequence>
</complexType>
<complexType name="ParentThing">
<complexContent>
<sequence>
<element name="things" type="Things"/>
</sequence>
<complexContent>
</complexType>
In the code from the site linked above, the collection is declared more directly:
<xs:complexType name="example">
<xs:sequence>
...
<xs:element name="items">
<xs:complexType>
<xs:sequence>
<xs:element name="item" type="item" maxOccurs="5"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
(In case you're thrown off, "example" is a type and an element in the sample code. This threw me off while investigating how the sample code worked. (I prefer the convention of capitalizing types/classes only.))
Anyhow, the sample code works, and the schema difference seemed to be the only difference that mattered. Looking at the XML instances (his and mine), there wasn't a difference to see. Each collection is parented by an element with a pluralized name. That is <Things> has <thing> instances, while <items> has <item> instances.
I'd be interested to know what your schema and/or XML instance looks like and whether changing it to match the example above (if schema changes are possible in your case) fixes the issue.
Related
I have a #OneToMany JPA association with an instance of Curriculum having several instances of WorkExperience.
The issue I have is that I want to be able to persist one Curriculum together with several WorkExperiences in a single entity manager persist/save call.
I am not sure how to glue several instances of WorkExperiences coming from a regular HTTP POST of a html form to a java collection/set in the Spring MVC model attribute...
First of all, is this possible at all? If so is it a good idea and what kind of html can post collections/arrays of data in a regular HTTP POST?
The Curriculum JPA entity:
#Entity
public class Curriculum {
...
#OneToMany
private Set<WorkExperience> workExperiences;
...
The WorkExperience JPA entity:
#Entity
public class WorkExperience {
...
Yes, it is possible. Spring MVC supports sending Lists/Maps as form values. The way that works is by subscripting the value. For a List, you use the list number, like
<form:input path="myVal[1].property" />
And for a Map you use the map key like
<form:input path="myVal[key].property' />
This is assumming your Model Attribute has a List/Map of said item. I would recommend using a DTO and translating to your Entity. It may be overkill, but I have a problem with allowing the View to manipulate my Entity objects directly.
Also to note: You will have to do some View-side coding to dynamically add/remove items on the form. This can be a real pain, as deletes don't work like you would imagine. Spring MVC has the ability to add to a List/Map, alter the items in a List/Map, but I haven't found a way to remove items from a map directly. I usually handle removes by adding a "remove" boolean flag into my DTOs, then tracking removals by simply adding a form:hidden element for that item in the List/Map, and clean the List/Map on the server-side when I get it.
Once you get all your Entities on the Server-side, then you have to store them. If you want this to be more auto-magic, simply set an annotaion on your parent Entity like
#OneToMany(cascade=CascadeType.PERSIST)
There are several CascadeTypes available, so pick the one that makes sense.
Suppose I instantiate two sub-objects in Mate event map:
<EventMap>
...
<ObjectBuilder generator="{SubModelA}" />
<ObjectBuilder generator="{SubModelB}" />
...
</EventMap>
...and one main object which must contain previous objects in a collection:
...
<ObjectBuilder generator="{MainModel}" />
...
How can I assign created SubModelA and SubModelB objects as a collection to property in MainModel by using Mate?
You'll have to use the Mate PropertyInjector to inject them in an appropriate setter in MainModel, which handles the collection logic. Something like:
<ns:Injectors target="{MainModel}">
<ns:PropertyInjector source="{SubModelA}" targetKey="updateCollection"/>
<ns:PropertyInjector source="{SubModelB}" targetKey="updateCollection"/>
</ns:Injectors>
Of course, you'll have to add a lot of checks for already added models in the updateCollection method. With custom [Bindable] metadata you'll even support binding to the collection in MainModel. It is a bit ugly (and, actually, a very bad use of dependency injection), but I'm pretty sure you wouldn't be able to instantiate any collection from the EventMap in a reasonable way. The other way is to create your custom Mate action (it's not that hard, see the sources for hints how to do it). You may also consider simplifying your design.
I know that in ASP.NET (talking about 2.0 here primarily) one can set a property on an object that takes a collection of things (an enumerable type I'm guessing is the trigger) and then reference it declaritivly. For example:
<ObjectDataSource properties="blahblahblah">
<SelectParameters>
<asp:Parameter />
</SelectParameters>
</ObjectDataSource>
It is the <asp:Parameter /> part which is the root of my question. Say I wanted a simpler collection on a type. Say a List<String> or if generics are out, an IntegerCollection or StringCollection. How would I use that declaratively? Is <string value=''> allowed, or can I put raw values into it like <StringCollection>string, string, string</StringCollection> or what?
EDIT:
I feel like I was not clear enough in my question. I understand that ObjectDataSource implements its SelectParameters property as a ParametersCollection, and that one can use that property declaratively (in an ASPX page) to set up Parameter types within that collection. What I'm wondering is if I made something like StringCollection as a property on another control, is there a syntax (in ASPX) for adding strings to that collection? Or would I have to define a wrapping class like how DropDownList takes ListItems to fill its collection?
In an objectdatasource the selectparameter refers to a parameter in a method that returns a collection. That parameter needs to be something that can be converted from a string, it cannot be a collection or an array.
I eventually found what I needed for this. The general answer is to use a TypeConverter attribute on the property. The GridView does this with (as one example) DataKeyNames, converting a comma separated list of names in a string into an array of strings.
I understand that I can make the property nullable or use a bool called [PropertyName]Specified to determine whether the property is serialized to XML, but I would like the auto-generated examples to hide these elements in one method's definition, and show them in another. This way the user knows whether they'll be there or not.
For example,
here is what displays now (same for both):
Web Service Method1 Example
...
<Object>
<Column Value="int" xsi:nil="true" />
</Object>
...
Web Service Method2 Example
...
<Object>
<Column Value="int" xsi:nil="true" />
</Object>
...
here is what I want to display:
Web Service Method1 Example
...
<Object>
<Column Value="int" />
</Object>
...
Web Service Method2 Example
...
<Object />
...
Is this even possible without creating different Classes?
No, it's not. You're serializing instances of classes. This is independent of web methods.
The web service infrastructure doesn't fit what you're looking for. In WSDL, an operation uses messages which have parts which are of types which are described in an XML schema. In order for two operations to be the same except for one element (column), they must use messages referring to different types.
Alternatively, you could have one of your methods accept a parameter of a class without the extra column, and have the other use that same parameter, plus a separate parameter which is just the extra column.
Best way, then, is just to have one class inherit the other and add the Column property.
I use ASP.Net with NHibernate accessing a Pgsql database.
For some of our Objects, we use NHibernate bags, which map to List objects in our application. Sometimes we have issues with needing to refresh the objects through NHibernate when we update anything to do with the lists in the database.
<bag name="Objects" inverse="true" lazy="true" generic="true" >
<key column="object_id" />
<one-to-many class="Object" />
</bag>
Above is a sample of the code I use for our bags.
I was wondering if anyone else came across this issue anywhere, and what you do to work around it?
Have you tried NHibernate cascades, such as save-update?
You are able to tell NHibernate to automatically traverse an entity's associations, and act according to the cascade option. For instance, adding an unsaved entity to a collection with save-update cascade will cause it to be saved along with its parent object, without any need for explicit instructions on our side.
Here is what each cascade option means:
none - do not do any cascades, let the users handle them
save-update - when the object is saved/updated, check the associations and save/update any object that requires it (including save/update the associations in many-to-many scenario).
delete - when the object is deleted, delete all the objects in the association.
delete-orphans - when the object is deleted, delete all the objects in the association. In addition to that, when an object is removed from the association and not associated with another object (orphaned), also delete it.
all - when an object is saved/updated/deleted, check the associations and save/update/delete all the objects found.
all-delete-orphans - when an object is saved/updated/deleted, check the associations and save/update/delete all the objects found. In addition to that, when an object is removed from the association and not associated with another object (orphaned), also delete it.
More info here:
NHibernate Cascades: the different between all, all-delete-orphans and save-update