[514561] NPE When building XCore models with circular dependencies
diff --git a/plugins/org.eclipse.emf.codegen.ecore.xtext/src/org/eclipse/emf/codegen/ecore/xtext/GenModelQualifiedNameProvider.java b/plugins/org.eclipse.emf.codegen.ecore.xtext/src/org/eclipse/emf/codegen/ecore/xtext/GenModelQualifiedNameProvider.java
index e9621fe..ecaf34d 100644
--- a/plugins/org.eclipse.emf.codegen.ecore.xtext/src/org/eclipse/emf/codegen/ecore/xtext/GenModelQualifiedNameProvider.java
+++ b/plugins/org.eclipse.emf.codegen.ecore.xtext/src/org/eclipse/emf/codegen/ecore/xtext/GenModelQualifiedNameProvider.java
@@ -31,7 +31,7 @@
     if (eObject instanceof GenPackage)
     {
       String packageName = ((GenPackage)eObject).getQualifiedPackageName();
-      if (packageName != null)
+      if (packageName != null && packageName.length() != 0)
       {
         return qualifiedNameConverter.toQualifiedName(packageName);
       }
@@ -44,7 +44,7 @@
       {
         String packageName = genPackage.getQualifiedPackageName();
         String classifierName = classifier.getName();
-        if (packageName != null && classifierName != null)
+        if (packageName != null && packageName.length() != 0 && classifierName != null)
         {
           return qualifiedNameConverter.toQualifiedName(packageName).append(classifierName);
         }
diff --git a/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/generator/AbstractGeneratorAdapter.java b/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/generator/AbstractGeneratorAdapter.java
index 21690c3..39ed3a1 100644
--- a/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/generator/AbstractGeneratorAdapter.java
+++ b/plugins/org.eclipse.emf.codegen.ecore/src/org/eclipse/emf/codegen/ecore/generator/AbstractGeneratorAdapter.java
@@ -41,6 +41,7 @@
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IPath;
 import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.OperationCanceledException;
 import org.eclipse.core.runtime.Path;
 import org.eclipse.core.runtime.Platform;
 import org.eclipse.jdt.core.IBuffer;
@@ -377,7 +378,10 @@
    */
   protected Diagnostic toDiagnostic(Exception exception, String currentMessage)
   {
-    CodeGenEcorePlugin.INSTANCE.log(exception);
+    if (!(exception instanceof OperationCanceledException))
+    {
+      CodeGenEcorePlugin.INSTANCE.log(exception);
+    }
 
     currentMessage = currentMessage != null ?
       CodeGenEcorePlugin.INSTANCE.getString("_UI_GenerateException_diagnostic", new Object[] { currentMessage }) :
diff --git a/plugins/org.eclipse.emf.ecore.xcore.ui/src/org/eclipse/emf/ecore/xcore/ui/container/XcoreJavaProjectsState.java b/plugins/org.eclipse.emf.ecore.xcore.ui/src/org/eclipse/emf/ecore/xcore/ui/container/XcoreJavaProjectsState.java
index 476bc72..bf471fd 100644
--- a/plugins/org.eclipse.emf.ecore.xcore.ui/src/org/eclipse/emf/ecore/xcore/ui/container/XcoreJavaProjectsState.java
+++ b/plugins/org.eclipse.emf.ecore.xcore.ui/src/org/eclipse/emf/ecore/xcore/ui/container/XcoreJavaProjectsState.java
@@ -78,7 +78,8 @@
             // Unless there is such an entry on the list of visible containers, the resource description for this URI will not be used.
             // https://bugs.eclipse.org/bugs/show_bug.cgi?id=500822
             //
-            Map<URI, IStorage> allEntries = jdtExtensions.getAllEntries((IPackageFragmentRoot)visibleHandleElement);
+            IPackageFragmentRoot packageFragmentRoot = (IPackageFragmentRoot)visibleHandleElement;
+            Map<URI, IStorage> allEntries = jdtExtensions.getAllEntries(packageFragmentRoot);
             for (URI uri : allEntries.keySet())
             {
               if ("xcore".equals(uri.fileExtension()) && uri.isPlatformResource())
@@ -91,6 +92,16 @@
                 continue LOOP;
               }
             }
+
+            IJavaProject javaProject = packageFragmentRoot.getJavaProject();
+            if (javaProject != null)
+            {
+              String projectHandle = javaProject.getHandleIdentifier();
+              if (!result.contains(projectHandle))
+              {
+                i.add(projectHandle);
+              }
+            }
           }
         }
 
