|
|||||||||
PREV NEXT | FRAMES NO FRAMES |
See:
Description
Packages | |
net.janino | The classes in this package pose the core of the Janino JavaTM compiler. |
net.janino.samples | Sample applications for the Janino JavaTM compiler. |
net.janino.tools | Auxiliary command line tools related to JANINO. |
net.janino.util | Application-independent helper classes. |
net.janino.util.resource | Classes related to loading "resources". |
Janino, and embedded compiler for the JavaTM programming language.
$Revision: 1.56 $
ClassLoader
that loads JavaTM classes directly from source codeJanino is a compiler that reads a JavaTM expression, block, class body or source file, and generates JavaTM bytecode that is loaded and executed directly. Janino is not intended to be a development tool, but an embedded compiler for run-time compilation purposes, e.g. expression evaluators or "server pages" engines like JSP.
The major design goal was to keep the compiler small and simple, while
partially sacrificing completeness. I don't like the idea of carrying around
huge libraries for simple applications. See Parser
for
the list of implemented and missing language features.
Say you build an e-commerce system, which computes the shipping cost for the items that the user put into his/her shopping cart. Because you don't know the merchant's shipping cost model at implementation time, you could implement a set of shipping cost models that come to mind (flat charge, by weight, by number of items, ...) and select one of those at run-time.
In practice, you will most certainly find that the shipping cost models you implemented will rarely match what the merchant wants, so you must add custom models, which are merchant-specific. If the merchant's model changes later, you must change your code, re-compile and re-distribute your software.
Because this is so unflexible, the shipping cost expression should be specified at run-time, not at compile-time. This implies that the expression must be scanned, parsed and evaluated at run-time, which is why you need an expression evaluator.
A simple expression evaluator would parse an expression and create a "syntax tree". The expression "a + b * c", for example, would compile into a "Sum" object who's first operand is parameter "a" and who's second operand is a "Product" object who's operands are parameters "b" and "c". Such a syntax tree can evaluated relatively quickly. However, the run-time performance is about a factor of 100 worse than that of "native" Java code executed directly by the JVM. This limits the use of such an expression evaluator to simple applications.
Also, you may want not only do simple arithmetics like "a + b * c % d", but take the concept further and have a real "scripting" language which adds flexibility to your application. Since you know the Java programming language already, you may want to have a syntax that is similar to that of the Java programming language.
All these considerations lead to compilation of Java code at run-time, like some engines (e.g. JSP engines) already do. However, compiling Java programs with SUN's JDK is a relatively resource-intensive process (disk access, CPU time, ...).
This is where Janino comes into play... a leight-weight, "embedded" Java
compiler that compiles simple programs in memory into Java bytecode
which executes within the JVM of the running program. (See the source code
of ExpressionEvaluator
for an
example.)
OK, now you are curious... this is how you use the
ExpressionEvaluator
:
// Compile the expression once; relatively slow. ExpressionEvaluator ee = new ExpressionEvaluator( "c > d ? c : d", // expression Integer.TYPE, // expressionType new String[] { "c", "d" }, // parameterNames new Class[] { Integer.TYPE, Integer.TYPE } // parameterTypes ); // Evaluate it with varying parameter values; very fast. Integer res = (Integer) ee.evaluate( new Object[] { // parameterValues new Integer(10), new Integer(11), } ); System.out.println("res = " + res);
Compilation of the expression takes 670 microseconds on my machine (2 GHz P4), evaluation 0.35 microseconds (approx. 2000 times faster than compilation).
Analogously to the expression evaluator, a script evaluator
exists that compiles and
processes a JavaTM "block", i.e. the body of a method. If a
return value other than "void" is defined, then the block must return a
value of that type. Example:
System.out.println("Hello world"); return true;
Analogously to the expression evaluator and the script evaluator, a class body evaluator
exists that compiles and
processes the body of a JavaTM class, i.e. a series of method an
variable declarations. If you define a contract that the class body should
define a method named "main()", then your script will look almost like a
"C" program:
import java.util.*; public static void main(String[] args) { Vector v = new Vector(); for (int i = 0; i < args.length; ++i) { v.add(args[i]); } System.out.println("Command line args converted into vector!"); }
The SimpleCompiler
compiles a single "compilation
unit" (a.k.a. ".java" file). Opposed to to normal JavaTM
compilation, that compilation unit may define more than one public
class. Example:
package my.pkg; import java.util.*; public class A { public static void main(String[] args) { B b = new B(); b.meth1(); } } public class B { void meth1() { System.out.println("Hello there."); } }
ClassLoader
that loads JavaTM classes directly from source code
The JavaSourceClassLoader
extends JavaTM's
java.lang.ClassLoader
class with the ability to load classes
directly from source code.
To be precise, it searches for a matching ".java" file in any of the directories specified by a given "source path", reads, scans, parses and compiles it and defines the resulting classes in the JVM. No intermediate files are created in the file system.
A BASH shell script named "bin/janino" is provided that wraps the
JavaSourceClassLoader
in a JAVAC-like command line interface:
$ cat my/pkg/A.java package my.pkg; import java.util.*; public class A { public static void main(String[] args) { B b = new B(); b.meth1(); } } class B { void meth1() { System.out.println("Hello there."); } } $ type janino /usr/local/bin/janino $ janino my.pkg.A Hello there. $
The Compiler
class mimics the behavior of SUN's javac
tool. It compiles a set of "compilation units" (i.e. JavaTM source files)
into a set of class files.
The BASH script "bin/janinoc" implements a drop-in replacement for SUN's JAVAC utility:
$ janinoc -sourcepath src -d classes src/com/acme/MyClass.java $ janinoc -help A drop-in replacement for the JAVAC compiler, see the documentation for JAVAC Usage: janinoc [ <option> ] ... <class-name> [ <argument> ] ... Options: -sourcepath <dir-list> Where to look for source files -classpath <dir-list> Where to look for class files -cp <dir-list> Synonym for "-classpath" -extdirs <dir-list> Where to look for extension class files -bootclasspath <dir-list> Where to look for boot class files -encoding <encoding> Encoding of source files, default is platform-dependent -verbose Report about opening, parsing, compiling of files -n Print subcommands to STDOUT instead of running them (any valid command-line optipon for the JAVA tool, see "java -help") $
You can plug JANINO into the utility through
the AntCompilerAdapter
class. Just make sure that janino.jar
is on the class path, then run ANT with the following command-line option:
-Dbuild.compiler=net.janino.AntCompilerAdapter
If you want to use JANINO with TOMCAT, just copy the "janino.jar" file into TOMCAT's "common/lib" directory, and add the follwing init parameter section to the JSP servlet definition in TOMCAT's "conf/web.xml" file:
<init-param> <param-name>compiler</param-name> <param-value>net.janino.AntCompilerAdapter</param-value> </init-param>
As of today, Janino is written and maintained entirely by myself, . I do this work without support of any company. I am independent from SUN Microsystems Inc.
Janino is distributed under the terms of the LGPL. I chose this license so that Janino will (hopefully) be useful in both free and proprietary projects.
Janino was initially developed with JDK 1.2.2 and CVS on Linux. Meanwhile, I switched to JDK 1.3.1 on Windows XP and dropped support for JDK 1.2.2. While the JavaTM platform is moving towards 1.5 and 1.6, I hope that all sane people have now upgraded to at least 1.3.1 ;-)
Janino should run on any operating system platform for which a JDK 1.3.1 or higher is available.
Janino has become a more or less complete JavaTM compiler, lacking only inner classes. This now allows for its use in more complex applications, e.g. a light-weight JSP engine.
The source code of
the ShippingCost
class demonstrates
how easy it is to use Janino as an expression evaluator.
The ExpressionDemo
class implements
a command line-based test environment for the expression evaluator (see also
its source code).
The ScriptDemo
class implements
a command line-based test environment for the script evaluator (see also
its source code).
The ClassBodyDemo
class implements
a command line-based test environment for the class body evaluator (see also
its source code).
Unzip the ZIP file you have downloaded:
$ jar xvf janino-1.0.21.zipChange to the Janino directory
$ cd janino-1.0.21You will find the Janino JAR file, the JAVADOC documentation, and the source code for the demo programs.
To compile the demo programs, run
$ mkdir classes $ javac -classpath lib/janino.jar -sourcepath src -d classes src/net/janino/samples/ExpressionDemo.java src/net/janino/samples/ScriptDemo.java src/net/janino/samples/ClassBodyDemo.javaTo learn how to use the demo programs, run:
$ java -classpath lib/janino.jar:classes net.janino.samples.ExpressionDemo -help $ java -classpath lib/janino.jar:classes net.janino.samples.ScriptDemo -help $ java -classpath lib/janino.jar:classes net.janino.samples.ClassBodyDemo -helpNotice: On MS Windows, the classpath separator is ";", not ":".
Unzip the ZIP file you have downloaded:
$ jar xvf janino-1.0.21-src.zipChange to the Janino directory
$ cd janino-1.0.21and compile the source code:
$ mkdir classes $ javac -sourcepath src -d classes src/net/janino/Compiler.javaYou will find the Janino class file in the
classes
subdirectory.
To generate the JAR file, run:
$ jar cf lib/janino.jar -C classes net/janino
To compile the demo programs, run:
$ javac -sourcepath src -d classes -classpath lib/janino.jar src/net/janino/samples/ExpressionDemo.java src/net/janino/samples/ScriptDemo.java src/net/janino/samples/ClassBodyDemo.javaTo learn how to use the demo programs, run:
$ java -classpath lib/janino.jar:classes net.janino.samples.ExpressionDemo -help $ java -classpath lib/janino.jar:classes net.janino.samples.ScriptDemo -help $ java -classpath lib/janino.jar:classes net.janino.samples.ClassBodyDemo -helpNotice: On MS Windows, the classpath separator is ";", not ":".
To generate the JAVADOC documentation, run:
$ mkdir javadoc $ javadoc -splitindex -package -doctitle "Janino 1.0.21" -windowtitle "Janino 1.0.21" -overview src/overview.html -sourcepath src -classpath classes -d javadoc net.janino net.janino.samplesYou will find the JAVADOC documentation in the
javadoc
subdirectory.
If you think you have found a bug in Janino, proceed as follows:
ExpressionDemo
, ScriptDemo
and ClassBodyDemo
command-line tools.
If you experience problems with downloading, installing or using Janino, issue a support request on the .
Please issue requests for new features on the .
This newsletter, as the name indicates, distributes information relevant for Janino users. It is very low traffic; mostly it announces the more important releases of Janino. You can subscribe and unsubscribe to this newsletter on the .
Other JavaTM compiler projects and products that I know about:
I appreciate your . Let me know how you want to utilize Janino, if you find it useful, or why you cannot use it for your project.
There's no special story behind the name. It begins with a "J", "janino.net" was still available, and it sounds similar to the name of a close relative of mine ;-)
NullPointerException
in the AntCompilerAdapter
.
ExpressionEvaluator
and the
ScriptEvaluator
.
Compiler
and AntCompilerAdapter
now
provide for the "extdirs" and "bootclasspath" features.
AntCompilerAdapter
now honors most of the options that ANT
passes to it.
IClassLoader
used to load
classes defined outside the current compilation unit are now stored in
thread-local globals. The IClassLoader
also holds the formerly
global IClass
cache, which caused a memory leak (reported by
Fabrice Carnet 2003-05-20).
IClass.isAssignableFrom(net.janino.IClass)
did not handle primitive types (reported
by Fabrice Carnet 2003-05-20).
ClassLoader
, if that is a
ByteArrayClassLoader
. This is necessary if the expressions,
scripts and classes need to refer to each other. (Requested by Fabirce Carnet
2003-05-20.)
java.lang.NullPointerException
.
net.janino.ClassLoaderIClassLoader.ReflectionIClass
holds a map
that guarantees that java.lang.Class
es and IClass
es
map one-to-one. This posed a memory leak. (Reported by Fabrice Carnet 2003-05-20.)
ClassBodyEvaluator
.
java.lang.ClassLoader
used to load the just-compiled
class now uses as its parent the current thread's context class loader
(reported by Fabrice Carnet 2003-03-26).
break
and continue
.
Java and all Java-based marks are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries. Arno Unkrig is independent of Sun Microsystems, Inc.
|
|||||||||
PREV NEXT | FRAMES NO FRAMES |