-
Notifications
You must be signed in to change notification settings - Fork 0
Theory of Operation
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.
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.
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 isHTMLImageElement
, which defines a named constructor namedImage
in its IDL file. Although you cannot create instances ofHTMLImageElement
withnew
, because that class lacks a constructor, you can create an image element withnew 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 theNavigator
orWindow
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 ofNavigator
that defines thegeolocation
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 exampleWindow
andWorker
. 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
andDictionaryMemberUnionTypeProcessor
: 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 aNode
or aNodeList
. When specified on a return type for a method, again the return value could either be aNode
or aNodeList
. 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 methodfoo(int x, optional int y, optional int z)
would be replaced with three overloads, one withx' as a parameter, one with
xand
y` 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 alength
attribute and a getter with a numeric index implicitly implementsArrayLike
, 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 aniterable()
method that returns ajava.lang.Iterable<T>
in the case ofArrayLike
classes. -
ImportResolver
: This processor figures out, for each definition that results in a Java class, what the list ofimport
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.
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.