diff --git a/plugins/org.eclipse.emf.ecore.xcore/src/org/eclipse/emf/ecore/xcore/resource/XcoreModelAssociator.java b/plugins/org.eclipse.emf.ecore.xcore/src/org/eclipse/emf/ecore/xcore/resource/XcoreModelAssociator.java
index fbcacd6..954db31 100644
--- a/plugins/org.eclipse.emf.ecore.xcore/src/org/eclipse/emf/ecore/xcore/resource/XcoreModelAssociator.java
+++ b/plugins/org.eclipse.emf.ecore.xcore/src/org/eclipse/emf/ecore/xcore/resource/XcoreModelAssociator.java
@@ -173,7 +173,6 @@
           @Override
           public void process(Resource state) throws Exception
           {
-            xcoreEcoreBuilder.linkInstanceTypes();
             jvmInferrer.inferDeepStructure(genModel);
           }
         });
diff --git a/plugins/org.eclipse.emf.ecore.xcore/src/org/eclipse/emf/ecore/xcore/util/XcoreEcoreBuilder.java b/plugins/org.eclipse.emf.ecore.xcore/src/org/eclipse/emf/ecore/xcore/util/XcoreEcoreBuilder.java
index db085a4..84fb41c 100644
--- a/plugins/org.eclipse.emf.ecore.xcore/src/org/eclipse/emf/ecore/xcore/util/XcoreEcoreBuilder.java
+++ b/plugins/org.eclipse.emf.ecore.xcore/src/org/eclipse/emf/ecore/xcore/util/XcoreEcoreBuilder.java
@@ -9,6 +9,7 @@
 
 
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.regex.Pattern;
@@ -38,7 +39,11 @@
 import org.eclipse.emf.ecore.ETypedElement;
 import org.eclipse.emf.ecore.EcoreFactory;
 import org.eclipse.emf.ecore.EcorePackage;
-import org.eclipse.emf.ecore.impl.EClassifierImpl;
+import org.eclipse.emf.ecore.impl.EAnnotationImpl;
+import org.eclipse.emf.ecore.impl.EClassImpl;
+import org.eclipse.emf.ecore.impl.EDataTypeImpl;
+import org.eclipse.emf.ecore.impl.EGenericTypeImpl;
+import org.eclipse.emf.ecore.impl.EReferenceImpl;
 import org.eclipse.emf.ecore.util.EcoreUtil;
 import org.eclipse.emf.ecore.util.EcoreValidator;
 import org.eclipse.emf.ecore.util.ExtendedMetaData;
@@ -61,7 +66,6 @@
 import org.eclipse.emf.ecore.xcore.XTypeParameter;
 import org.eclipse.emf.ecore.xcore.XTypedElement;
 import org.eclipse.emf.ecore.xcore.XcorePackage;
-import org.eclipse.emf.ecore.xcore.XcorePlugin;
 import org.eclipse.emf.ecore.xcore.interpreter.IClassLoaderProvider;
 import org.eclipse.emf.ecore.xcore.interpreter.XcoreConversionDelegate;
 import org.eclipse.emf.ecore.xcore.interpreter.XcoreInterpreter;
@@ -105,9 +109,7 @@
   @Inject
   private XcoreGrammarAccess xcoreGrammarAccess;
 
-  protected List<Runnable> runnables = new ArrayList<Runnable>();
-
-  protected List<Runnable> instanceTypeRunnables = new ArrayList<Runnable>();
+  protected final List<DeferredInitializer> deferredInitializers = new ArrayList<DeferredInitializer>();
 
   protected XcoreInterpreter interpreter;
 
