Search code examples
javavalidationxtextxtend

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


I have encountered some code from another developer who tries to validate an object FooBar against other objects BooFar, and the code does something like this:

// 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)
    ]
    // ...
  }
  // ...
}

So, this validator tries to access the "classpath" and loads all exported BOOFAR objects to do the validation.

Now my question is: Is this even allowed?

It is obviously not good, because

  1. I guess the resourceSetProvider creates a new ResourceSet for each BOOFAR EObjectDescription
  2. For each EObjectDescription, a Resource is loaded and parsed to resolve the EObject

I know (at least I think I know) that the more (most?) optimal way to cross-validate is to include all information needed for the validation in the EObjectDescription of the BooFar object and thus, not to resolve the object but validate against the EObjectDescription.

My question is: Is the above allowed and does the code have any disadvantages other than being slow?

Also - Bonus Question - I have also seen code which resolves against the resourceSet of the validated resource. So in the example code above replace the line in question with

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

Is this allowed? My thoughts are that this could cause problems because this code interferes with the XtextBuilder's ResourceSet and if we use a ParallelResourceLoader then it might even cause race conditions?

So to summarize: I would like to know if the two variants above are only bad or even forbidden.


Solution

  • Other than being slow, the code is fine (in theory). Though it always depends on what is going to happen with the objects in allObjects. Let's say two exported objects come from the same resource, the list will contain two objects from two different resources and operations like equality checks or comparisons become unnecessarily hard.

    Doing the same operation in the context of the own resource set is usually fine. The builder will load in parallel before the validation is triggered. Nevertheless - depending on your project structure - loading all objects may exceed the memory limit of the JVM. Usually the XtextBuilder tries to free memory if things are getting close the Xmx. If a validation loads all resources, this mechanism cannot kick in.

    Long story short: Making the validation based on the IEObjectDescriptions is certainly the recommended way. The variant with the own resource set per objects is very bad. The second variant is only bad. Both are allowed but discouraged.