Skip to main content



      Home
Home » Modeling » EMF » [Xcore/2] circular dependencies
[Xcore/2] circular dependencies [message #1102266] Thu, 05 September 2013 11:24 Go to next message
Eclipse UserFriend
I know this topic has been discussed here earlier, but Xcore breathes a little bit of new life into it Wink
(After all, Xcore makes creating models productive enough to encounter this kind of stuff again.)

The problem is not really with Xcore, apart from the fact that Xcore doesn't flag the problem.
The actual problem lies with the way the <packageName>PackageImpl are generated: their init() implementations only register the package under the nsURI after full creation, which entails calling initializePackageContents() which may need package instances that haven't been registered at that point in time yet. There are no infinite loops, but the required packages variables may simply be null.

To fix this completely, I think it could be enough that all package instances are registered and their createPackageContents() called before initializePackageContents is called on any of them.
Re: [Xcore/2] circular dependencies [message #1102299 is a reply to message #1102266] Thu, 05 September 2013 12:03 Go to previous messageGo to next message
Eclipse UserFriend
Meinte,

I couldn't reproduce such a problem. I have A.xcore

@GenModel(testsDirectory="/abc.tests/src")
package a

import b.B

class A
{
refers B b
}

class C extends B
{
}

and B.xcore

package b

import a.A

class B extends A
{
refers A a
}

In the generated example I write this code:


APackage.eINSTANCE.eResource().save(System.err, null);
BPackage.eINSTANCE.eResource().save(System.err, null);


And it writes out the following, so all seems to be there.

<?xml version="1.0" encoding="UTF-8"?>
<ecore:EPackage xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" name="a"
nsURI="a" nsPrefix="a">
<eClassifiers xsi:type="ecore:EClass" name="A">
<eStructuralFeatures xsi:type="ecore:EReference" name="b"
eType="ecore:EClass b#//B"/>
</eClassifiers>
<eClassifiers xsi:type="ecore:EClass" name="C" eSuperTypes="b#//B"/>
</ecore:EPackage>
<?xml version="1.0" encoding="UTF-8"?>
<ecore:EPackage xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" name="b"
nsURI="b" nsPrefix="b">
<eClassifiers xsi:type="ecore:EClass" name="B" eSuperTypes="a#//A">
<eStructuralFeatures xsi:type="ecore:EReference" name="a"
eType="ecore:EClass a#//A"/>
</eClassifiers>
</ecore:EPackage>

Of course such mutually dependent models need to be hosted in the same
bundle, otherwise the bundles would need to be mutually dependent, which
isn't allowed.

Are you using the Kepler version of Xcore? Is there some scenario I
missed in my example?



On 05/09/2013 5:24 PM, Meinte Boersma wrote:
> I know this topic has been discussed here earlier, but Xcore breathes
> a little bit of new life into it ;)
> (After all, Xcore makes creating models productive enough to encounter
> this kind of stuff again.)
>
> The problem is not really with Xcore, apart from the fact that Xcore
> doesn't flag the problem.
> The actual problem lies with the way the <packageName>PackageImpl are
> generated: their init() implementations only register the package
> under the nsURI after full creation, which entails calling
> initializePackageContents() which may need package instances that
> haven't been registered at that point in time yet. There are no
> infinite loops, but the required packages variables may simply be null.
>
> To fix this completely, I think it could be enough that all package
> instances are registered and their createPackageContents() called
> before initializePackageContents is called on any of them.
>
Re: [Xcore/2] circular dependencies [message #1102353 is a reply to message #1102299] Thu, 05 September 2013 13:22 Go to previous messageGo to next message
Eclipse UserFriend
My code is:
package a
import b.B
class A { contains B b }

package b
import c.C
class B { contains C c }

package c
import a.A
class C { refers A a }

Evaluation of any of the expressions <x>Package.eINSTANCE with x=A, B, or C (see the CircularDependencyTester main class) leads to a NPE.

Could you have a try with this?

Edit1:
(The Eclipse project is attached.)

Edit2:
I'm running on 4.2.2, so that's still Juno. I'll try it after upgrading to 4.3 as well.

Edit3:
Same result on Kepler 4.3.0. I was already running on EMF 2.9.1 (part of latest Xtend release).

[Updated on: Thu, 05 September 2013 13:48] by Moderator

Re: [Xcore/2] circular dependencies [message #1102386 is a reply to message #1102353] Thu, 05 September 2013 14:09 Go to previous messageGo to next message
Eclipse UserFriend
Meinte,

The package initialization code is quite different from that for my
example.

public static BPackage init()
{
if (isInited) return
(BPackage)EPackage.Registry.INSTANCE.getEPackage(BPackage.eNS_URI);

// Obtain or create and register package
BPackageImpl theBPackage =
(BPackageImpl)(EPackage.Registry.INSTANCE.get(eNS_URI) instanceof
BPackageImpl ? EPackage.Registry.INSTANCE.get(eNS_URI) : new
BPackageImpl());

isInited = true;

// Obtain or create and register interdependencies *** This isn't
present in your example &&&
APackageImpl theAPackage =
(APackageImpl)(EPackage.Registry.INSTANCE.getEPackage(APackage.eNS_URI)
instanceof APackageImpl ?
EPackage.Registry.INSTANCE.getEPackage(APackage.eNS_URI) :
APackage.eINSTANCE);


I think it's not recognizing them as co-dependant because it's three-way
circular. Please open a bugzilla and I'll have a closer look at what
needs to be fixed; it should generate code more like the above. (Your
suggestion of registering an incompletely initialized package sounds
like a bad idea; who knows who will gain access to that instance and
suffer failures as a result...


On 05/09/2013 7:22 PM, Meinte Boersma wrote:
> My code is:
>
> package a
> import b.B
> class A { contains B b }
>
> package b
> import c.C
> class B { contains C c }
>
> package c
> import a.A
> class C { refers A a }
>
> Evaluation of any of the expressions <x>Package.eINSTANCE with x=A, B, or C leads to a NPE.
>
> Could you have a try with this? (The Eclipse project is attached.)
Re: [Xcore/2] circular dependencies [message #1102405 is a reply to message #1102386] Thu, 05 September 2013 14:32 Go to previous messageGo to next message
Eclipse UserFriend
Done: https://bugs.eclipse.org/bugs/show_bug.cgi?id=416656

You're right: registering unfinished product is probably a recipe for disaster Wink Maybe one could use a "local registry" during construction?
Re: [Xcore/2] circular dependencies [message #1102422 is a reply to message #1102405] Thu, 05 September 2013 14:51 Go to previous messageGo to next message
Eclipse UserFriend
Meinte,

I think they just need to be recognized as "InterDependencies" so that
this part is generated:

<%if (!genPackage.getPackageInterDependencies().isEmpty()) {%>
// Obtain or create and register interdependencies
<%for (GenPackage interdep :
genPackage.getPackageInterDependencies()) {%>
<%=interdep.getImportedPackageClassName()%>
<%=genPackage.getPackageInstanceVariable(interdep)%> =
(<%=interdep.getImportedPackageClassName()%>)(<%=genModel.getImportedName("org.eclipse.emf.ecore.EPackage")%>.Registry.INSTANCE.getEPackage(<%=interdep.getImportedPackageInterfaceName()%>.eNS_URI)
instanceof <%=interdep.getImportedPackageClassName()%> ?
<%=genModel.getImportedName("org.eclipse.emf.ecore.EPackage")%>.Registry.INSTANCE.getEPackage(<%=interdep.getImportedPackageInterfaceName()%>.eNS_URI)
: <%=interdep.getImportedPackageInterfaceName()%>.eINSTANCE);
<%}%>

<%}%

That's the case for my simpler example but not for the one you
provided. I'll have a close look and see what's needed...


On 05/09/2013 8:32 PM, Meinte Boersma wrote:
> Done: https://bugs.eclipse.org/bugs/show_bug.cgi?id=416656
>
> You're right: registering unfinished product is probably a recipe for
> disaster ;) Maybe one could use a "local registry" during construction?
Re: [Xcore/2] circular dependencies [message #1103008 is a reply to message #1102422] Fri, 06 September 2013 05:38 Go to previous messageGo to next message
Eclipse UserFriend
Great, thanks! Smile

(And I hope the solution will indeed be as simple as triggering that emitter code.)
Re: [Xcore/2] circular dependencies [message #1741563 is a reply to message #1103008] Thu, 25 August 2016 16:37 Go to previous message
Eclipse UserFriend
Has this been fixed? I am running into this issue with cycle dependency in Xcore (I am using the Neon release):
I have the following packages:
package a
import b.B
class A {
   refers B b
}

package b
import a.A
import c.C
class B {
   refers A a
   refers C c
}

package c
import b.B
class C {
   refers B b
}

I get the following code generated when I clean the project that contains the three packages forcing code generation for the three packages.
public static APackage init() {
   ... 
   // Obtain or create and register interdependencies
   BPackageImpl theBPackage = ...

   // Create package meta-data objects
   theAPackage.createPackageContents();
   theBPackage.createPackageContents();

   // Initialize created meta-data
   theAPackage.initializePackageContents();
   theBPackage.initializePackageContents();
   ...
}

public static BPackage init() {
   ...
    // Obtain or create and register interdependencies
   APackageImpl theAPackage = ...
   CPackageImpl theCPackage = ...

   // Create package meta-data objects
   theBPackage.createPackageContents();
   theAPackage.createPackageContents();
   theCPackage.createPackageContents();

   // Initialize created meta-data
   theBPackage.initializePackageContents();
   theAPackage.initializePackageContents();
   theCPackage.initializePackageContents();
   ...
}

public static CPackage init() {
   ...
    // Obtain or create and register interdependencies
   BPackageImpl theBPackage = ...

   // Create package meta-data objects
   theCPackage.createPackageContents();
   theBPackage.createPackageContents();

   // Initialize created meta-data
   theCPackage.initializePackageContents();
   theBPackage.initializePackageContents();
   ...
}

However, if I then do a dummy change to package A and save it, I get package A looking like this (which is more correct):
public static APackage init() {
   ... 
   // Obtain or create and register interdependencies
   BPackageImpl theBPackage = ...
   CPackageImpl theCPackage = ...

   // Create package meta-data objects
   theAPackage.createPackageContents();
   theBPackage.createPackageContents();
   theCPackage.createPackageContents();

   // Initialize created meta-data
   theAPackage.initializePackageContents();
   theBPackage.initializePackageContents();
   theCPackage.initializePackageContents();
   ...
}

However, doing the same to package C does not result in a similar change. What is interesting is that switching the order of properties (a and c) in class B would switch the package that would generate correctly after a resave.

[Updated on: Fri, 26 August 2016 15:29] by Moderator

Previous Topic:Memory leak with EditingDomainActionBarContributor?
Next Topic:sorting the serialized objects in xml
Goto Forum:
  


Current Time: Fri Jul 11 23:31:54 EDT 2025

Powered by FUDForum. Page generated in 0.24969 seconds
.:: Contact :: Home ::.

Powered by: FUDforum 3.0.2.
Copyright ©2001-2010 FUDforum Bulletin Board Software

Back to the top