@@ -115,49 +117,17 @@
 
   public void link()
   {
-    // Hook up local references.
-    //
-    List<Runnable> currentRunnables = new ArrayList<Runnable>(runnables);
-    runnables.clear();
-    for (Runnable runnable : currentRunnables)
+    for (DeferredInitializer deferredInitializer : deferredInitializers)
     {
-      try
-      {
-        runnable.run();
-      }
-      catch (Throwable throwable)
-      {
-        XcorePlugin.INSTANCE.log(throwable);
-      }
+      deferredInitializer.setNeedsInitialization(true);
     }
-    for (Runnable runnable : runnables)
-    {
-      try
-      {
-        runnable.run();
-      }
-      catch (Throwable throwable)
-      {
-        XcorePlugin.INSTANCE.log(throwable);
-      }
-    }
-  }
 
-  public void linkInstanceTypes()
-  {
-    // Hook up instance types.
-    //
-    for (Runnable runnable : instanceTypeRunnables)
+    for (DeferredInitializer deferredInitializer : deferredInitializers)
     {
-      try
-      {
-        runnable.run();
-      }
-      catch (Throwable throwable)
-      {
-        XcorePlugin.INSTANCE.log(throwable);
-      }
+      deferredInitializer.initialize();
     }
+
+    deferredInitializers.clear();
   }
 
   public static void setQualifiedPackageName(EPackage ePackage, String name)
@@ -286,32 +256,19 @@
         }
       }
     }
-    handleAnnotations(xModelElement, eModelElement, true);
-    runnables.add
-      (new Runnable()
-       {
-         public void run()
-         {
-           handleAnnotations(xModelElement, eModelElement, false);
-         }
-       });
-  }
 
-  protected void handleAnnotations(final XModelElement xModelElement, final EModelElement eModelElement, boolean preIndexing)
-  {
+    Map<String, DeferredEAnnotationImpl> specialAnnotations = new HashMap<String, XcoreEcoreBuilder.DeferredEAnnotationImpl>();
     EList<EAnnotation> eAnnotations = eModelElement.getEAnnotations();
     for (XAnnotation xAnnotation : xModelElement.getAnnotations())
     {
       //      map(eAnnotation, xAnnotation);
       String sourceURI = null;
 
-      if (preIndexing)
-      {
         List<INode> nodes = NodeModelUtils.findNodesForFeature(xAnnotation, XcorePackage.Literals.XANNOTATION__SOURCE);
         StringBuilder annotationLiteral = new StringBuilder();
-        for (INode node : nodes)
+        for (INode sourceNode : nodes)
         {
-          annotationLiteral.append(NodeModelUtils.getTokenText(node));
+          annotationLiteral.append(NodeModelUtils.getTokenText(sourceNode));
         }
         int index = annotationLiteral.lastIndexOf(" ");
         if (index != -1)
@@ -336,54 +293,50 @@
         {
           sourceURI = ExtendedMetaData.ANNOTATION_URI;
         }
-      }
-      else
-      {
-        XAnnotationDirective source = xAnnotation.getSource();
-        if (source != null)
-        {
-          sourceURI = source.getSourceURI();
-        }
-      }
 
-      if (sourceURI != null)
-      {
         EClass eClass = EcorePackage.eNS_URI.equals(sourceURI) ? eModelElement.eClass() : null;
-   
-        EMap<String, String> details = xAnnotation.getDetails();
-        if (details.isEmpty())
+
+        DeferredEAnnotationImpl eAnnotation = specialAnnotations.get(sourceURI);
+        if (eAnnotation == null)
         {
-          EAnnotation eAnnotation = EcoreFactory.eINSTANCE.createEAnnotation();
-          eAnnotation.setSource(sourceURI);
-          eAnnotations.add(eAnnotation);
-        }
-        else
-        {
-          for (Map.Entry<String, String> detail : details)
+          eAnnotation = new DeferredEAnnotationImpl(xAnnotation);
+          if (sourceURI != null)
           {
-            String key = detail.getKey();
-            String value = detail.getValue();
-            if (eClass != null)
-            {
-              EStructuralFeature eStructuralFeature = eClass.getEStructuralFeature(key);
-              if (eStructuralFeature instanceof EAttribute)
-              {
-                // Be more careful about exceptions.
-                // TODO
-                //
-                EDataType eDataType = (EDataType)eStructuralFeature.getEType();
-                eModelElement.eSet(eStructuralFeature, EcoreUtil.createFromString(eDataType, value));
-                continue;
-              }
-            }
-            if (EcoreUtil.getAnnotation(eModelElement, sourceURI, key) == null)
-            {
-              EcoreUtil.setAnnotation(eModelElement, sourceURI, key, value);
-            }
+            specialAnnotations.put(sourceURI, eAnnotation);
           }
         }
+        eAnnotation.setSource(sourceURI);
+
+        EMap<String, String> details = eAnnotation.getDetails();
+        for (Map.Entry<String, String> detail : xAnnotation.getDetails())
+        {
+          String key = detail.getKey();
+          String value = detail.getValue();
+
+          if (eClass != null)
+          {
+            EStructuralFeature eStructuralFeature = eClass.getEStructuralFeature(key);
+            if (eStructuralFeature instanceof EAttribute)
+            {
+              // Be more careful about exceptions.
+              // TODO
+              //
+              EDataType eDataType = (EDataType)eStructuralFeature.getEType();
+              eModelElement.eSet(eStructuralFeature, EcoreUtil.createFromString(eDataType, value));
+              continue;
+            }
+          }
+
+          details.put(key,  value);
+        }
+
+        // Add it if it's not an Ecore annotation or if it is an Ecore annotation but isn't empty.
+        if (eClass == null || !eAnnotations.isEmpty())
+        {
+          eAnnotations.add(eAnnotation);
+          deferredInitializers.add(eAnnotation);
+        }
       }
-    }
   }
 
   protected EClassifier getEClassifier(final XClassifier xClassifier)
