Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.
Bug 325427 - Wrong Classifier ID's in ModelPackage when using ENUM's
Summary: Wrong Classifier ID's in ModelPackage when using ENUM's
Status: CLOSED FIXED
Alias: None
Product: EMFT
Classification: Modeling
Component: Texo (show other bugs)
Version: unspecified   Edit
Hardware: PC Linux
: P3 normal (vote)
Target Milestone: ---   Edit
Assignee: Martin Taal CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2010-09-16 05:51 EDT by Mark Hoffmann CLA
Modified: 2017-07-02 18:37 EDT (History)
3 users (show)

See Also:


Attachments
Sample ecore (1.67 KB, application/xml)
2010-09-16 05:53 EDT, Mark Hoffmann CLA
no flags Details
Sample Annotionsmodel (10.35 KB, application/xml)
2010-09-16 05:54 EDT, Mark Hoffmann CLA
no flags Details
My ecore (6.59 KB, application/xml)
2010-09-16 17:23 EDT, Mark Hoffmann CLA
no flags Details
My ModelPackage (28.92 KB, text/x-java)
2010-09-16 17:25 EDT, Mark Hoffmann CLA
no flags Details
Sample plugin that demonstrates the problem (41.68 KB, application/octet-stream)
2010-09-20 08:43 EDT, Mark Hoffmann CLA
no flags Details
Patch for GeneratorUtils (never tested!!!!) (1.69 KB, patch)
2011-04-28 07:55 EDT, Mark Hoffmann CLA
no flags Details | Diff
Better Patch for GeneratorUtils (never tested!!!!) (1.79 KB, application/octet-stream)
2011-04-28 08:10 EDT, Mark Hoffmann CLA
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Mark Hoffmann CLA 2010-09-16 05:51:46 EDT
Build Identifier: 20100617-1415

Texo 0.1.0-201008031709
If you have an enum in your ecore, the classifier id's in the generated model package are not correct and you will end up with the following exception:
Caused by: java.lang.ClassCastException: org.eclipse.emf.ecore.impl.EEnumImpl cannot be cast to org.eclipse.emf.ecore.EClass
	at de.sim.texo.model.common.person.PersonModelPackage.getContactEClass(PersonModelPackage.java:787)
	at de.sim.texo.model.common.person.PersonModelPackage.initialize(PersonModelPackage.java:405)
	at de.sim.texo.model.common.person.PersonModelPackage.<clinit>(PersonModelPackage.java:376)
	... 31 more


Reproducible: Always
Comment 1 Mark Hoffmann CLA 2010-09-16 05:53:35 EDT
Created attachment 179011 [details]
Sample ecore
Comment 2 Mark Hoffmann CLA 2010-09-16 05:54:03 EDT
Created attachment 179012 [details]
Sample Annotionsmodel
Comment 3 Mark Hoffmann CLA 2010-09-16 05:56:08 EDT
As workaround you can debug into the getEPackage method of the generated package and find the right index for the certain classes/enums and change their CLASSIFIER_ID's by hand in the generated code.
Comment 4 Martin Taal CLA 2010-09-16 05:58:45 EDT
Hi Mark,
Both attachments seem to be empty when I download them, can you email them directly to me:
mtaal@elver.org

gr. Martin
Comment 5 Martin Taal CLA 2010-09-16 06:19:37 EDT
Hi,
Forget my request, I can download them.

gr. Martin
Comment 6 Martin Taal CLA 2010-09-16 10:03:40 EDT
Hi Mark,
I reacted in the newsgroup for completeness:

Hi Mark,
I checked the annotations model and there are some strange in there. For example the Address eclass annotation has this eattribute:
qualifiedClassName="texo.test.Address"
however, the Person eclass has an ereference annotation for address with this eattribute:
type="test.Address"

This is the reason that there are compile errors in the generated code for the Person, as it refers to a type which does not get generated. It is best to have a quite empty annotationsmodel (so only annotate what you want to change, the rest is automatically generated). So to solve this I would remove all the ereference annotations.

To be sure, did you manually change the annotations model?

