Programmatically create an SConceptAdapter
Hi there,
We're upgrading our languages and plugins, from MPS 3.3 to MPS 2017.1 and we're finding that several classes no longer exist.
Two of them are the SConceptAdapterByName and SPropertyAdapterByName. The only classes that exist are the "...ById" ones. Is there any place that has examples for its usages? What is the preferred way to do this?
It would be nice if, when deprecating/removing some functionality, an alternative could be presented.
Regards,
Sérgio Ribeiro
Porto - Portugal
Please sign in to leave a comment.
Hello again,
We've managed to get it working and just wanted to let it here how we did it in case anyone else needs it.
In our previous version, we had the following code:
As the SConceptAdapterByName no longer exists, we changed to the following:
Regards,
Sérgio Ribeiro
Porto - portugal
Though technically correct, I strongly discourage this approach, as it's MPS internal APIs and are subject to change without notice.
To reason you need an SConcept defined this way is some non-MPS code that needs to interoperate with MPS stuff. First, consider moving the code into an MPS solution, where regular concept/REFERENCE/ clause would yield all the code necessary to identify SConcept, without need for you to depend on implementation details. Second, if moving the code into MPS is not an option (the only legitimate reason I could think of is bootstrapping), generate the definitions, at least. Please refer to jetbrains.mps.smodel.SNodeUtil class, full of SProperty/SConcept statics MPS needs itself for bootstrap purposes.
Use of new SConceptId and new SConceptAsapterById is very fragile approach.
Hi Tikhomirov,
We used to have an MPS based editor and, at that point, we could use the type of code you're referring to. However we had some problems regarding customisation, translations and some class loading troubles.We then decided to abandon MPS as our IDE base and use IntelliJ directly.
We now have an IntelliJ based IDE with all non-essential menus/options/actions removed, fully customised to our reality, totally translated and that works nicely with our Java world.
We still use MPS: our languages are plugins that are deployed with our IDE. We overrided the persistency: the model lives on memory only and we have a Websevice that keeps our instances (with user and locking control).
We try to use Open API functionalities as much as we can, but sometimes we have to go "under the hood" :-) Yes that makes us dependent on implementation changes, but, for now, it's been quite rewarding...
The ideal solution would be having the possibility of completely manipulate models through Open API (and more documentation), but until then...
Regards,
Sérgio Ribeiro
Porto - Portugal
I see your point. Nevertheless, I suggest you consider approach similar to SNodeUtil (with generated static fields). After all, it's only a set of constants, there'd be no classloading/customization issues, and you can still benefit from MPS doing dirty job and handling its own implementation details.
If that approach is not an option for any reason, at least use MetaAdapterFactory.getConcept(long,long,long,String) instead of 'new SConceptAdapterById' clause. Though it's part of MPS internals, too, as long as MPS uses MetaAdapterFactory for generated code, there would be at least an extra release (or even 2 releases) when this class would stay functional albeit deprecated. We can't guarantee this for SConceptAdapterById and SConceptId classes. With that, you'd have more time to react to changes.
Right now, all SConcept's we need to use (and calculate like shown) are available in a class (public static final).
I'll look into MetaAdapterFactory - I assume that the uuidHigh/uuidLow long parameters are the ones obtained through UUID.getMostSignificantBits()/UUID.getLeastSignificantBits(), right?
Regards,
Sérgio Ribeiro
Porto - Portugal
The moment you generate your class with fileds in MPS (using concept// expression) you're all set.
True, MetaAdapterFactory takes uuid.getMostSignificantBits(), uuid.getLeastSignificantBits(), although there's no need to go through UUID, you can just pass long values directly.