@@ -417,39 +370,17 @@
         eClassifier.setInstanceTypeName(instanceTypeLiteral.toString());
       }
 
-      instanceTypeRunnables.add
-        (new Runnable()
-         {
-           public void run()
-           {
-             JvmTypeReference instanceType = xClassifier.getInstanceType();
-             if (instanceType != null)
-             {
-               String instanceTypeName = instanceType.getIdentifier();
-               String normalizedInstanceTypeName = EcoreUtil.toJavaInstanceTypeName((EGenericType)EcoreValidator.EGenericTypeBuilder.INSTANCE.parseInstanceTypeName(instanceTypeName).getData().get(0));
-               eClassifier.setInstanceTypeName(normalizedInstanceTypeName);
-               if (classLoader != null && eClassifier instanceof EClassifierImpl)
-               {
-                 try
-                 {
-                   Class<?> instanceClass = classLoader.loadClass(eClassifier.getInstanceClassName());
-                   ((EClassifierImpl)eClassifier).setInstanceClassGen(instanceClass);
-                 }
-                 catch (Throwable throwable)
-                 {
-                   // Ignore.
-                 }
-               }
-             }
-           }
-         });
+      if (eClassifier instanceof DeferredInitializer)
+      {
+        deferredInitializers.add((DeferredInitializer)eClassifier);
+      }
     }
     return eClassifier;
   }
 
   protected EClass getEClass(final XClass xClass)
   {
-    final EClass eClass = EcoreFactory.eINSTANCE.createEClass();
+    final EClass eClass = new DeferredEClassImpl(xClass, classLoader);
     mapper.getMapping(xClass).setEClass(eClass);
     mapper.getToXcoreMapping(eClass).setXcoreElement(xClass);
     if (xClass.isInterface())
@@ -626,8 +557,7 @@
     }
     else
     {
-      final EGenericType eGenericType = EcoreFactory.eINSTANCE.createEGenericType();
-      //      map(eGenericType, xGenericType);
+      DeferredEGenericTypeImpl eGenericType = new DeferredEGenericTypeImpl(xGenericType);
       XGenericType lowerBound = xGenericType.getLowerBound();
       if (lowerBound != null)
       {
@@ -643,36 +573,14 @@
       {
         eTypeArguments.add(getEGenericType(typeArgument));
       }
-
-      runnables.add(new Runnable()
-        {
-          public void run()
-          {
-            GenBase type = xGenericType.getType();
-            if (type != null)
-            {
-              if (type instanceof GenTypeParameter)
-              {
-                eGenericType.setETypeParameter(((GenTypeParameter)type).getEcoreTypeParameter());
-              }
-              else if (type instanceof GenClassifier)
-              {
-                eGenericType.setEClassifier(((GenClassifier)type).getEcoreClassifier());
-              }
-              else
-              {
-                eGenericType.setEClassifier(eGenericType.getERawType());
-              }
-            }
-          }
-        });
+      deferredInitializers.add(eGenericType);
       return eGenericType;
     }
   }
 
   protected EReference getEReference(final XReference xReference)
   {
-    final EReference eReference = EcoreFactory.eINSTANCE.createEReference();
+    final DeferredEReferenceImpl eReference = new DeferredEReferenceImpl(xReference);
     mapper.getMapping(xReference).setEStructuralFeature(eReference);
     mapper.getToXcoreMapping(eReference).setXcoreElement(xReference);
     if (xReference.isContainment())
@@ -687,34 +595,8 @@
     {
       eReference.setResolveProxies(false);
     }
-
     handleEStructuralFeature(eReference, xReference);
-
-    runnables.add(new Runnable()
-      {
-        public void run()
-        {
-          GenFeature opposite = xReference.getOpposite();
-          if (opposite != null)
-          {
-            eReference.setEOpposite((EReference)opposite.getEcoreFeature());
-          }
-          runnables.add(new Runnable()
-            {
-              public void run()
-              {
-                for (GenFeature key : xReference.getKeys())
-                {
-                  EStructuralFeature eAttribute = key.getEcoreFeature();
-                  if (eAttribute instanceof EAttribute)
-                  {
-                    eReference.getEKeys().add((EAttribute)eAttribute);
-                  }
-                }
-              }});
-        }
-      });
-
+    deferredInitializers.add(eReference);
     return eReference;
   }
 
