Home » Modeling » Epsilon » Feature not found in undefined object(Property not working in ETL without setter or on nested class)
Feature not found in undefined object [message #1787199] |
Mon, 21 May 2018 23:01  |
Eclipse User |
|
|
|
Hello,
I am writing a standalone (i.e. Java runtime) transformation where the source is an EMF model generated by Xtext and the target is plain (non-EMF) Java classes.
The source class, loaded with new InMemoryEmfModel(...), is generated as:
public class MySourceImpl extends MinimalEObjectImpl.Container implements MySource {
protected MySourceData data;
public MySourceData getData()
{
return data;
}
}
The target class is loaded with new JavaModel(...) and defined as:
public class MyTarget extends MySuperTarget<Data> {
public class Data extends MySuperTarget.Data {
// stuff here
}
}
public abstract class MySuperTarget<D extends Data> {
private D data;
public D getData() {
return data;
}
}
This is how I am trying to implement the transformation:
rule TransformTest
transform ms : Origin!MySource
to md : Destination!MyTarget {
md.data ::= ms.data;
md.data.id = ms.data.id;
}
When module.execute() runs, it fails with the following exception:
Property 'data' not found in object org.eclipse.test.MyTarget@7aa85607
at (bundleresource://14.fwk154482552/org/eclipse/test/transformation/TransformTest.etl@5:4-5:27)
at (unknown@0:0-0:0)
The message is clear that it does not find the data property in the target. After some debugging, I found out that OperationContributorRegistry.findContributedMethodForEvaluatedParameters(...) looks for a MyTarget.setData() method, but it does not really exist because the class is normally instantiated by Gson, which uses the fields directly, instead of setter methods. Anyway, I added a setData() method for test purposes with Epsilon, and now the error changes to the following:
Called feature id on undefined object
at (bundleresource://14.fwk342597804/org/eclipse/test/transformation/TransformTest.etl@6:4-6:31)
at (unknown@0:0-0:0)
Two questions:
- It looks like the script is trying to call setId() on the MyTarget.data, which is null. Why is the object null if I just set it to the equivalent() of the source object by using the special assignment on the previous line?
- I tried to create another specific rule to transform MySourceData to MyTarget.Data, but the editor complains about the dot - so should I assume that nested classes are simply not supported as explicit targets of transformation rules?
Thanks,
Flavio
[Updated on: Mon, 21 May 2018 23:04] by Moderator
|
|
| |
Re: Feature not found in undefined object [message #1787249 is a reply to message #1787226] |
Tue, 22 May 2018 13:56   |
Eclipse User |
|
|
|
Hi Dimitris,
I have created a minimal working example for this situation, which gives the same problem as reported above - project (plugin) files attached here.
I am using Epsilon 1.4.0.201611012202 with Java 8.
After importing the project, you can right click on org.eclipse.epsilon.mwe.EtlTest, then Run As -> Java Application. It will run the main method, which gives out the expected error:
Called feature id on undefined object
at (...\org.eclipse.epsilon.mwe\target\classes\org\eclipse\epsilon\mwe\TransformTest.etl@6:4-6:28)
at (unknown@0:0-0:0)
at org.eclipse.epsilon.eol.dom.PropertyCallExpression.execute(PropertyCallExpression.java:46)
at org.eclipse.epsilon.eol.dom.PropertyCallExpression.execute(PropertyCallExpression.java:40)
at org.eclipse.epsilon.eol.dom.AssignmentStatement.execute(AssignmentStatement.java:52)
at org.eclipse.epsilon.eol.execute.ExecutorFactory.executeAST(ExecutorFactory.java:97)
at org.eclipse.epsilon.eol.dom.StatementBlock.execute(StatementBlock.java:49)
at org.eclipse.epsilon.eol.execute.ExecutorFactory.executeAST(ExecutorFactory.java:97)
at org.eclipse.epsilon.eol.dom.ExecutableBlock.executeBlockOrExpressionAst(ExecutableBlock.java:94)
at org.eclipse.epsilon.eol.dom.ExecutableBlock.execute(ExecutableBlock.java:108)
at org.eclipse.epsilon.eol.dom.ExecutableBlock.execute(ExecutableBlock.java:137)
at org.eclipse.epsilon.eol.dom.ExecutableBlock.execute(ExecutableBlock.java:81)
at org.eclipse.epsilon.etl.dom.TransformationRule.executeSuperRulesAndBody(TransformationRule.java:221)
at org.eclipse.epsilon.etl.dom.TransformationRule.transform(TransformationRule.java:175)
at org.eclipse.epsilon.etl.strategy.FastTransformationStrategy.executeTransformations(FastTransformationStrategy.java:165)
at org.eclipse.epsilon.etl.strategy.FastTransformationStrategy.transformModels(FastTransformationStrategy.java:157)
at org.eclipse.epsilon.etl.EtlModule.execute(EtlModule.java:133)
at org.eclipse.epsilon.mwe.EtlTest.main(EtlTest.java:41)
Maybe it's just a problem with my ETL script, maybe it's on the way I load the models, or due to the nested class in the target... not sure, so any support would be appreciated.
Thanks,
Flavio
|
|
| | | |
Re: Feature not found in undefined object [message #1787339 is a reply to message #1787290] |
Wed, 23 May 2018 16:06   |
Eclipse User |
|
|
|
Dimitris,
It seems to work, thanks for the help! I would prefer to be able to reference it in the transformation as Destination!MyTarget.Data instead, as it would avoid ambiguity in case we have MyTarget.Data and MyOtherTarget.Data, but I hope that won't be an issue with my current model. I also had to make the nested class static, else Epsilon was not able to instantiate it, but that would also be a minor functional improvement.
My main concern now is that Epsilon forces me to provide setters for any properties used in the transformation. My target model is basically read-only, as it's derived from the editable source model, so I don't need and don't want to add setters everywhere so the person working on the client application using the model does not get confused by those.
I see that JavaPropertySetter looks specifically for a setX() method, so the transformation does not work without these. As I mentioned on my initial message above, Gson uses reflection to set private fields even if a setter is not exposed, and I would like to have that feature on Epsilon as well. Is there a way for me to write my own AbstractPropertySetter to implement this feature, or can I add a OperationContributor to do that? Else, should I create a new enhancement request in Bugzilla?
Thanks,
Flavio
[Updated on: Wed, 23 May 2018 16:46] by Moderator
|
|
| |
Re: Feature not found in undefined object [message #1787453 is a reply to message #1787344] |
Fri, 25 May 2018 11:34   |
Eclipse User |
|
|
|
Hi Dimitris,
It was actually fairly easy to implement it! A JavaFieldPropertySetter implementation extending JavaPropertySetter did the trick, with 82 lines of code, and it seems to work very well in my initial testing (it would be even less if org.eclipse.epsilon.eol.execute.introspection.java.ObjectField defined a constructor to set its properties.
Since I was already extending JavaModel, I also added some reflection functionality to automatically identify the classes and object instances to be added to the model, starting from its root element. Therefore, this code:
MySource sourceObj = new MySource("My data id");
Collection<Object> objects = Arrays.asList(sourceObj, sourceObj.getData());
Collection<Class<?>> classes = Arrays.asList(MySource.class, MySourceData.class);
JavaModel javaModel = new JavaModel("Origin", sourceObj, sourceObj.getData());
Can be replaced by one single line of code:
JavaModel javaModel = new ReflectiveJavaModel("Origin", new MySource("My data id"));
The same can be done for the target model, I can now load it with one line and reflection does its magic internally:
JavaModel javaModel = new ReflectiveJavaModel("Destination", Collections.singleton(MyTarget.class));
The other two changes I'd like to see, namely the support for non-static inner classes and explicitly specifying the name of the enclosing class in the ETL rule (e.g. Destination!MyTarget$Data), would apparently be more complicated. It might require changes to FastTransformationStrategy, EolModelElementType, and probably other places.
I am happy with the results, I am attaching the final code here for your appreciation. It would be good if at least JavaFieldPropertySetter is added to Epsilon's code base, since it's generic enough and could be useful for anyone using read-only target Java models.
Thanks for all the assistance,
Flavio
|
|
| | |
Re: Feature not found in undefined object [message #1787544 is a reply to message #1787486] |
Mon, 28 May 2018 10:42  |
Eclipse User |
|
|
|
Hi Dimitris,
I wasn't aware of the backticks syntax (it is only seems to be mentioned in a footnote on 149 of the Epsilon Book).
I will keep the classForName implementation as it looks cleaner on the ETL script, but it is good to have that as an option.
Thanks,
Flavio
|
|
|
Goto Forum:
Current Time: Sat Jul 12 09:41:38 EDT 2025
Powered by FUDForum. Page generated in 0.27562 seconds
|