Looking inside – bottom-up

Strengths and Characteristics

Japaki builds on standard Java classes and apis, using already existing implementation and allowing better interaction with other frameworks. Japaki is organized in several layers allowing amendments and extensions on every layer.

Packages

Japaki consists of six packages that are based on each other:
basic
contains helper classes of general use, not related to parsing in particular;
beans
defines properties and beans,
io
provides helper classes for in- and output,
text
contains the parsers,
kit
offers the classes to create parsers,
self
the topmost package to interpret syntax definitions.

Core Classes

The following graphic shows the main classes of japaki.

japaki core classes

Parser class – the text package

The starting point is the Format class in the java.text package with its basic methods format and parseObject. A format is a rule how to transform a java object into a string. A format can be parameterized by some fields like The japaki parser differs from the standard Format in three aspects:
  1. It uses generics: A format or parser only applies to certain types of objects
    1. The NumberFormat to numbers,
    2. The DateFormat to dates,
  2. This is not reflected in the Format, the parseObject-method of which returns an Object, because it was written before Generics came up.
  3. The standard java class ParsePosition is determined by a single integer and therefore limited to (single line) strings. The japaki positions ParseReader and ParseWriter are intended for files and therefore also contain a line number and a newLine method.
  4. The standard format and parse methods deliver the result as the return value from the method. Japaki methods do not return a value but store the result in an object using properties. A property tells the parser how and where to store and retrieve the value.
The connection between a Parser and a Format is established by the LeafParser class that creates a parser out of a Format.

Abstracting properties – the beans package

Say, we have a bean with a property foo:

public String getFoo(){ return foo;}
public void setFoo(String foo){ this.foo = foo;}
In order to pass the get- and set-method to a parser they have to be converted into an object. This is the idea of the Property-interface. A property tells the parser how and where to store and retrieve the value in the object by virtue of getValue and setValue methods. The bean package contains a set of properties for basic java classes.

Generic Beans

One of the strengths of Japaki comes from abstracting a property into its own class. This makes the path to the next step: A bean that provides a list of all its properties. This is of course similar to using reflection, where a list of all getter methods can be obtained using reflection methods. Reflection allows using common Java beans which are widespread in the java world, while generic beans allows checking of dependencies at compile time. ReflectionProperty and JavaBeanInspector support the use of reflection.

Nested definition – the kit package

One of the main characteristics of a more complex syntax is that a parser is defined using another parser. This calls for a place where the yet defined parsers can be looked up. This function is adopted by the ParserStore class. To be flexible the ParserStore does not store parsers but factory classes that create a certain type of parsers based on its construction parameters. This factory class is called a ParserMold. So the ParserStore contains
  1. a mapping of names to ParserMolds.
Typically only one parser is needed for a class type, so the next thing the ParserStore has is
  1. a mapping of classes to ParserMolds
The class can be derived from the property, so if the default parser for the class is used, the parser name can be omitted. The simplest way to retrieve a parser is with a property using findParser.

Parsing the syntax definition – the self package

As a proof of concept, japaki is applied on itself or, strictly speaking, on the syntax definition strings. The meta definition parser is defined in SyntaxParser. This permits changing the syntax definition syntax if necessary by writing either a subclass of SyntaxParser or changing the parser store for small changes or writing a syntax definition file. To facilitate flexibility in finding the properties from the property names, two new classes – the Inspector and InspectorMill – are used. The inspector knows how to create a property for a specific bean class. The inspector mill knows the inspector for a given class. The tree of java beans and other objects is mirrored by a tree of inspectors created while parsing the syntax definition file.

Because inspectors cannot be used in the parsing process, the creation of a parser from the syntax definition is done in two steps:

  1. Parsing the text and storing the results in a ParserBean tree. The name of the property and not the property is stored in the parser bean.
  2. Invoking recursively the toParser() method, creating properties from the property names. This requires a parser bean for every parser.

Patterns

Composite Pattern

The composite pattern is used several times within japaki. It consists of an interface, of which the implementing classes can have zero to many instances of the interface, so that a tree is built. The central method takes a data container as argument that is shared among all members of the tree.
package data container interface
text ParseReader
ParseWriter
Parser
self InspectorMill Inspector
self Inspector ParserBean