Skip to content

Theory of Operation

tbenbrahim edited this page Aug 7, 2017 · 3 revisions

The jsinterop-gen program converts WebIDL files into GWT Java jsinterop classes. WebIDL is the W3C standard for documenting all Web Standards and is fully document in the WebIDL specification.

Model Generation

The Interface Definition Language (IDL) files contain class and dictionary (similar to POJO) definitions, and callback definitions, among other things. The first task is to read those files and turn them into an in memory model. This is done in two passes by the ModelBuilder processor:

  • The first pass scans all of the IDL files to determine what types they contain and what package (folder) they belong to.
  • The second pass fully parses each file to extract all classes, attributes and other information, building an in-memory model as it goes along.

During the parsing phase, extension files are also read and added to the model. Extension files allow the classes defined IDL to be extended, either defining new classes (the Browser class that holds all of the global objects is defined this way), or partial classes, that augment existing classes with new @Overlay methods.

For information about the model that is built,see Model Description.

Glossary Note: The terms interface definition and dictionary definition are used in WebIDL. A WebIDL interface definition results in a Java class, with fields and methods, and sometimes a constructor. A dictionary definition results in a Java POJO, with only getters and setters, and a constructor. In JavaScript, a dictionary might look like {x: 1, y: 2}, while window, with its many fields and methods, would be defined by an interface definition.

Model Transformation

During the model transformation phase, the model is augmented with additional information such as the creation of overloaded methods for methods with optional arguments. Each model processor is defined in its own class and only has one very narrow task. This makes debugging much easier. As of this writing, the following processors run on the model:

  • NamedConstructorHandler: WebIDL has a concept of named constructors Normally a constructor does not have a name, since if there is a constructor (most classes do not have constructors), it is assumed to be the same as the class name. So if a constructor is named, it signifies that a new class should be defined that extends the original one and carries the named constructor. An example is HTMLImageElement, which defines a named constructor named Image in its IDL file. Although you cannot create instances of HTMLImageElement with new, because that class lacks a constructor, you can create an image element with new Image(). The job of this processor therefore is to look for named constructors in the model, and for each one it finds, add a new interface definition to the model, extending from the class where the named constructor was found.
  • PartialsMerger: WebIDL has a concept of partial definitions. For example, rather than describing the Navigator or Window class in one IDL files, the main features of a class are defined in the primary definition, and other features are defined in another file, using a partial definition, usually in another folder, dealing only with the new features to be added to the main definition. For example, there is a partial definition of Navigator that defines the geolocation field, another that adds the vibration API, among others. The job of this processor is find all of the partial definitions, and merge all the defined fields and methods into the main definition.
  • RedundantImplementsRemoval: This processor removes redundant implements definitions (described in the next bullet point). This happens when an implements definition exists on both the child and the parent class, in which case the one on the child class is redundant and is removed.
  • ImplementsMerger: WebIDL definitions can also be extended by implements definitions. The functionality is similar to partial definitions, but with a different implementation. A named interface is defined, then later, an implements definition declares that definition X implements definition Y. This is used most often when some functionality is implemented by two classes, for example Window and Worker. Rather than having two partial definitions, there is one interface definition, and later two one line implements definitions. The job of this processor is to merge the interfaces mentioned in the implements definition into the target definitions.
  • DuplicateInheritedDictionaryMemberRemover: It sometimes happen that a child class defines the same fields as its parent classes. When this is the case, the field from the child class is removed, as jsinterop does not allow method or field overriding in child classes.
  • DuplicateInheritedInterfaceMembersRemover': THis processor performs the same job as DuplicateInheritedDictionaryMemberRemover, but for interface definitions.
  • GenericTypesProcessor: TODO
  • MethodUnionArgsExpander, AttributeUnionTypeProcessor and DictionaryMemberUnionTypeProcessor: WebIDL, and JavaScript, define union types, which you may be familiar with if you are familiar with C/C++. An argument may be defined as accepting two or more types of value. For example, the union type (Node or NodeList) specified on an argument means that the argument can either be a Node or a NodeList. When specified on a return type for a method, again the return value could either be a Node or a NodeList. Since union types are not convenient to work with in Java, the job of these processor is to create method overloads for methods and fields with union types arguments. For the example above, this would create two method overloads with the union type in each being replaced by a single type.
  • MethodOptionalArgsExpander: Methods can be defined in WebIDL to have optional arguments. Since Java does not support optional arguments, the job of this processor is to remove any method with optional arguments, and replace it with as many overloads as it takes to handle all cases. For example, a method foo(int x, optional int y, optional int z) would be replaced with three overloads, one with x' as a parameter, one with xandy` as a parameter, and one with all three parameters.
  • MethodEnumArgumentProcessor, AttributeEnumTypeProcessor, DictionaryMemberEnumTypeProcessor: WebIDL defines 120 enum types, and gwt-jelement supports them with method overlays. These processors analyzes methods and fields with enum types and determines the underlying type of the enum.
  • ArrayArgumentHandler:
  • SuperCallConstructorProcessor: It is often the case that WebIDL will define a constructor on a parent class, but not on children classes. However, Java requires that whenever a parent class has a constructor, the child class must also have a constructor. This processor adds constructors as needed to satisfy Java, but creates them as private so as not to introduce nonexistent constructors into the API.
  • AttributeConflictingOverlayRemover
  • InterfaceDetector: Java like interfaces are not declared in WebIDL, they are implied. For example, any object with a length attribute and a getter with a numeric index implicitly implements ArrayLike, which makes it iterable. This processor analyzes each class definition and adds implicit interfaces to classes as needed, so that they can get the implied functionality, for example an iterable() method that returns a java.lang.Iterable<T> in the case of ArrayLike classes.
  • ImportResolver: This processor figures out, for each definition that results in a Java class, what the list of import statements will be for each class, based on the types used in the definitions methods or fields.

Although it may seem that like there are a lot of processors, there is plenty of room to add additional processors, as it only takes 300 ms to run all of the current processors on the nearly 1200 WebIDL definitions, so performance is not a concern at this point.

Source Generation

Java source code generation is done by the SourceGenerator processor. The templates for the code to be generated is defined in Xtend, which is ideally suited for this kind of processing. This phase generates not only the Java code, but also a GWT module file and Maven POM file to build the library jar.

Although most information has been obtained in the previous phase, there is still a bit of logic in this phase, to determine the proper method signatures. A focus for future work may be to eliminate all logic from this phase and moving it to additional processors, leaving only iteration through the model objects in this phase.