是否允许在 Xtext 验证器中访问另一个资源?

Is it allowed to access another Resource in an Xtext validator?

我遇到了另一位开发人员的一些代码,他们试图针对其他对象 BooFar 验证对象 FooBar,并且代码执行如下操作:

// Xtend code

@Inject IContainer.Manager containerManager
@Inject IResourceDescriptions resourceDescriptions
@Inject Provider<XtextResourceSet> resourceSetProvider

@Check
def validate(FooBar foobar) {
  var desc = resourceDescriptions.getResourceDescription(foobar.eResource.URI)
  var visibleContainers = containerManager.getVisibleContainers(desc, resourceDescriptions)

  for (visibleContainer : visibleContainers) {
    var exported = visibleContainer.getExportedObjectsByType(ModelPackage.Literals.BOOFAR)
    var allObjects = newArrayList

    exported.forEach [boofar |  
      // this is the line I'm interested about -->  
      allObjects.add(resourceSetProvider.get.getEObject(boofar.EObjectURI, true) as BooFar)
    ]
    // ...
  }
  // ...
}

因此,此验证器尝试访问“类路径”并加载所有导出的 BOOFAR 对象以进行验证。

现在我的问题是:这甚至被允许吗?

显然不好,因为

  1. 我猜 resourceSetProvider 为每个 BOOFAR EObjectDescription
  2. 创建了一个新的 ResourceSet
  3. 对于每个 EObjectDescription,加载并解析 Resource 以解析 EObject

我知道(至少我想我知道)交叉验证的更多(最多?)最佳方法是将验证所需的所有信息包含在 [=13= 的 EObjectDescription 中] 对象,因此,不是解析对象而是针对 EObjectDescription.

进行验证

我的问题是:以上是否允许,代码除了速度慢之外还有其他缺点吗?

另外 - 奖金问题 - 我还看到了针对已验证资源的 resourceSet 进行解析的代码。因此,在上面的示例代码中,将有问题的行替换为

  allObjects.add(EcoreUtil.resolve(boofar.EObjectOrProxy, foobar.eResource.resourceSet) as BooFar)

这是允许的吗?我的想法是这可能会导致问题,因为这段代码会干扰 XtextBuilderResourceSet,如果我们使用 ParallelResourceLoader 那么它甚至可能导致竞争条件?

所以总结一下:我想知道上面的两个变体是不好的还是被禁止的。

除了速度慢之外,代码还不错(理论上)。尽管它总是取决于 allObjects 中的对象将会发生什么。假设两个导出的对象来自同一个资源,列表将包含来自两个不同资源的两个对象,相等性检查或比较等操作变得不必要地困难。

在自己的资源集上下文中执行相同的操作通常没问题。构建器将在触发验证之前并行加载。尽管如此 - 根据您的项目结构 - 加载所有对象可能会超出 JVM 的内存限制。通常,如果事情接近 Xmx,XtextBuilder 会尝试释放内存。如果验证加载所有资源,则此机制无法启动。

长话短说:基于 IEObjectDescriptions 进行验证当然是推荐的方法。每个对象都有自己的资源集的变体非常糟糕。第二种变体只是不好的。两者都允许但不鼓励。