Showing posts with label java. Show all posts
Showing posts with label java. Show all posts

2009-03-09

Interacting between <insert JVM lang here> and Java

[2009-03-15: This blog post has been thoroughly rewritten after I found out some details were wrong and people wanted more details]

I don't like Java. If care to find out why you can search my blog, but it's no secret Java is not exactly at the top of my list of favorite programming languages. But I am not stupid enough to think that Java is about to go away. And I have nothing against the JVM, just the primary language that runs on it.

Thanks to the JVM, just because I have to work with Java code does not mean I have to write Java code. Thanks to various languages being ported to the JVM there are now multiple options for working with Java code in languages other than Java:



By targeting the JVM all the above languages can call Java code in order to be relevant in a Java-heavy world. But just because they can easily consume Java code does not mean that the reverse is true. What I am looking for is not just a way to call into Java, but to call other languages from Java.

To better explain this, take the following three files. First, I have Spam.java:

public class Spam {
public String serves() {
return "spam";
}
}
I have another class that implements a subclass, BaconSpam.java:
public class BaconSpam extends Spam {
@Override
public String serves() {
return "bacon " + super.serves();
}
}
And finally, the class that runs the show, Waitress.java:
public class Waitress {
public static void main(String[] args) {
BaconSpam menu = new BaconSpam();
String food = menu.serves();
System.out.println("We serve " + food + "!");
}
}
What I am after is a language to rewrite BaconSpam.java in another JVM language such that I don't touch Spam.java. I also want the changes to Waitress.java to be minimal or non-existent while still having to store an instance of the class and the value returned by serves() to show how objects would be stored and used in a long-running Java application (i.e. no cheating by inlining some call in the println() call to make the example a little tougher and more "real world").


Jython



Thanks to the Jython guys I was pointed to a Jython Monthly article from October 2006 that explains how best to go about accessing Jython code from Java.

To start I wrote BaconSpam in Python:
import Spam

class BaconSpam(Spam):
def serves(self):
return " ".join(["bacon", Spam.serves(self)])


While that was rather simple, there is still the issue of getting an instance of the class. Because Jython dynamically interprets Python code you can't simply drop in BaconSpam.py and have it work with Waitress.java. You need to create an instance of org.python.util.PythonInterpreter and interface with it to get at the Python code:

import org.python.core.__builtin__;
import org.python.core.PyObject;

public class Waitress {
public static void main(String[] args) {
PyObject BaconSpam = __builtin__.__import__("BaconSpam").__getattr__("BaconSpam");
Spam menu = (Spam)BaconSpam.__call__().__tojava__(Spam.class);
String food = menu.serves();
System.out.println("We serve " + food + "!");
}
}


Because Jython dynamically loads Python code, Waitress.java has to be modified. Luckily a large chunk of the code is boilerplate that can be extracted out into a factory class to help simplify things.

And just a warning for anyone wanting to run the above code: for some odd reason the above code only worked for me with Jython 2.5b3, not 2.2.1.


JRuby



Writing the BaconSpam subclass was simple:


class BaconSpam < Spam
def serves
"bacon " + super
end
end


But as of right now you need to use JSR 223 to interface with the class which is worse than the Jython approach, so I am not going to go through the steps here.

But Charles Nutter has blogged about adding signature support to JRuby's in-dev compiler2. It looks like as soon as inheritance is handled properly in compiler2 that JRuby will be in the same position at Groovy and Scala for ease of integration (see below for details on those two languages).

Rhino



I don't like JavaScript, so I am skipping Rhino. =) But it's another JSR 223 approach.

Clojure



I actually didn't get Clojure to work. I tried to follow the gen-class example from the Clojure wikibooks, but ran into several issues that included having to manually execute compilation for the Eclipse plug-in to even get an error message and putting the code in a package to get Clojure to not assume I was working off of java.lang when inheriting from Spam.java.


(ns pkg.BaconSpam
(:gen-class
:extends pkg.Spam
:exposes {serves servesSuper}))

(defn -serves [this]
(str "bacon " (.servesSuper this))
)


With an error of "java.lang.IllegalArgumentException: Don't know how to create ISeq from: Symbol", I just stopped trying to make this work. I assume Waitress.java will need to be changed beyond just being put in a package anyway in order to deal with Clojure's dynamic typing.


Groovy



Writing the Groovy version of BaconSpam was very easy thanks to the language having been designed for the JVM from the outset. The only trick was that serves() needed to have the return type specified for the method instead of being dynamic:


public class BaconSpam extends Spam {
// Using 'def' makes return value dynamic.
String serves() {
return "bacon " + super.serves()
}
}


With the typed method there is no need for modifying Waitress.java. Groovy basically ends up looking like Java with some syntax removed.

One issue that did come up with writing the Groovy example was that the Eclipse plug-in is in some bad shape; I couldn't get it to run the project. This drove me to download and use NetBeans since it has Groovy support included. That was a much better experience since it actually worked.

Oh, and the docs suck. Took way too long to figure out how the darn language is even structured. Just had to read various examples to figure things out.


