An attempt to port Java classes into Javascript while preserving the original Java language code's structure and hierarchy, i.e. inheritance and interfaces.
- OOP Layer: qooxdoo Core
- Although it comes with a toolchain, jsava currently utilizes its own compiler script to organize dependency management and task execution.
- Testing: Jasmine
- Minification: UglifyJS
- Code Style: configuration file is found in lib/style.xml
- Fork or clone the repository.
- Make sure your system meets the following requirements:
- Perl (>= 5.010)
- Java (>= 1.6)
- nodejs
- node-coverage module (Only needed for coverage analysis)
- UglifyJS (contained in
lib/
)
- Execute
tools/compile.pl
to build the project. - To run the tests you can either open the
SpecRunner.html
in a browser or use thetests.jstd
file for jsTestDriver. Both files will be generated in the previous step.
jsava classes follow the same package naming schema as in Java, with one slight modification: The root package is called
jsava
(d'oh). This means that classes can be accessed by their fully qualified name, i.e.
var map = new jsava.util.HashMap();
However, this is pretty exhausting and verbose. To make life a bit easier, jsava currently tries to export all classes to a shortened name – if possible. Whenever the short name already exists, it will be tried with a 'j' prefix. If this is still not possible, it will be skipped. This allows something like
var map = new HashMap();
However, because Object
is already a Javascript built-in type, the jsava class is prefixed and will be available as
jObject
.
A little example script would be
var map = new HashMap();
map.put( 42, 1337 );
console.log( map.get( 42 ) ); // 1337
- The main objective is to preserve the original Java implementation as closely as possible.
- To keep the code consistent, the following rules shall be followed.
- However, this list is subject to change.
- If any situation not covered in these rules is encountered, existing code shall be looked at for examples and new patterns be documented.
- All names shall follow the original Java name pattern, not the qooxdoo pattern.
- For conflicting names (e.g. property
size
and methodsize()
), the entity that gets the original name is determined by the following rules:
- Higher visibility (
public
>protected
>public
) - Methods over fields
- The inferior entity shall be named according to the qooxdoo scheme (e.g. private field
size
->__size
). If the visibility retains the name conflict, the entity shall be handled as private.
- Classes shall be defined using
defineClass
, interfaces by usingdefineInterface
. These are wrappers forqx.Class.define
andqx.Interface.define
to perform some additional tasks (e.g. inheriting static members). - Classes and interfaces must be annotated as such (see existing classes).
- Every method in an interface that takes a parameter or returns something shall have annotations.
- Every method in a class that has not been defined in a superclass or interface shall be annotated.
- If a class has a constructor, it must call the parent constructor (this is tested).
- To check an argument for its type, use either
qx.Class.hasInterface()
(for interfaces) orqx.Class.isSubClassOf
(for classes). Do not useimplementsInterface
,objectImplements
, … - Static inner classes must be instanciated with
new this.constructor.SomeClass(...)
, otherwise it will result in wrong behavior when the class is inherited (see example injsava.util.HashMap
). - Inner classes, especially those requiring a reference to the enclosing class, shall be initialized with
null
as a member (with corresponding annotations) and be defined in the enclosing class's constructor (see example injsava.util.HashMap
).
- Private members may be implemented differently or omitted altogether if not necessary.
- Every member not initialized with its actual type (i.e. when initialized as
null
) shall have a@type
annotation. - Every member not defined in a superclass shall have its visibility annotated.
- Members that either currently or permanently cannot be implemented shall still be added and throw an
UnsupportedOperationException
. - No member variable shall ever be initialized with
undefined
. Instead, the correct default value shall be taken, i.e. a simpleNumber
member will be0
while any complex object will default tonull
. - If any implementation -- or its behavior -- differs from the original Java code, there shall be comments if necessary.
- Any static member that is not explicitly referenced from a class needs to be called via
this.constructor.NAME
in order to allow hiding the value.
- See
jsava.lang.RuntimeException
for an example on how to define a simple exception only encapsulating a subclass with a new name. - Since Javascript can only catch anything that is thrown, the following pattern shall be used to catch exceptions in a similar manner to Java:
try {
// ...
} catch( e ) {
if( qx.Class.isSubClassOf( e.constructor, jsava.lang.IllegalStateException ) ) {
// caught an IllegalStateException
}
// rethrow non-caught exceptions
throw e;
}
- Every public method of a class shall have at least one test.
- Every non-error use-case of a method shall be tested (error-cases are a nice plus, though).
- A
TODO
comment may never be empty; it should always contain what the comment is about.