How to get an Ecore feature disply name without an object instance? - eclipse-emf

I'd like to create a GUI table to display a given list of features of an EObject sub-class. To do this I have to get the display names of the features for the column header.
How do I get the feature display names in the best way?
One solution that seems a bit like a hack:
If I have an instance of the class then I can use the adaptor factory to get a IItemPropertySource that can do this:
SomeEntity e = ...
String displayName = adaptorFactory.adapt(e, IItemPropertySource.class)
.getPropertyDescriptor(null, feature).getDisplayName(null));
But when the table is empty there is no SomeEntity object handy to use to get the IItemPropertySource.
I can create a dummy object using the EFactory in this way:
EClass containingClass = feature.getEContainingClass();
SomeEntity dummy = containingClass.getEPackage().getEFactoryInstance()
.create(containingClass));
... and then use that object the get the IItemPropertySource. But this seem a bit like a hack. Is there no better solution?

If you know the class at compile time, you can create the ItemProviderAdapter yourself:
MyClassItemProvider provider = new MyClassItemProvider(adaptorFactory);
String name = provider.getPropertyDescriptor(null, property).getDisplayName(null);
If you do not know the class at compile time, but only have an EClass instance at runtime, things are more complicated, because the necessary methods are protected. You have to "make" them public first.
I would add respective methods to the generated MyPackageSwitch and MyPackageAdapterFactory classes (in myPackage.util).
In MyPackageAdapterFactory:
/**
* #generated NOT
*/
public MyPackageSwitch<Adapter> getModelSwitch() {
return modelSwitch;
}
In MyPackageSwitch:
/**
* generated NOT
*/
public T doPublicSwitch(EClass theEClass, EObject theEObject) {
return doSwitch(theEClass, theEObject);
}
Now you can create an ItemProviderAdapter for an EClass theEClass like this:
provider = (ItemProviderAdapter) adapterFactory.getModelSwitch()
.doPublicSwitch(theEClass, null);
EMF was obviously not made for this. Keep in mind that this all is only working if you do not have any custom provider implementations that uses the EObject values.

Related

Initializing empty relationships in entities

