Tips/Advices to change EMF code generator behaviours [message #1793217] |
Wed, 01 August 2018 12:22  |
Eclipse User |
|
|
|
Hi,
We want to change slightly the way EMF generates the code to permit clear separation of custom code from generated-code using JET and EMF Code Generator. Here is an overview of the test that illustrates our issue.
BundleA XCore model
@GenModel(editDirectory="/org.eclipse.emf.test1.bundle_a.edit/src-gen")
package org.eclipse.emf.test1.bundle_a
class ClassA1{
op void func()
}
class ClassA2{
op void func()
}
BundleA files
/src-gen/...impl/ClassA1Impl
/src-gen/...impl/Bundle_aFactoryImpl
/src-gen-custom/...impl/UserDefinedClassA2Impl (extends ClassA1Impl outside EMF).
/src-gen-custom/...impl/UserDefinedBundle_aFactoryImpl (extends Bundle_aFactoryImpl outside
EMF).
plugin.xml (provide an factory_override that refers to UserDefinedBundle_aFactoryImpl
BundleB XCore model
@GenModel(editDirectory="/org.eclipse.emf.test1.bundle_b.edit/src-gen")
package org.eclipse.emf.test1.bundle_b
import org.eclipse.emf.test1.bundle_a.ClassA1
import org.eclipse.emf.test1.bundle_a.ClassA2
class ClassB1 extends ClassA1{
}
class ClassB2 extends ClassA2{
}
BundleB files
BundleB only contains generated code.
Default EMF Generator Behaviour
ClassA1Impl <- ClassB1Impl
ClassA2Impl <- ClassB2Impl
Desired EMF Generator Behaviour
ClassA1Impl <- ClassB1Impl
[color=skyblue]ClassA2Impl <- UserDefinedClassA2Impl <- ClassB2Impl[/color]
Problem Summary
In other words, if we detect a UserDefined class for a specific EMF generated class then we would like the inherited classes extend that UserDefined class. We would like similar behaviour with the ItemProviders generated in the .edit bundles.
Options
1) Use default EMF Code Generation and then start a new Builder that would analyse the EMF CompilationUnit and fix the inheritance with the AST. We think this option could work efficiently.
2) Inject required code/modified JET templates into the EMF Code Generator. We are not so sure with this option.
Workspace Sample
To import the attached sample
1) Import->General Existing Projects into Workspace
2) Select archive file: test_factory_override.zip
Thanks in advance for any tips and advices.
Thanks
Regent ;-)
|
|
|
|
|
|
|
Re: Tips/Advices to change EMF code generator behaviours [message #1793522 is a reply to message #1793217] |
Thu, 09 August 2018 09:52   |
Eclipse User |
|
|
|
Hi,
As indicated above, I created customs GenClassGeneratorAdapter and ImportManager classes and overrided ImportManager#getImportedName(String qualifiedName, boolean autoImport). I am trying to get the definition of the EClass associated to that qualifiedName. I digged into GenClass, EPackage, ECoreUtil but I found nothing. I presume the code generator maintains that kind of information somewhere. If you have some tips, that would be appreciated. Here is an overview of the code.
public class ApogyGenClassAdapter extends GenClassGeneratorAdapter {
public ApogyGenClassAdapter(GeneratorAdapterFactory generatorAdapterFactory) {
super(generatorAdapterFactory);
}
@Override
protected void createImportManager(String packageName, String className) {
importManager = new ImportManager(packageName, className) {
@Override
public String getImportedName(String qualifiedName, boolean autoImport) {
// Here are the elements on which we can dig into to figure out the
// associated EClass:
// -GenClass genClass = (GenClass) generatingObject;
// -String qualifiedName (e.g. org.eclipse.emf.ecore.EObject)
// -String this.packageName (e.g. org.eclipse.apogy)
// -String this.className (e.g. DummyClassnameImpl)
return super.getImportedName(qualifiedName, autoImport);
}
};
}
}
Regent ;-)
|
|
|
|
|
|
|
|
Re: Tips/Advices to change EMF code generator behaviours [message #1794355 is a reply to message #1793217] |
Wed, 29 August 2018 09:37   |
Eclipse User |
|
|
|
Hi,
In the past few days, I have continued development. While I was completing the javadoc and the last tests, I realized that the Import Manager has stopped working. I decided to create an example from the bottom up. After 2 days of tests of all kinds, I can no longer operate the Import Manager. It seems that the getImportedName () I overloaded no longer plays its role. Yet everything worked perfectly. I'm sure it's a detail that is missing but I cannot figure it out. Here's the main artifacts.
1) TestGeneratorAdapterFactory
public class TestGeneratorAdapterFactory extends GenModelGeneratorAdapterFactory {
@Override
public Adapter createGenClassAdapter() {
if (genClassGeneratorAdapter == null) {
genClassGeneratorAdapter = new GenClassGeneratorAdapter(this) {
@Override
protected void createImportManager(String packageName, String className) {
importManager = new TestImportManager(packageName);
importManager.addMasterImport(packageName, className);
if (generatingObject != null) {
((GenBase) generatingObject).getGenModel().setImportManager(importManager);
}
}
};
}
return genClassGeneratorAdapter;
}
@Override
public Adapter createGenPackageAdapter() {
if (genPackageGeneratorAdapter == null) {
genPackageGeneratorAdapter = new GenPackageGeneratorAdapter(this) {
@Override
protected void createImportManager(String packageName, String className) {
importManager = new TestImportManager(packageName);
importManager.addMasterImport(packageName, className);
if (generatingObject != null) {
((GenBase) generatingObject).getGenModel().setImportManager(importManager);
}
}
};
}
return genPackageGeneratorAdapter;
}
@Override
public Adapter createGenModelAdapter() {
if (genModelGeneratorAdapter == null) {
genModelGeneratorAdapter = new GenModelGeneratorAdapter(this) {
@Override
protected void createImportManager(String packageName, String className) {
importManager = new TestImportManager(packageName);
importManager.addMasterImport(packageName, className);
if (generatingObject != null) {
((GenBase) generatingObject).getGenModel().setImportManager(importManager);
}
}
};
}
return genModelGeneratorAdapter;
}
public class TestImportManager extends ImportManager {
public TestImportManager(String compilationUnitPackage) {
super(compilationUnitPackage);
}
@Override
public String getImportedName(String qualifiedName, boolean autoImport) {
if (qualifiedName.equals("test.impl.AImpl")) {
return super.getImportedName("test.impl.ACustomImpl", autoImport);
} else {
return super.getImportedName(qualifiedName, autoImport);
}
}
};
}
2) test.xcore test sample
@GenModel(dynamicTemplates="false")
package test
class A{}
class B extends A{}
3) Resulting Class (AImpl should be ACustomImpl based on TestGeneratorAdapterFactory)
public class BImpl extends AImpl implements B {
protected BImpl() {
super();
}
@Override
protected EClass eStaticClass() {
return TestPackage.Literals.B;
}
} //BImpl
I put in attachment the codegen sample project (Eclipse host) and the codegen test project (Eclipse target).
Thanks in advance.
|
|
|
|
|
|
|
|
Re: Tips/Advices to change EMF code generator behaviours [message #1794378 is a reply to message #1793217] |
Wed, 29 August 2018 15:23   |
Eclipse User |
|
|
|
Hi,
My colleague and pursued the investigation without any success. I modified a little the codegen to simplify the debugging. I tried different approaches in ImportManager#getImportedName(String, boolean) such as:
returnValue = super.getImportedName("test.impl.AImpl", autoImport);
returnValue = super.getImportedName("test.impl.ACustomImpl", autoImport);
shortNameToImportMap.put("AImpl", "test.impl.ACustomImpl");
addImport("test.impl.ACustomImpl");
returnValue = "ACustomImpl";
Despite the several permutations, no changes were conclusive.
IMPORTANT NOTE: At some point, and I don't know why, we noticed momentarily the proper desired change to be reflected in the target JDT editor then it switched back to the default and undesired behaviour. This happened for a while before stopping for a reason that I do not understand.
ORIGINAL: public class BImpl extends AImpl
INTERMEDIATE: public class BImpl extends ACustomImpl (change momentarily less than half a second)
FINAL: public class BImpl extends AImpl
If you generate the code for test.xcore, the custom codegen generate a log in the console. Pay attention to the last section:
TestImportManager(): Qualified Name = test.impl.BImpl, ECoreClass = B
getImportedName(): test.impl.AImpl
[color=red] getImportedName() === Customize the import for this one.[/color]
[color=red] getImportedName(): test.impl.AImpl >>> ACustomImpl[/color]
getImportedName(): test.B
getImportedName(): test.B >>> B
getImportedName(): org.eclipse.emf.ecore.EClass
getImportedName(): org.eclipse.emf.ecore.EClass >>> EClass
getImportedName(): test.TestPackage
getImportedName(): test.TestPackage >>> TestPackage
printMap(shortName, importName):
super => BImpl.super
EClass => org.eclipse.emf.ecore.EClass
B => test.B
[color=red]ACustomImpl => test.impl.ACustomImpl[/color]
BImpl => test.impl.BImpl
this => BImpl.this
TestPackage => test.TestPackage
printImports():
org.eclipse.emf.ecore.EClass
test.B
test.TestPackage
I put in attachment the latest version of the custom codegen and its sample. I added the target platform I used to launch the target and test the sample.
I followed the loophole example (https://github.com/mbarbero/emf-loophole) and the OCLInEcore code generator.
I hope this could lead you to an idea???
Thanks ;-)
|
|
|
|
|
|
|
|
|
|
|
|
|
Powered by
FUDForum. Page generated in 0.33912 seconds