Acceleo : How to cast in a Collection ? [message #1766897] |
Wed, 28 June 2017 15:47 |
Mad Vin Messages: 40 Registered: September 2013 |
Member |
|
|
Hello,
Here is a simple extract of code to show easily the problem (so replace OclAny by Sequence(OclAny) is not the answer i want :p, because i have this kind of problem for a much more complex architecture) :
[let seq : OclAny = Sequence{1, 'str', Set(OclAny), null}] ... [/let]
How to retrieve seq->at(1) ? seq->at(2) ? seq->at(3) ? seq->at(4) ? How to cast seq into a Sequence(OclAny) ?
I've found nothing on the internet. Without this cast, it's impossible to retrieve the elements of the sequence, because the 'at' method cannot be called on an OclAny typed variable, "->oclAsType" cannot be called on an OclAny typed variable, and the oclAsType method refuses Sequence(OclAny) argument. Same problem in the queries.
Thank you for your help.
Acceleo version : 3.4.1
Eclipse version : Helios Service Release 2
|
|
|
|
Re: Acceleo : How to cast in a Collection ? [message #1766947 is a reply to message #1766905] |
Wed, 28 June 2017 23:35 |
Mad Vin Messages: 40 Registered: September 2013 |
Member |
|
|
Ok, that's what i thought... it's particularly weird for a typed language to not allow to cast a type into a subtype, especially when the subtype is a type defined by the language... :/
Aren't the Sequence instances typed by a subtype of EObject that we could use to do the cast ? Aren't there a solution to retrieve these Sequences and their contents by using a Java services class that i could implement ?
I'm going to try to explain what i want to do : I need to use several internal structures in Acceleo to store some settings (a setting is implemented by storing a setting's id associated to a specific value described in the documentation) about some elements (some of them can be extracted from an emx model, and others can be specified by the Acceleo developers). So it's a kind of Acceleo queries API that will be used by the other Acceleo developers. This API defines queries for creating these structures with the specified settings values, for enabling to access to the values of these settings in a simple way, and for generating the expected code according to the values of the specified settings of a structure.
But i want to hide the internal implementation of these structures from the callers because i want that these structures can be extended by new features later without modifying the already existing calls. It's too long to explain exactly how i do it, but to be brief, the API queries creating structures return an OclAny object (the internal implementation is hidden because it is too complex, and this implementation is done by a Sequence of several kind of objects more or less complex that the developers don't need to know), and the API queries accessing to the structures and generating the expected code take these structures instances as parameter. My problem is that the caller gives to the queries generating code an OclAny typed parameter that i know it is a Sequence of several objects in a specific order (the hidden internal implementation that i'm the only one who needs to know), but i can't specify to Acceleo that this OclAny parameter is a Sequence... This is my problem.
Sorry if it's hard to understand... I know a better solution to do that is to create a new ECore defining these structures, to generate this Ecore code, to import in the Acceleo project this metamodel, and to create the instances in a java services class called by Accelo queries. but for the moment i would like to find a simple solution without adding any external dependency to the Acceleo projects because i've got several Acceleo projects executed in standalone outside Eclipse and depending from each others, and i prefer to avoid to lose time for the moment by trying to fix the dependencies errors.
Thank you for your patience. ;)
[Updated on: Thu, 29 June 2017 03:32] Report message to a moderator
|
|
|
|
Re: Acceleo : How to cast in a Collection ? [message #1766968 is a reply to message #1766957] |
Thu, 29 June 2017 07:55 |
|
Hi,
You will encounter issues with the OCL implementation we rely on not considering that Sequences (collections, in general) are instances of OclAny so what you plan to achieve is at first sight impossible in Acceleo.
It seems extremely strange, however, that you're basically saying "my user will send me an object that I know is a Sequence, but I don't want to type my parameter as a Sequence". By default, I consider that APIs that take "Object" as parameter without telling me exactly what they want are a bad design. I really agree with Ed here in that it seems, from the explanation you've given, that you should really reconsider the design of your APIs. Do you really want to obfuscate your APIs with OclAny parameters?
Nevertheless, if you're really stuck on this design decision for any reason, you will have to work around the limitations of the underlying OCL implementation. That will have to be done either in Java (through a service call) or with quirky workarounds in your acceleo template such as casting into a set then flattening it... And I'm not even sure that would work, especially if your initial sequence can contain other sequences. You haven't given us much to work with but off the top of my head, these are the only things I can think of that might help:
myOclAny->flatten() (the "->" operator on an object that is not typed as a sequence is an implicit cast into a set, but you'll likely end up with a Set containing your Sequence)
myOclAny->asSequence() (same deal here, that will likely be a Sequence containing your initial sequence as sole object, but it's still typed as oclAny so you likely won't be able to use it)
Laurent Goubet
Obeo
|
|
|
Re: Acceleo : How to cast in a Collection ? [message #1766984 is a reply to message #1766968] |
Thu, 29 June 2017 09:27 |
Mad Vin Messages: 40 Registered: September 2013 |
Member |
|
|
Thank you for your answers.
I know such a design is not perfect because the structures i create are not typed clearly, and i suppose that the only way to create properly new typed complex structures usable in Acceleo is to create a new metamodel only for this task. But like i said, for the moment i prefer to avoid this solution.
I can't explain to you easily the architecture of my API, the only thing to know is that it should work like i wanted, but the only problem i have is this problem of cast of OclAny objects into Collections.
But after having tested several things, i've finally found a solution by using a Java services method that is simple. It only needs to create a query calling a Java services method casting the OclAny object into Sequence, like this :
@SuppressWarnings("unchecked")
public static List<Object> castObjectIntoSequence(Object obj) {
return (List<Object>) obj;
}
[query public castObjectIntoSequence(contextObject : OclAny, obj : OclAny) : Sequence(OclAny) =
invoke('package1.MyJavaServicesClass', 'castObjectIntoSequence(java.lang.Object)', Sequence{obj})
/]
We have to do the same kind of solution for Set instances and other Collections types.
And it works ! I can easily retrieve like this the contents of the Sequence. And if one of the element of the Sequence is another Sequence or a Set, it only needs to call the corresponding cast query on this element. Ex :
castObjectIntoSet(castObjectIntoSequence(myObject)->at(2)) if the second element of the Sequence is a Set.
Thank you for your support.
Best regards.
|
|
|
|
Powered by
FUDForum. Page generated in 0.04274 seconds