I have entities with 1:1 or 1:M relations to other entities. All relations however are nullable.
I want to proxy some operations to the related entity. I'm giving example below. The problem is that if the relation still does not exist, I have null, so I'm ending up constantly checking for nulls, which obviously is wrong. What I would like to do is to hydrate my entities with empty objects. Reasons:
Doctrine knows what instance should be created for the field anyway. So it should just provide empty instance instead of null
I don't want to fill my code with initializations, like
$object->setSettings(new SettingsEntity)
If the requests should be proxied is somehow disputable, but I want to hide the DB representation from the client code. If my direction however is totally wrong, please point me to the right direction. I may accept that this is responsibility of the model, not of the entity, but Doctrine always returns entities to me
Sure, I can add the initialization either in the constructor of the entity, or to provide getter that creates a new instance of the object, if such does not exists. There are couple of reasons I don't want this:
I don't know how objects are actually hydrated. I assume such initialization should happen in an event and not in the constructor
I don't want to write the code for each entity (at some point, someone will forget to add the initialization in the getter) and want to make it automatically for each relation instead.
Some example code:
/**
* SomeObject
* #ORM\Entity()
* #ORM\Table(
name="some_object"
* )
*/ class SomeObject implements DataTransfer {
/**
* #ORM\OneToOne(targetEntity="Settings", mappedBy="SomeObject")
*/
protected $settings;
public function getSettings() {
return $this->settings;
}
public function get() {
$record = new \stdClass();
$record->id = $this->getId();
...
$settingsObject = $this->getSettings();
$record->someKey = $settingsObject ? $settingsObject->getSomeKey() : null;
$record->someOtherKey = $settingsObject ? $settingsObject->getSomeOtherKey() : null;
return $record;
}
Any suggestions, including hacking Doctrine, are welcome.
P.S. Doctrine-ORM version is 2.3. I can upgrade if this will help solving the problem.
I won't discuss your proxy-thingie-theory: your code, your design, I don't have enough knowlegde of these to have an opinion.
About you knowing how Doctrine hydrates its entities, you can see how it's done in \Doctrine\ORM\UnitOfWork::createEntity. It doesn't seem to invoke the constructor (uses \ReflectionClass::newInstanceWithoutConstructor, which obviously shouldn't use the constructor), but you may be interested in listening to Doctrine's post-load event (part of the lifecycle events logic).
About initializing your null properties, i.e. the code that your post-load event should trigger, you should begin by having a superclass over all of your entities: instead of class SomeObject implements DataTransfer {...}, you'd have class SomeObject extends MyEntity {...} (and have MyEntity implement DataTransfer to keep your interface). This MyEntity class would be a "mapped superclass", it would be annotated with #HasLifecycleCallbacks, and declare a method annotated with #PostLoad. There you have your hook to run your null-to-something code.
For this code to be generic (as it'd be coded from this superclass), you can rely on Doctrine's entity metadata, which retains association mappings and all data that the Unit Of Work needs to figure out its low-level DB-accessing business. It should look like the following:
/** #HasLifecycleCallbacks #MappedSuperclass ... */
public class MyEntity implements DataTransfer {
...
/** #PostLoad */
public function doPostLoad(\Doctrine\Common\Persistence\Event\LifecycleEventArgs $event) { //the argument is needed here, and is passed only since 2.4! If you don't want to upgrade, you can work around by using event listeners, but it's more complicated to implement ;)
$em = $event->getEntityManager();
$this->enableFakeMappings($em);
}
private function enableFakeMappings(\Doctrine\ORM\EntityManager $em) {
$mappings = $em->getClassMetadata(get_class($this))->getAssociationMappings(); //try and dump this $mappings array, it's full o'good things!
foreach ($mappings as $mapping) {
if (null === $this->{$mapping['fieldName']}) {
$class = $mapping['targetEntity'];
$this->{$mapping['fieldName']} = new $class(); //this could be cached in a static and cloned when needed
}
}
}
}
Now, consider the case where you have to new an entity, and want to access its properties without the null values checks: you have to forge a decent constructor for this job. As you still need the Entity Manager, the most straightforward way is to pass the EM to the constructor. In ZF2 (and Symfony I believe) you can have a service locator injected and retrieve the EM from there. Several ways, but it's another story. So, the basic, in MyEntity:
public function __construct(\Doctrine\ORM\EntityManager $em) {
$this->enableFakeMappings($em);
}
Doing this, however, would probably confuse Doctrine when the entity is persisted: what should it do with all these instantiated empty objects? It'll cascade-persist them, which is not what you want (if it is, well, you can stop reading ;)). Sacrificing cascade-persisting, an easy solution would be something like this, still in your superclass:
/** #PrePersist */
public function doPrePersist(\Doctrine\Common\Persistence\Event\LifecycleEventArgs $event) {
$em = $event->getEntityManager();
$this->disableFakeMappings($em);
}
/** #PreUpdate */
public function doPreUpdate(\Doctrine\Common\Persistence\Event\LifecycleEventArgs $event) {
$em = $event->getEntityManager();
$this->disableFakeMappings($em);
}
private function disableFakeMappings(\Doctrine\ORM\EntityManager $em) {
$uow = $em->getUnitOfWork();
$mappings = $em->getClassMetadata()->getAssociationMappings();
foreach ($mappings as $mapping) {
if (!$this->{$mapping['fieldName']} instanceof MyEntity) {
continue;
}
//"reset" faked associations: assume they're fake if the object is not yet handled by Doctrine, which breaks the cascading auto-persist... risk nothing, gain nothing, heh? ;)
if (null === $uow->getEntityState($this->{$mapping['fieldName']}, null)) {
$this->{$mapping['fieldName']} = null;
}
}
}
Hope this helps! :)

Accessing Sitecore template field values

This may be documented somewhere, but I cannot find it.
I am using the Sitecore helper and razor syntax to place values into my view:
#Html.Sitecore().Field("foo");
This works fine, but, I have Fields defined in Groups, and a few of them have the same name, like:
Group1: foo
Group2: foo
Question: Is there any way to access the field by group?
Something like this (what I have already tried):
#Html.Sitecore().Field("Group1.foo");
As long as I know it is not possible to use the sections name.
I would avoid to have the same field name even between differents sections.
Or a option is to pass the field ID and then create classes or constants to not hard code IDs
#Html.Sitecore().Field("{E77E229A-2A34-4F03-9A3E-A8636076CBDB}");
or
#Html.Sitecore().Field(MyTemplate.MyGroup.Foo); //where foo returns the id.
EDIT:
MyTemplate.MyGroup.Foo would be classes/structs you created your own just to make easier and more reliable the references all over you project. (you can use a tool to auto-generate it like a T4 template)
public static struct MyTemplate
{
public static struct MyGroup1
{
public static readonly ID Foo = new ID("{1111111-1111-1231-1231-12312323132}");
}
public static struct MyGroup2
{
public static readonly ID Foo = new ID("{9999999-9999-xxxx-1231-12312323132}");
}
}
Try accessing via the GUID of the field. This way, even if they have the same name, the API will be able to load the appropriate field.

Inspect Ember.js: Get the type of an object (Class)?

I use console.log() a lot, especially in combination with Ember.inspect(). But there's one thing I miss:
How can I find out the type of an object (Class)?
For example: Getting something like <Sandbox.ApplicationController:ember288> when inspecting Ember.get("controller")?
If you just want the model name (for example app/models/comment.js has the model name comment), you can use thing.constructor.modelName.
For example:
var aComment = this.get('store').createRecord('comment');
aComment.get('constructor.modelName') // => 'comment'
I understand you are looking for a string for debugging purposes, but I originally came to this question wanting to know specifically how to get the type of the object, not a string describing the object.
Using the built in Javascript property constructor will yield the class used to construct the instance. For example you could do:
person = App.Person.create();
person.constructor // returns App.Person
person.constructor.toString() // return "App.Person"
If you get Class, you can usually call toString() (or as a shortcut concat an empty string + '') to get something like <Sandbox.ApplicationController:ember288>
Another useful feature (in chrome) is the dir command.
dir(App.User)
This will give you the full object information, rather than just the name.
Be aware that some of these answers suggested here only work in development. Once your code is in production most of those methods / class names will get minified.
import Model from '#ember-data/model';
export default class Animal extends Model {
// ...
}
So in development:
const model = this.store.createRecord('animal');
model.constructor.name // returns Animal
in production:
const model = this.store.createRecord('animal');
model.constructor.name // returns 'i' (or any other single letter).
To avoid this, use constructor.toString()
const model = this.store.createRecord('animal');
model.constructor.toString() // returns 'model:animal'

Can I make an Ecore metamodel that enables models to reference Java classes?

Suppose I want to design an Ecore metamodel that looks something like this, designed to be used to "run" a list of classes:
JavaClassRunnerList
0..* JavaClass
And assume I have some Java project that has classes named PrintsHello, PrintsSeparator, and PrintsWorld.
I'd like to be able to then write models that look like this:
JavaClassRunnerList
PrintsHello.class
PrintsSeparator.class
PrintsWorld.class
PrintsSeparator.class
PrintsSeparator.class
I want my model to be able to include a Java project and to recognize its classes as choices for the model references (possibly co-located in the same project the model is in.)
Is this possible?
Ed Merks said the following. See the thread for the remainder of the discussion.
You can use Ecore's EJavaClass data type to create a multi-valued
attribute. You might be better just to use class names, and use a
class loader to convert therm to actual class instances.
Same goes for
wanting references to IProject; you can use a string and then resolve
it to an IProject using the the workspace root.
You should define additional EDatatypes to your ecore for each Java class you want to reference (with 'Instance Type Name' = java class qualified name), and simply use these datatypes to type some of your EAttributes.
Note that you will have to implement specific converters for each created EDatatype if you want to persist EAttribute values in your Resource files.
Example with an EDatatype named 'Date', with instanceTypeName='java.util.Date', you would have to give implementation for the following two methods in your factory implementation:
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* #generated
*/
public Date createDateFromString(EDataType eDataType, String initialValue) {
// TODO replace with your implementation
return (Date)super.createFromString(eDataType, initialValue);
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* #generated
*/
public String convertDateToString(EDataType eDataType, Object instanceValue) {
// TODO replace with your implementation
return super.convertToString(eDataType, instanceValue);
}

Can I get an XmlObject instance if I have its corresponding SchemaType object?

In XmlBeans, I have a compiled schema and I create an instance through the
MyStuff stuff = MyStuff.Factory.newInstance() method.
But in a part of my application I need to treat MyStuff as a generic XmlObject and yet I want to create instances of it. Suppose that I want to do:
workWithObjectsAbstractly(stuff)
where workWithObjectsAbstractly is defined as:
public void workWithObjectsAbstractly(XmlObject o)
{
.
.
SchemaType type = o.schemaType();
XmlObject newInstance = type.??????? <--- is there such method?
.
.
[Work with new instances as XmlObjects]
.
}
Is there a way to do that?
I could inspect the schemaType through Particles and Properties and then create stuff with
XmlCursor, but it seems cumbersome. Can I avoid it?
I don't think you can avoid this, org.apache.xmlbeans.impl.xsd2inst.XmlSampleUtil does this abstraction in order to create auto-generated, valid instances from a SchemaType.
In this case, it uses
XmlObject object = XmlObject.Factory.newInstance();
XmlCursor cursor = object.newCursor();
// Skip the document node
cursor.toNextToken();
// ... it then uses the cursor to add elements, attributes, etc
Hope that helps a bit...