The reason that the ContactType enum is generated in a separate package is because its annotation has this eattribute set:
 qualifiedClassName="test.ContactType"

so therefore it ends up in the test package and not in the texo.test package.

gr. Martin
Comment 7 Martin Taal CLA 2010-09-16 14:30:04 EDT
Hi Mark,
Which Eclipse/EMF version are you using? I tried it on EMF 2.6/Eclipse 3.6.

gr. Martin
Comment 8 Mark Hoffmann CLA 2010-09-16 15:33:00 EDT
(In reply to comment #7)
> Hi Mark,
> Which Eclipse/EMF version are you using? I tried it on EMF 2.6/Eclipse 3.6.
> 
> gr. Martin

Hi Martin,

I investigated a little bit. 
In my opinion, without looking in the code I would say, the CLASSIFIER ID's that are generated in the ModelPackage are the position of the eclassifier-tag in the ecore file. I verified that using an ecore with 12 classes and enums. The generated numbers reflect exactly the position number of the eclassifier tag in the ecore xml file. Enums and eclasses are mixed in the order. The order is given by the ecore-file.

The order in the ModelPackage#getEPackage- eClassifiers starts with eclasses after that the enums are listed. The order of all eclasses are the same as before and the order of the enums is the same, but eclasses and enums are not mixed:

Example:
 
Ecore Order
0 Person class
1 TitleType enum
2 GenderType enum
3 Address class
4 Geolocation class
5 AddressList class
6 PersonList class
7 Contact class
8 ContactType enum
9 ContactContextType enum
10 ContactList class
11 MaritalStatusType enum

ModelPackage eClassifier order:
0 Person class   (ecore index 0)
1 Address class   (ecore index 3)
2 Geolocation class   (ecore index 4)
3 AddressList class   (ecore index 5)
4 PersonList class   (ecore index 6)
5 Contact class   (ecore index 7)
6 ContactList class   (ecore index 10)
7 TitleType enum   (ecore index 1)
8 GenerType enum   (ecore index 2)
9 ContactType   (ecore index 8)
10 ContactContextType   (ecore index 9)
11 MaritalStatusType   (ecore index 11)

I think something like this could happened while creating the model code (Pseudocode):

List<EEnum> enums = new LinkedList<EEnum>();
List<EClass> eclasses = new LinkedList<EClass>();
Map<String,Short) classifierIdMap = new HashMap<String,Integer>();

ECLassifier[] ecoreClassifiers = ecorePackage.getAllEClassifiers();

for (int i = 0; i < ecoreClassifiers.length; i++) {
  EClassifier ec = ecoreClassifiers[i];
  String eclassConst = null;
  if (ec instanceof EClass) {
    eclasses.add((EClass)ec);
  }
  if (ec instanceof EEnum) {
    enums.add((Enum)ec);
  }
  classifierIdMap.put(ec.getName(), i);
}

List<EClassifier> modelClassifiers = new ArrayList...
modelClassifiers.addAll(eclasses);
modelClassifiers.addAll(enums);
return modelClassifiers;

Regards,
Mark
Comment 9 Martin Taal CLA 2010-09-16 16:02:32 EDT
Hi Mark,
I am not sure, this is the piece of template which creates the content of the ModelPackage:

	«FOREACH this.EDataTypeModelGenAnnotations AS eClassifierAnnotation-»
	public static final int «toUpperCase(eClassifierAnnotation.name)»_CLASSIFIER_ID = «eClassifierAnnotation.EClassifier.classifierID»;
	«ENDFOREACH»
	«FOREACH this.EClassModelGenAnnotations AS eClassAnnotation-»
	public static final int «toUpperCase(eClassAnnotation.name)»_CLASSIFIER_ID = «eClassAnnotation.EClass.classifierID»;

so afaics, the classifier id in the generated code is exactly the same as the classifierid created/used by EMF.

Can you try the following in some testcode:
for (EClassifier eClassifier : ePackage.getEClassifiers()) {
System.err.println(eClassifier.getName() + " --> " eClassifier.getClassifierID());
}
where ePackage is your ePackage.

