public class Test { public static void main(String[] args) { // Looks like C++... Vector v1 = new Vector(); // works like Java... v1.add("Foo"); v1.add("Bar"); v1.add(1, "Baz"); // ... but no casting needed when extracting elements. String baz = v1.elementAt(1); // Adding a mere Object to a Vector of Strings is an error, // and it's caught at compile-time. v1.add(new Object()); } } #### public class __CLASSNAME__ { private java.util.Vector impl; public __CLASSNAME__() { impl = new java.util.Vector(); } public void add(int index, __TYPE1__ element) { impl.add(index, element); } public boolean add(__TYPE1__ o) { return impl.add(o); } public __TYPE1__ elementAt(int index) { return (__TYPE1__) impl.elementAt(index); } // The rest of java.util.Vector's interface here... } #### #!/usr/bin/perl -w # java-templater.pl, version 0.01, 2001/06/13 # Makes type-safe Java classes from templates. # Author: Colin McMillen (mcmillen@cs.umn.edu) =head2 TODO * Better error tolerance (current code barfs on whitespace, among other things) * Get nested templates working. * Check to make sure the number of arguments within a template declaration (like Foo) matches the actual number of arguments needed to create a templated class of the appropriate type. * Make into a module. (?) * Support for templated classes of Java built-in types, such as int and double. * Support for recursively processing a directory structure's worth of files. * Support for putting template instantiations into a separate package, which would then be imported by files that use templates. * Better documentation. * Implement in Java (ack.) * Creation of the proper templates to replace Java's entire Collections hierarchy. * Much, much more, I'm sure... =cut use strict; my $VERSION = "0.01"; my @templates = qw(Vector); # We need at least two command-line arguments (a directory and a # .tmpl file) to do anything. unless (@ARGV >= 2) { usageMessage(); exit(0); } # Used to make sure we don't generate the same templated class twice. my %createdClasses; # Get the code directory and make it if needed. my $codeDir = shift @ARGV; mkdir $codeDir; # Create all our .java files! createTemplatedClasses($_) foreach @ARGV; # Given a .javat file, parses the file, looking for uses of templates. # Translates code which uses templates into valid Java and generates new # .java files for every different templated class used by the .javat file. sub createTemplatedClasses { my ($filename) = @_; # We make sure the filename ends with the proper extension so we don't # accidentally try to parse non-templated files. die "Filename $filename must end in '.javat'" unless $filename =~ /\.javat$/i; # Read the file. local $/ = undef; open (CODE, $filename) or die "Could not open template file: $!"; my $code = ; # For each type of template, look for template syntax. # Replace template syntax with valid Java code, and create new # templated classes. foreach my $template (@templates) { while ($code =~ s/$template<(.*?)>/getClassName($template, extractTypes($1))/e) { my @types = extractTypes($1); createTemplate($template, \@types); } } # Write the file to the proper location. $filename =~ s/\.javat$/\.java/; print "Creating $codeDir/$filename..."; open (CODE, ">$codeDir/$filename") or die "Could not output to $codeDir/$filename: $!"; print CODE $code; close(CODE); print " done.\n"; } # Given a comma-separated list of class names, returns a list of the names. sub extractTypes { my $argString = shift; my @types = split /,\s*/, $argString; } # Given a template and a list of Type arguments, # generates a descriptive class name. sub getClassName { my ($template, @types) = @_; @types = map { stripPackagePart($_); } @types; return join("", @types) . $template; } # Given a class name, strips off the package qualifier and returns # the result. (i.e. "java.util.Vector" -> "Vector") sub stripPackagePart { my $name = shift; $name =~ s/.*\.(.*?)/$1/; return $name; } sub createTemplate { my ($template, $types_ref) = @_; my @types = @$types_ref; # Get the name of the class we'll be creating. my $newClassName = getClassName($template, @types); # Return if we've already created a class with this name. return if defined $createdClasses{$newClassName}; # Prevent duplicate classes from occurring. $createdClasses{$newClassName} = 1; # Read the template from disk. print "Creating $codeDir/$newClassName.java..."; local $/ = undef; open (TEMPLATE, $template."Template.tmpl") or die "Could not open template file: $!"; my $text =