@@ -783,7 +665,7 @@
 
   protected EDataType getEDataType(XDataType xDataType)
   {
-    EDataType eDataType = EcoreFactory.eINSTANCE.createEDataType();
+    EDataType eDataType = new DeferredEDataTypeImpl(xDataType, classLoader);
     mapper.getMapping(xDataType).setEDataType(eDataType);
     mapper.getToXcoreMapping(eDataType).setXcoreElement(xDataType);
     EList<ETypeParameter> eTypeParameters = eDataType.getETypeParameters();
@@ -826,4 +708,411 @@
     eEnumLiteral.setValue(xEnumLiteral.getValue());
     return eEnumLiteral;
   }
-}
+
+  /**
+   * This was introduced to address the problems uncovered by https://bugs.eclipse.org/bugs/show_bug.cgi?id=514561.
+   */
+  public interface DeferredInitializer
+  {
+    void setNeedsInitialization(boolean needsInitialization);
+    void initialize();
+  }
+
+  private static final class DeferredEDataTypeImpl extends EDataTypeImpl implements DeferredInitializer
+  {
+    private final XClassifier xClassifier;
+
+    private final ClassLoader classLoader;
+
+    private boolean needsInitialization;
+
+    public DeferredEDataTypeImpl(XClassifier xClassifier, ClassLoader classLoader)
+    {
+      this.xClassifier = xClassifier;
+      this.classLoader = classLoader;
+    }
+
+    public void setNeedsInitialization(boolean needsInitialization)
+    {
+      this.needsInitialization = needsInitialization;
+    }
+
+    public void initialize()
+    {
+      if (needsInitialization)
+      {
+        needsInitialization = false;
+
+        JvmTypeReference instanceType = xClassifier.getInstanceType();
+        if (instanceType != null)
+        {
+          String instanceTypeName = instanceType.getIdentifier();
+          String normalizedInstanceTypeName = EcoreUtil.toJavaInstanceTypeName(
+            (EGenericType)EcoreValidator.EGenericTypeBuilder.INSTANCE.parseInstanceTypeName(instanceTypeName).getData().get(0));
+          setInstanceTypeName(normalizedInstanceTypeName);
+          if (classLoader != null)
+          {
+            try
+            {
+              Class<?> instanceClass = classLoader.loadClass(getInstanceClassName());
+              setInstanceClassGen(instanceClass);
+            }
+            catch (Throwable throwable)
+            {
+              // Ignore.
+            }
+          }
+        }
+      }
+    }
+
+    @Override
+    public boolean isSetInstanceClassName()
+    {
+      initialize();
+      return super.isSetInstanceClassName();
+    }
+
+    @Override
+    public String getInstanceClassName()
+    {
+      initialize();
+      return super.getInstanceClassName();
+    }
+
+    @Override
+    public boolean isSetInstanceTypeName()
+    {
+      initialize();
+      return super.isSetInstanceTypeName();
+    }
+
+    @Override
+    public String getInstanceTypeName()
+    {
+      initialize();
+      return super.getInstanceTypeName();
+    }
+
+    @Override
+    public Class<?> getInstanceClass()
+    {
+      initialize();
+      return super.getInstanceClass();
+    }
+  }
+
+  private static final class DeferredEClassImpl extends EClassImpl implements DeferredInitializer
+  {
+    private final XClassifier xClassifier;
+
+    protected boolean needsInitialization;
+
+    private ClassLoader classLoader;
+
+    public DeferredEClassImpl(XClassifier xClassifier, ClassLoader classLoader)
+    {
+      this.xClassifier = xClassifier;
+      this.classLoader = classLoader;
+    }
+
+    public void setNeedsInitialization(boolean needsInitialization)
+    {
+      this.needsInitialization = needsInitialization;
+    }
+
+    public void initialize()
+    {
+      if (needsInitialization)
+      {
+        needsInitialization = false;
+
+        JvmTypeReference instanceType = xClassifier.getInstanceType();
+        if (instanceType != null)
+        {
+          String instanceTypeName = instanceType.getIdentifier();
+          String normalizedInstanceTypeName = EcoreUtil.toJavaInstanceTypeName(
+            (EGenericType)EcoreValidator.EGenericTypeBuilder.INSTANCE.parseInstanceTypeName(instanceTypeName).getData().get(0));
+          setInstanceTypeName(normalizedInstanceTypeName);
+          if (classLoader != null)
+          {
+            try
+            {
+              Class<?> instanceClass = classLoader.loadClass(getInstanceClassName());
+              setInstanceClassGen(instanceClass);
+            }
+            catch (Throwable throwable)
+            {
+              // Ignore.
+            }
+          }
+        }
+      }
+    }
+
+    @Override
+    public boolean isSetInstanceClassName()
+    {
+      initialize();
+      return super.isSetInstanceClassName();
+    }
+
+    @Override
+    public String getInstanceClassName()
+    {
+      initialize();
+      return super.getInstanceClassName();
+    }
+
+    @Override
+    public boolean isSetInstanceTypeName()
+    {
+      initialize();
+      return super.isSetInstanceTypeName();
+    }
+
+    @Override
+    public String getInstanceTypeName()
+    {
+      initialize();
+      return super.getInstanceTypeName();
+    }
+
+    @Override
+    public Class<?> getInstanceClass()
+    {
+      initialize();
+      return super.getInstanceClass();
+    }
+  }
+
+  private static class DeferredEReferenceImpl extends EReferenceImpl implements DeferredInitializer
+  {
+    private final XReference xReference;
+
+    private boolean needsInitialization;
+
+    public DeferredEReferenceImpl(XReference xReference)
+    {
+      this.xReference = xReference;
+    }
+
+    public void setNeedsInitialization(boolean needsInitialization)
+    {
+      this.needsInitialization = needsInitialization;
+    }
+
+    public void initialize()
+    {
+      if (needsInitialization)
+      {
+        needsInitialization = false;
+        GenFeature opposite = xReference.getOpposite();
+        if (opposite != null)
+        {
+          setEOpposite((EReference)opposite.getEcoreFeature());
+        }
+        for (GenFeature key : xReference.getKeys())
+        {
+          EStructuralFeature eAttribute = key.getEcoreFeature();
+          if (eAttribute instanceof EAttribute)
+          {
+            getEKeys().add((EAttribute)eAttribute);
+         }
+        }
+      }
+    }
+
+    @Override
+    public boolean eIsSet(int featureID)
+    {
+      switch (featureID)
+      {
+        case EcorePackage.EREFERENCE__EREFERENCE_TYPE:
+        case EcorePackage.EREFERENCE__EKEYS:
+          initialize();
+          break;
+      }
+
+      return super.eIsSet(featureID);
+    }
+
+    @Override
+    public EList<EAttribute> getEKeys()
+    {
+      initialize();
+      return super.getEKeys();
+    }
+
+    @Override
+    public EReference getEOpposite()
+    {
+      initialize();
+      return super.getEOpposite();
+    }
+
+    @Override
+    public EReference basicGetEOpposite()
+    {
+      initialize();
+      return super.basicGetEOpposite();
+    }
+  }
+
+  private static final class DeferredEGenericTypeImpl extends EGenericTypeImpl implements DeferredInitializer
+  {
+    private final XGenericType xGenericType;
+
+    private boolean needsInitialization;
+
+    private DeferredEGenericTypeImpl(XGenericType xGenericType)
+    {
+      this.xGenericType = xGenericType;
+    }
+
+    public void setNeedsInitialization(boolean needsInitialization)
+    {
+      this.needsInitialization = needsInitialization;
+    }
+
+    public void initialize()
+    {
+      if (needsInitialization)
+      {
+        GenBase type = xGenericType.getType();
+        // It's possible that we recursively reach this point again while resolving the type proxy.
+        // This does not cause stack overflow because it succeeds the next time, but there's no point in processing the type again if it's already been processed.
+        if (needsInitialization)
+        {
+          needsInitialization = false;
+          if (type != null)
+          {
+            if (type instanceof GenTypeParameter)
+            {
+              setETypeParameter(((GenTypeParameter)type).getEcoreTypeParameter());
+            }
+            else if (type instanceof GenClassifier)
+            {
+              setEClassifier(((GenClassifier)type).getEcoreClassifier());
+            }
+            else
+            {
+              setEClassifier(getERawType());
+            }
+          }
+        }
+      }
+    }
+
+    @Override
+    public EClassifier getERawType()
+    {
+      initialize();
+      return super.getERawType();
+    }
+
+    @Override
+    public EClassifier basicGetERawType()
+    {
+      initialize();
+      return super.basicGetERawType();
+    }
+
+    @Override
+    public EClassifier getEClassifier()
+    {
+      initialize();
+      return super.getEClassifier();
+    }
+
+    @Override
+    public EClassifier basicGetEClassifier()
+    {
+      initialize();
+      return super.basicGetEClassifier();
+    }
+
+    @Override
+    public ETypeParameter getETypeParameter()
+    {
+      initialize();
+      return super.getETypeParameter();
+    }
+
+    @Override
+    public boolean eIsSet(int featureID)
+    {
+      switch (featureID)
+      {
+        case EcorePackage.EGENERIC_TYPE__ERAW_TYPE:
+        case EcorePackage.EGENERIC_TYPE__ETYPE_PARAMETER:
+        case EcorePackage.EGENERIC_TYPE__ECLASSIFIER:
+          initialize();
+          break;
+      }
+
+      return super.eIsSet(featureID);
+    }
+
+    @Override
+    public String toString()
+    {
+      if (needsInitialization)
+      {
+        return "* needs initialization *";
+      }
+
+      return super.toString();
+    }
+  }
+
+  private static final class DeferredEAnnotationImpl extends EAnnotationImpl implements DeferredInitializer
+  {
+    private final XAnnotation xAnnotation;
+
+    private boolean needsInitialization;
+
+    private DeferredEAnnotationImpl(XAnnotation xAnnotation)
+    {
+      this.xAnnotation = xAnnotation;
+    }
+
+    public void setNeedsInitialization(boolean needsInitialization)
+    {
+      this.needsInitialization = needsInitialization;
+    }
+
+    public void initialize()
+    {
+      if (needsInitialization)
+      {
+        needsInitialization = false;
+        XAnnotationDirective source = xAnnotation.getSource();
+        if (source != null)
+        {
+         setSource(source.getSourceURI());
+        }
+      }
+    }
+
+    @Override
+    public boolean eIsSet(int featureID)
+    {
+      switch (featureID)
+      {
+        case EcorePackage.EANNOTATION__SOURCE:
+          initialize();
+          break;
+      }
+
+      return super.eIsSet(featureID);
+    }
+
+    @Override
+    public String getSource()
+    {
+      initialize();
+      return super.getSource();
+    }
+  }
+}
\ No newline at end of file