Can you attach the generated ModelPackage java file to this bugzilla?

gr. Martin
Comment 10 Mark Hoffmann CLA 2010-09-16 17:23:13 EDT
Created attachment 179074 [details]
My ecore
Comment 11 Mark Hoffmann CLA 2010-09-16 17:25:17 EDT
Created attachment 179075 [details]
My ModelPackage
Comment 12 Mark Hoffmann CLA 2010-09-16 17:34:50 EDT
(In reply to comment #9)

> so afaics, the classifier id in the generated code is exactly the same as the
> classifierid created/used by EMF.
Its seems to be like that

> 
> Can you try the following in some testcode:
> for (EClassifier eClassifier : ePackage.getEClassifiers()) {
> System.err.println(eClassifier.getName() + " --> "
> eClassifier.getClassifierID());
> }
> where ePackage is your ePackage.
Here is the result:
Person --> 0
Address --> 1
GeoLocation --> 2
AddressList --> 3
PersonList --> 4
Contact --> 5
ContactList --> 6
TitleType --> 7
GenderType --> 8
ContactType --> 9
ContactContextType --> 10
MaritalStatusType --> 11

My currently working configuration is:
Person --> 0
Address --> 3
GeoLocation --> 4
AddressList --> 5
PersonList --> 6
Contact --> 7
ContactList --> 10
TitleType --> 1
GenderType --> 2
ContactType --> 8
ContactContextType --> 9
MaritalStatusType --> 11

Regards,
Mark
Comment 13 Martin Taal CLA 2010-09-17 00:40:22 EDT
Hi Mark,
A quick scan of the ModelPackage shows no collision in classifier ids, or am I maybe overlooking something?
Does this ModelPackage work correctly?

gr. Martin
Comment 14 Mark Hoffmann CLA 2010-09-17 07:10:02 EDT
(In reply to comment #13)
> Hi Mark,
> A quick scan of the ModelPackage shows no collision in classifier ids, or am I
> maybe overlooking something?
> Does this ModelPackage work correctly?
> 
> gr. Martin

Hi Martin,

the CLASSIFIER_ID constants are used as index to access the classifiers list in the epackage of the model package.
The problem is the sort order doesn't match to the generated classifier id's anymore. 
The sort order in the epackage.getEClassifier list is:

eClassifier --> index
Person --> 0
Address --> 1
GeoLocation --> 2
AddressList --> 3
PersonList --> 4
Contact --> 5
ContactList --> 6
TitleType --> 7
GenderType --> 8
ContactType --> 9
ContactContextType --> 10
MaritalStatusType --> 11

But the CLASSIFIER_ID's have another sort order.
If you would load parse the XML of the ecore you wouldn't get this order:

Person --> 0 ModelPackage.getEClassifier(PERSON_CLASS_ID) matches Person
TitleType --> 1 ModelPackage.getEClassifier(TITLETYPE_CLASS_ID) matches Address
GenderType --> 2 ModelPackage.getEClassifier(GENDERTYPE_CLASS_ID) matches GeoLocation

and so on. 

This is the order the CLASSIFIER_ID in the model package are generated from. This mismatch causes the error. There are no double ID's.

The classifier id reflect the order od the eClassifier tags from the ecore-file.
The eClassifiers in the ePAckage.getEClassifier are ordered: first classes then enums.

I have to take a deeper look into it.

Regards,
Mark
Comment 15 Mark Hoffmann CLA 2010-09-17 07:12:09 EDT
(In reply to comment #13)
> Hi Mark,
> A quick scan of the ModelPackage shows no collision in classifier ids, or am I
> maybe overlooking something?
> Does this ModelPackage work correctly?

At me, the attached ModelPackage doesn't work. 
I changed the CLASSIFIER_ID's by hand, after getting the right order from the eClassifier list with debugging.

Mark
Comment 16 Martin Taal CLA 2010-09-17 07:37:57 EDT
Okay, I finally understand what you mean... 

Can you generate once more an incorrect ModelPackage and then zip up the whole generated javapackage (with the sources) and attach it to this bugzilla?

The ecore model attached now, is that the one used to generate the source code, or is the one copied into the source tree? I would need both.

gr. Martin
Comment 17 Martin Taal CLA 2010-09-17 11:10:53 EDT
Maybe it is this: in the annotations model in the epackage annotation there is an attribute ecorefilecontent. This contains the ecore model which is written out to the ecore file in the generated source package. As it is already set it is not overwritten in subsequent generation actions. This means that you have an old model there. The sources are however generated on the basis of the ecore file on which you do right-click.

In the latest build of Texo this attribute is not serialized anymore.

Can you try to remove this attribute and regenerate the sources? 

My feeling is that this is the issue...

gr. Martin
Comment 18 Mark Hoffmann CLA 2010-09-20 08:42:16 EDT
Hi Martin,

I can make the problem reproducable. If you have just an ecore a

1. I created an empty EMF project
2. Create an ecore as an mix of classes and enums in the order like this:
- class AClass
- enum AEnum 
- class BClass
- enum BEnum
3. Add Texo nature to this project
4. Create the texo model code without an annotationsmodel
5. Test creating the model package: Everything works here now. No error here

6. Create a genmodel from the ecore
7. I just modified the base package attribute in the genmodel
8. Create the model code
9. Add the texo dependency to the plugin again
10. Delete the old model code
11. Generate the model code again
12. Test creating the model code fails now.

I tested this with the latest texo 0.1.0-201009161717.
In my opinion the problem has something to do with the extension:
   <extension
         point="org.eclipse.emf.ecore.generated_package">
      <package
            class="emf.test.TestPackage"
            genModel="model/test.genmodel"
            uri="http://test">
      </package>
   </extension>
And the model generation in texo.

Before I created the genmodel, everything was fine, but this package wasn't registered. After generating the model code the extension was added and texo generates wrong classifier id's in the model package.

I attached my sample project as zip.

Regards, 
Mark
Comment 19 Mark Hoffmann CLA 2010-09-20 08:43:35 EDT
Created attachment 179240 [details]
Sample plugin that demonstrates the problem
Comment 20 Mark Hoffmann CLA 2010-09-20 12:00:37 EDT
The Problem lies in the org.eclipse.emf.texo.utils.ModelUtils#readEPackagesFromFile

If the package is already registered, nothing will be done in this method. Thats the case, if you have the package registered via org.eclipse.emf.ecore.generated_package-extension. If you get the ePackage now from ModelPackage#getEPackage the field ePackage is null and the method gets the ePackage via ModelUtils#getEPackage(getNsURI()).

The eClassifier field has after this example the sort order:
EClass AClass
EClass BClass
EClass BEnum (my mistake, i defined BEnum as ECLass and not as ENum)
EENum AEnum

Now delete the plugin.xml and with it the extension generated_package!.
What happens now, is the ModelUtils#readEPackagesFromFile reads the ecore file and gets an package from it, which will be registered with the corresponding registry. The eClassifier field here has a different sort order:
EClass AClass
EENum AEnum
EClass BClass
EClass BEnum (my mistake, i defined BEnum as ECLass and not as ENum)

I hope this information helps.

Regards,
Mark
Comment 21 Martin Taal CLA 2010-09-21 16:33:34 EDT
Hi Mark,
Okay clear so this happens when you have both EMF generated code and the plugin.xml and then also generate Texo code. 

I need to think of a solution for this. Texo will always check the package registry for the epackage, it is kind of difficult to do this differently as Texo should not read an epackage if it is already present in the registry.

I am keeping this bugzilla open for now.

Thanks for your detailed analysis!

gr. Martin
Comment 22 Mark Hoffmann CLA 2011-04-28 07:54:35 EDT
Hi Martin,

thought about this problem. Maybe I am wrong but there are two use cases generate the model code:
1. you have just an ecore and no generated EMF code from the genmodel
2. you have ecore and genmodel and the package that is registered in the plugin xml

For case 1 there are no problems. But, for case two, the model code has to be based on the registered packages.

I just looked in the org.eclipse.emf.texo.eclipse.popup.actions.GenerateCode class. In line 49 GeneratorUtils#readEPackages((final List<java.net.URI> uris, EPackage.Registry registry) will be called, that delegates to GeneratorUtils#readEPackagesUsingEMFURI(final List<URI> uris, EPackage.Registry registry).

If I understand the code right, the ecore file is loaded and the packages are registered. Maybe a solution is, to look in the ePackage registry first, to check, if there is an already existing package. 

I created an patch, to show what I mean. But I never tested the patch because, I couldn't get a build from the sources.

Regards, Mark
Comment 23 Mark Hoffmann CLA 2011-04-28 07:55:52 EDT
Created attachment 194252 [details]
Patch for GeneratorUtils (never tested!!!!)
Comment 24 Mark Hoffmann CLA 2011-04-28 08:10:02 EDT
Created attachment 194255 [details]
Better Patch for GeneratorUtils (never tested!!!!)

Please ignore patch on attachment 194252 [details].
Comment 25 Martin Taal CLA 2011-04-28 18:35:18 EDT
Hi Mark,
Thanks for the patch, I made some changes in a different way which should also solve this. Can you try the latest build of Texo?

gr. Martin
Comment 26 Mark Hoffmann CLA 2011-04-30 07:33:59 EDT
Hi Martin,

a first quick test with version 0.1.0.v201104282119 didn't succeed.
I will check it.

Regards,
Mark
Comment 27 Mark Hoffmann CLA 2011-04-30 07:45:58 EDT
Hi again,

the sample plugin, from the bug attachment, doen't work too.

Ragards,
Mark
Comment 28 Martin Taal CLA 2011-08-26 07:13:06 EDT
Okay I made a new solution, the eclassifiers are now sorted before generating the modelcode, the sorting is the same as in the genmodel generated code. Closing the issue, please re-open if it is still not solved...
Comment 29 Scott Dybiec CLA 2017-07-02 18:37:34 EDT
I just ran into this same problem Mark ran into --- ClassCastException --- using Texo version org.eclipse.emf.texo_0.9.0.v201611141242:

Caused by: java.lang.ClassCastException: org.eclipse.emf.ecore.impl.EDataTypeImpl cannot be cast to org.eclipse.emf.ecore.EEnum
	at com.humanfactor.rw.model.entity.factory.RegattaModelPackage.getCapturedResultsVersionEEnum(RegattaModelPackage.java:14092)
	at com.humanfactor.rw.model.entity.factory.RegattaModelPackage.initialize(RegattaModelPackage.java:6191)
	at com.humanfactor.rw.model.entity.factory.RegattaModelPackage.<clinit>(RegattaModelPackage.java:5971)
	... 2 more

Like Mark, I found that the feature IDs in the Texo-generated ModelPackage were out of sync with the EMF-generated EPackage. I traced the cause down to the fact that Texo generates the ModelPackage feature IDs from the .ecore file, while EMF generates them using its .genmodel file. When the ordering of the EClasses, EEnums and EDataTypes differ between these two, the integer assignments in the ModelPackage and EPackage are out of sync. 

The genmodel auto-sorts the EClasses and features from the .ecore file into groups (EClasses, EDataTypes, EEnums, etc). In my case the .ecore file was interspersed randomly with EClasses, EDataTypes and EEnums and EMF sorted them nicely in the genmodel file. The ordering of the elements determines how the integer IDs are assigned.

My workaround is to manually sort/order the .ecore file to match the genmodel. When I do this, The Texo-generate ModelPackage assigns the IDs just as EMF does and the ClassCastException disappears. 

Martin, in your previous fix you apparently solved the EClass, EEnum sorting problem that Mark found, but not EDataType sorting. Perhaps there are other feature types that need to to be sorted too, but I don't use them. Another approach would be to read the .genmodel file and use its ordering instead of the .ecore file. That would be resilient to changes in how EMF decides to sore the genmodel file in the future.