Scala



Much like Groovy, Scala was easy to use to rewrite BaconSpam.


class BaconSpam extends Spam {
override def serves(): String =
return "bacon " + super.serves()
}


And just like Groovy there was no need to change Waitress.java in order to interact with the class. But unlike Groovy the Eclipse plug-in for Scala actually allowed me to execute the application. Plus the docs are better so I didn't have to go digging around to figure out what I needed to do.

2008-08-01

Abstract and poster of my thesis work is online

The abstract and poster that I presented at SOUPS 2008 are now online (the poster will most likely not make a ton of sense without reading the abstract; it was more to act as a visual aide for me to explain my work than to be self-contained). It basically outlines a way for a Java developer to secure a pre-existing application against misuse of resources through AspectJ and an approach inspired originally by object-capabilities. As soon as I have a paper published and I am cleared to post it online I will (hopefully in December).

2008-02-07

Java should have stayed a systems language

Today's revelation about what I don't like Java stems from the fact that its dysfunctional attempt at being an application language has led to people thinking it is the be-all, end-all language for programming. Java was originally designed as a systems language for set-top boxes to connect to your TV. But thanks to the popularity of Java applets in web pages it has slowly tried to morph into an application language. But because it won't give up backwards-compatibility it feels like it is kind of a systems language, kind of an application language, but neither completely.

And yet people treat it like it is this grand language that can solve all of your problems. But even I don't think that is reasonable. I use Python when I can, but when I have to drop down to C I do. But Java just doesn't try to fit that bill since it tries to perform in the same space as Python. Now luckily Sun seems to have realized their mistake and is paying to develop JRuby and we have Jython, but I won't be satisfied until people start to realize that Java should be something they resort to, not start off with.

2008-01-31

Java needs to check the validity of its security policy files better

So I have been spending today trying to get an application to run under a security policy file from an Ant build file. Not exactly a complex task. And yet neither the policy file nor the Ant build file seem to have enough error checking when they are used to make sure that there are not any stupid typos.

Take the policy file for instance. The JVM makes sure it is well-formed. But if you have a Permission object listed that does not exist, there is absolutely no warning about that fact. You would think that the failure to instantiate an object would be an error, especially for something like a security policy file, but apparently not. And you can't rely on policytool since it won't let you use some substitution string as the code base location (I have my Ant build files generate the policy file as needed to make it completely platform-independent).

And for Ant build and property files, there is no checks to make sure that properties actually exist by default. So if you have a slight typo in a property name for string replacement you won't know because it will just evaluate to the empty string. You can run in verbose or debug mode, but the amount of output is a bit much.

I can't believe I am having to consider writing a verification tool for Java security policy files that makes sure that the thing has no typos. At least it would give me an excuse to learn more Jython.

2008-01-24

I really hate it when tools get in your way

One of the great things about Python is that it doesn't get in your way. I like being treated as an adult by my tool of choice. If there is a specific way I want to do something, darn it Python usually doesn't prevent me from taking my preferred approach.

The same can't be said for Java. Case in point is its generics implementation. For those of you who don't know, Java's generics is done through type erasure. That means that when you have some parameterized type like List, the compiler verifies that all uses of the type expect a String. But when the Java bytecode is emitted, there is no type information. This is what allows Java bytecode coded with generics to run on older JVMs. Nice for portability to old systems, but a bitch for me.

Why is this an issue? Namely it has led to very restrictive uses of the parameterized type in actual code. If I define a method or class to take a parameterized type of T, I can basically use that in places where a type normally might be found, but only as long as I don't try to do anything with the type itself. What this means is that using T in variable declarations is fine, but I can't work with T directly.

Normally this restriction is not a big deal. But what if you want to write a generic method that dispatches based on an argument and the generic type comes into play? An instance of this might be a generic equal() method that does nothing more than check if the argument to the method is a compatible type with T. Well, you can't do that. Try doing T.class or T.getClass() and see the lovely error message the Java compiler tosses you.

Now I can understand not allowing this if I was asking for random methods off the type. But getClass() is defined on Object, the base object type that all objects inherit from! There is no chance (to my knowledge) of setting a parameterized type to an object that does not inherit from Object! So why the hell can't I call methods that are on all objects on a generic type?!?

I eventually got around it by declaring a protected attribute that held a Class object and explicitly set it to what the type parameter is for subclasses. That's really hackish and stupid thing to have to do.

And within a short amount of time after that I had AspectJ and Eclipse piss me off. My work involves taking existing Java applications, applying AspectJ to them externally, and then running them with some extra stuff to the JVM (sorry for being vague, but I am holding off until I have a publication to really go into detail about what I am working on so I have something to point people to). Trying to get Eclipse projects to compile and weaving together turned out to be quite the hassle. So much so, in fact, that I am going to learn Apache Ant properly and use that for weaving and executing my AspectJ projects. It also doesn't help that Eclipse's AJDT plug-in does weaving MUCH slower than doing it through the command-line.

Overall a frustrating week. I am now behind where I wanted to be thanks to having wrestle with this crap. Bah.