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

2010-05-19

Scratching an itch

Several times in the past years I've found myself wanting a Java client for the Apache JServ Protocol, commonly used for communicating between a proxy/load balancer such as Apache and a servlet container such as Tomcat.

The itch has never been bad enough to spend time on, but tonight I decided to go ahead and write one (never say that waiting for maintenance windows to roll around can't be spent productively!).

So if this is the kind of thing that floats your boat, head on over to GitHub and grab your copy of the steaming hot pile of dung source code.

2009-06-19

More puzzling behaviour

Still in the spirit of Java Puzzlers; can you provide declarations for i and j to make this statement fail at runtime?

i = j;


I spent quite some time debugging this, once...

Puzzling behaviour

In the spirit of Java Puzzlers, what does this program print (if anything)?

public class java
{
static lang lang = new lang();

static class lang
{
static Long Short = new Long();

static class Short
{
}

static class Long
extends Short
{
}
}

public static void main(String[] args) {
System.out.println(java.lang.Short.class.getSimpleName());
}
}

2008-11-25

Fun on the bleeding edge

My pet project jde-mvn depends on bleeding-edge snapshots of Maven 3.0. The reason is simple: MvnServer needs maven-embedder, which pre-3.0 is only available in a buggy and frankly unusable version 2.0.4.

Mostly this is not a problem; however, the recent work Shane Isbell has done on the POM model breaks some existing POMs. Among them, unfortunately, is the CXF parent POM; this means that jde-mvn will choke on any project that depends on CXF (or any other POM that triggers the underlying bug).

I've reported this issue as MNG-3838; no word yet on when it will be fixed (although "sometime before 3.0 goes final" is a safe bet).

Since some of the things I work on in my day job use CXF, I've made my own nastyhack version of Maven and created a "release" of jde-mvn that embeds it; read more about this "release" on the BitBucket site.

2008-11-24

More fun with JDEE

With jde-mvn having reached a more-or-less stable point, I've played with some other ideas to make JDEE an even better environment.

One of these ideas is jde-refactor, which has now gotten far enough to unleash upon the unsuspecting masses. Er. Maybe there is one other person in the world who might find this useful?

2008-09-25

pom-parser is dead, long live jde-mvn!

As some of you know (I know you're out there, freaks), I'm happily hacking away at my JDEE-Maven integration project. Up to now I have had two separate projects:
  1. pom-parser, which dealt with getting information from the POM and into JDEE's variables
  2. jde-mvn, which dealt with using Maven as a build tool
This became cumbersome, and got in the way of some cool stuff I wanted to do. So I merged them. :)

pom-parser is now deprecated; if you use it, you should move to jde-mvn.

This shouldn't be onerous for the, like, two people besides me who use it (while I'm on the subject, if you use this please drop me a note!), even though most (all?) of the functions in pom-parser have changed names.

jde-mvn is packaged as a JDEE plugin (for more on this, read about plugins in the JDEE manual), which means that the installation process is both simpler and more complicated, but ultimately I think this is the way I want to go.

Anyway, jde-mvn now supports a server mode, thus amortizing the startup cost of the JVM across calls. Wee! The initial startup cost is quite heavy, though, but there is not much I can do about that.

So. If you want to play with jde-mvn, it is available from my Mercurial repository. I will try to keep even tip fairly stable (I do the major hacking on a local clone), but I will also tag what I consider to be stable revisions with 'stable-DATE'; if you don't fancy life on the severely-hemorrhaging edge, you may want to go with one of these.

Enjoy!

2008-09-05

I just can't let this go unpublished...

public class $_ {
public static <$_> $_ $_($_ a) {
return a;
}
public static <$_> void $_($_ ... $__) {
for ($_ $_ : $__) {
// \u000a\u0053\u0079\u0073tem\u002eo\u0075t\u002epr\u0069n\u0074\uu006c\u006e($_($_));
}
}

public static void \u006d\u0061\u0069\u006e(\u0053t\u0072i\u006e\u0067 ... $_) {
$_($_);
}
}


Or, even better:

public class $_ {
public static <$_> $_ $_($_ a) {
return \u0061\u003b\u002f\u002f$!"#$&/($##§!"a;
}
public static <$_> void $_($_ ... $__) {
for ($_ $_ : $__) {
// \u000a\u0053\u0079\u0073tem\u002eo\u0075t\u002epr\u0069n\u0074($_($_));
}
}

public static void \u006d\u0061\u0069\u006e(\u0053t\u0072i\u006e\u0067 ... $_) {
/*
* \u002a\u002fif($_\u002ele\u006egth\u003d=0)$_=\u006ee\u0077 \u0053t\u0072i\u006e\u0067[]{\u002f\u002a\u002a\u002f"Obfuscated!"};\u002f\u002a
*/

for (\u0053t\u0072i\u006e\u0067 _$ : $_) {
$_(_$\u002es\u0070\u006ci\u0074(\u0022"));
$_(\u0022\n"\u002c "")\u003b;
}
}
}

More obfuscation fun

From this blog entry comes this gem:

import java.util.Collection;
public class TestType {
public static <Collection> Collection myMethod(Collection a) {
return a;
}
public static void main(String ... args) {
System.out.println(myMethod("Hello World"));
}
}


Beautiful, just beautiful...

2008-09-02

The joy of programming

Today I had occasion to rediscover the joy of programming. Not that it's been dull lately, far from it, but today I did something real fun. Today's word is 'obfuscation'.

It started when I directed a colleague to The International Obfuscated C Code Contest. Obfuscation is just so easy in C; but can the same kind of thing be done in Java? Well...

Inspired particularly by the Mullender entry from the very first IOCCC, in 1984, I sat down and thought.

Here is what I came up with:
public class Obfuscated {
static String n, m;
static java.util.Map bm = new java.util.HashMap();
static {
try {
n = new String(new byte[] {79,66,70,85,67,76,65,83,83}, "UTF-8");
bm.put(n, new byte[] {
120,-100,109,80,93,75,2,65,20,61,-41,
-81,117,-73,45,77,-45,62,5,95,34,-19,33,-95,87,-93,
-88,64,8,36,-125,45,95,122,-102,-43,81,70,118,103,
67,103,-125,126,86,61,20,-12,-48,15,-24,71,69,
119,77,-112,-64,121,-72,-9,-50,-103,115,-18,61,119,
-66,127,62,-65,0,-100,-94,70,-80,123,87,-99,-121,
-21,-18,-91,-25,89,32,66,113,34,-98,69,43,16,122,
-36,-22,-7,19,57,48,22,-46,-124,66,-49,31,-59,-77,
-127,48,114,120,-110,16,8,-71,51,-91,-107,57,39,
-92,27,-51,-66,-117,28,44,7,25,-28,9,-103,80,40,
77,-88,54,30,-69,-53,86,-98,-103,42,61,110,55,-5,
-1,6,120,47,51,35,67,11,46,119,-119,98,67,-88,-4,
73,84,-44,-70,99,-66,97,-107,20,97,-37,-59,6,10,
54,-42,81,-28,-74,55,51,125,100,-22,-47,-62,-114,
-118,116,125,20,-21,-117,60,74,-124,-14,10,-79,-123,
45,-126,-11,-108,0,1,-69,-86,52,86,-103,114,81,
-59,-74,-125,10,118,-40,-2,117,52,-108,-68,112,87,
105,121,27,-121,-66,-100,-34,11,63,96,-60,-15,-94,
120,58,-112,29,21,72,16,82,-68,108,114,82,92,-13,
-18,28,-9,-8,86,-29,76,-100,-77,-57,31,-80,95,
-71,32,-20,115,-52,-51,65,-2,106,56,88,91,80,15,-25,
82,-64,126,-61,102,-87,-4,-114,-35,37,-35,-31,
39,36,-97,-119,44,35,7,-13,41,-39,95,48,-4,89,-18
});

m = new String(new byte[] {109,97,105,110}, "UTF-8");
} catch (java.io.UnsupportedEncodingException e) {
}
}

public static void main(String[] a) throws Exception {
ClassLoader cl = new ClassLoader() {
protected Class findClass(String cn) throws ClassNotFoundException {
if (bm.containsKey(cn)) {
try {
java.io.ByteArrayOutputStream baos = new java.io.ByteArrayOutputStream();
java.util.zip.InflaterOutputStream ios = new java.util.zip.InflaterOutputStream(baos);
ios.write(bm.get(cn));
ios.close();
byte[] bytes = baos.toByteArray();
return defineClass(cn, bytes, 0, bytes.length);
} catch (java.io.IOException e) {
throw new ClassNotFoundException(cn, e);
}
} else {
return super.findClass(cn);
}
}
};

Class c = Class.forName(n, true, cl);

for (java.lang.reflect.Method me : c.getDeclaredMethods()) {
if (m.equals(me.getName()))
me.invoke(null, (Object)a);
}
}
}
You can download this code.
Not as pithy as Mullender's, but it still has a certain something.

Now, of course, I didn't write that monstrous byte array by hand; in fact, the entire program above was written by another program, which is listed below:

public class Obfuscator {
static String n, m;
static java.util.Map bm = new java.util.HashMap();
static {
try {
n = new String(new byte[] {79,66,70,85,67,76,65,83,83}, "UTF-8");
bm.put(new String(new byte[] {77,101,116,104,111,100,82,101,110,97,109,101,114}, "UTF-8"),
new byte[] {
120,-100,-107,84,-51,78,19,81,24,61,-73,
45,20,-38,-31,-81,-108,42,34,32,32,-38,118,40,
69,65,65,1,21,17,-76,74,107,34,-124,-123,-69,-95,
-67,-64,-32,48,37,-19,-16,-93,111,-30,-54,37,91,77,
68,-125,11,-29,-54,-123,-113,-32,11,-8,14,-58,-120,
-25,78,-85,-87,-76,42,-90,-55,-52,-67,-33,-49,
57,-25,-98,-5,77,63,125,127,-9,30,-64,101,-36,23,
104,74,75,103,61,-97,123,36,109,99,83,22,-4,16,2,
-67,-7,-62,90,50,-65,-78,33,-77,-50,-82,92,73,26,
-59,-51,100,-87,104,38,103,108,57,-86,-56,43,16,
-6,-83,111,120,-61,-40,49,4,26,-14,86,46,-61,125,
81,-96,101,65,-123,-110,-37,-114,105,37,23,-91,51,
41,-32,-73,-27,-82,74,-78,-73,-108,-77,12,123,45,
-71,-24,20,76,123,-115,105,-49,-26,-114,64,-33,-62,
-97,-72,-105,-51,-94,-23,-28,11,44,-84,-97,50,
109,-45,-71,33,48,23,-3,103,-11,49,17,-43,-68,-79,
101,-127,-13,-1,-58,-119,45,107,-48,-48,28,-128,
15,45,26,2,8,54,-62,-125,54,13,-11,-16,-85,85,-69,
-122,6,52,-86,85,7,29,-35,81,77,75,79,-73,100,-54,
46,-38,2,-111,104,-86,54,111,-45,111,-30,-4,-24,
-92,-127,-39,-68,-19,24,-90,77,3,59,-94,21,93,15,
93,109,-109,-79,-57,26,-70,112,54,-120,51,-24,-2,
-53,61,-107,85,-5,-47,-85,-31,20,78,7,113,14,125,
2,-51,-82,-82,121,83,90,-71,-110,-80,-21,-75,-124,
-99,36,-94,-60,123,87,-51,61,-127,11,-47,26,-39,
-22,-112,-122,65,92,8,-48,-98,-117,26,6,112,94,9,
-118,113,68,92,65,37,-55,74,-111,6,-67,-108,27,-94,
17,38,7,-51,-32,33,-108,127,-79,-118,107,76,-107,
-29,-60,28,70,82,57,49,-62,-127,-86,-50,-5,113,
-103,35,-73,110,20,51,114,-49,-95,-36,-88,-14,110,
12,87,-126,24,-59,85,1,-97,-19,-122,-61,-47,88,
-75,-53,26,38,112,77,-43,93,23,104,61,126,22,63,-90,
-120,107,-38,57,-71,-9,112,-11,-40,45,-3,52,32,
-91,-31,6,110,6,48,-115,91,2,-127,-126,-36,-78,-116,
-84,-100,-79,44,-127,-119,26,-27,39,116,-16,54,
102,21,-30,29,106,-97,-51,-25,-92,-6,-62,76,91,
102,-74,55,87,100,97,-55,88,-79,24,105,90,116,-116,
-20,-109,-76,-79,85,-34,7,22,-13,-37,-123,-84,-100,
55,45,-119,62,-70,-17,-29,71,-17,-27,-101,83,
-53,-107,71,-51,-84,-5,-26,60,-13,93,7,-63,25,111,
-30,115,-98,-69,-23,114,125,71,92,127,-117,-42,-72,
126,-128,80,124,-24,0,-31,120,-30,0,-111,87,76,
8,-36,-27,51,-62,54,-80,-83,-114,-115,1,52,-93,-123,
-65,48,90,-103,-27,-32,-107,-95,30,-112,-44,-53,
119,79,-4,53,-62,67,-121,-24,-15,-32,57,26,-72,
-119,-92,-7,8,117,49,-44,-17,-59,43,87,-118,-62,
12,-71,-60,-19,68,12,115,29,65,55,-79,-18,-71,-46,
69,-120,-112,28,-96,50,-16,42,79,-94,-24,39,42,-127,
-69,92,76,-123,-98,-120,119,-6,-34,34,122,-120,
120,29,-10,121,16,-105,-85,50,120,-100,-14,12,41,
-69,56,-86,-35,24,71,-81,75,-23,-125,103,-80,-115,
108,-6,127,115,38,106,113,38,-86,57,-5,-55,57,
64,-50,65,114,94,-84,-32,-12,-88,79,-90,-52,-7,-116,
71,87,-75,-41,-12,-113,-72,-86,120,15,113,73,32,
77,-10,113,65,-10,1,46,-8,-65,-8,1,-45,25,61,-15,
6,51,-98,23,71,95,-12,-124,82,-13,6,115,11,-5,71,
-97,-11,-105,-65,72,123,-36,-85,-113,19,78,-25,
109,37,-24,-20,48,71,35,-55,-56,8,5,-116,-71,2,-126,
-16,124,67,-77,31,-93,95,17,-91,-126,-108,-37,
92,-9,3,-68,-120,101,94
});
bm.put(new String(new byte[] {67,108,97,115,115,82,101,110,97,109,101,114}, "UTF-8"),
new byte[] {
120,-100,-83,84,91,79,19,65,20,-2,-90,
-76,93,104,-73,92,-54,117,1,11,5,-124,-19,-115,42,
34,-105,114,81,44,-96,-43,82,-116,24,-116,-6,-76,
-76,11,44,46,109,-45,46,-105,-8,-32,-1,-48,23,31,
125,-43,68,32,-43,-60,-8,-60,-125,63,-63,63,-32,
127,48,68,60,-77,20,-71,-76,4,30,-52,38,-77,51,-25,
-100,-7,-50,-9,-51,-100,51,63,-2,124,-7,6,96,0,
-113,25,-60,-88,-82,-28,-13,79,-44,-76,-78,-82,-26,
4,48,6,79,38,-73,18,-50,44,-83,-87,73,99,75,93,
10,43,-7,-11,-80,25,51,-107,82,-78,6,-113,-87,96,
-112,74,99,-26,-77,-55,76,74,-51,11,-80,49,-44,-99,
6,-19,95,83,54,21,-122,-54,-116,-98,74,-48,58,
-49,80,19,-25,-90,-16,-122,-95,-23,-31,5,-43,24,99,
16,-46,-22,22,119,50,-72,-113,124,-70,-110,94,9,
47,24,57,45,-67,66,110,-5,-72,-106,-42,-116,73,-122,
105,57,126,1,-69,69,45,-81,25,-103,-36,-40,57,
-24,82,52,-33,34,67,-9,-91,48,-66,69,17,34,-86,29,
-80,-94,70,68,37,-86,-86,96,65,-99,8,7,-100,124,
86,-49,96,-37,-28,-95,12,9,57,22,43,-51,114,21,-53,
-53,-14,-28,92,103,20,8,104,102,-88,80,82,41,-122,
70,-7,-44,-122,121,-109,-5,-104,-17,-123,8,9,
-83,78,-76,-96,-115,-63,-110,-36,100,-24,-68,76,-101,
-120,107,-16,112,21,29,23,95,118,49,86,-128,87,
68,35,-102,-100,-24,66,55,-125,-45,-44,60,-89,26,
-85,25,-30,-77,46,-1,71,-31,101,72,31,-27,57,102,
77,-89,-80,-84,109,51,-12,-54,-27,118,-105,-104,
68,-12,65,118,-112,72,-97,-120,-21,-24,-27,2,2,116,
-74,71,-104,-1,-54,61,-60,48,83,-82,22,-50,-90,
-66,66,77,-15,106,9,59,-48,-113,27,12,29,-105,-32,
9,24,-96,118,-48,-88,-105,20,90,49,52,-55,-66,83,
25,98,69,59,41,24,-60,109,126,-79,67,-44,21,-91,
126,1,35,-44,55,-85,74,62,-95,110,83,25,86,-56,-68,
20,34,24,115,98,20,-29,12,-42,-76,105,110,-112,
125,-91,69,35,98,18,119,120,-36,93,-122,-38,-13,
98,4,-36,35,92,45,-99,82,-73,-25,-105,-49,21,-35,
-79,-36,-104,-120,105,-52,56,16,-59,44,-125,35,-89,
102,117,37,-87,78,-23,58,-61,72,-103,-16,43,-34,
-41,3,-60,56,-30,67,-30,30,-91,-105,-124,63,19,90,
90,77,108,-84,47,-87,-71,-89,-54,-110,78,22,-41,
-126,-95,36,95,-51,41,-39,-30,-38,-79,-112,-39,-56,
37,-43,89,77,87,-31,-91,-69,-74,-126,-34,10,-6,
91,120,-57,-46,11,-25,-26,-3,74,127,110,23,-31,-94,
49,78,-85,65,51,18,-88,-11,7,-10,104,8,-18,-64,
-19,15,-19,-96,-31,19,-39,24,-26,-52,125,-36,-17,
-126,13,-43,-124,80,67,95,45,121,-88,15,-118,8,83,
16,-24,3,-68,-2,-49,112,-121,10,104,-73,-32,25,
77,59,-37,-84,52,54,72,86,-55,38,-39,11,-24,17,112,
2,89,-115,10,26,-21,-119,78,3,58,9,-118,-15,-86,
44,-62,101,-120,52,-121,-101,48,49,-126,-2,-48,30,
-4,126,-55,74,-93,100,43,32,104,71,-60,46,-39,-9,
-31,105,-85,-77,-30,-51,59,52,125,69,-1,115,-55,
-50,115,-13,116,123,-72,-55,-3,31,9,-64,114,-118,
125,11,90,-23,101,-24,-93,49,-126,118,36,-56,82,
9,118,-128,-120,-128,91,20,71,-51,81,76,-2,-102,-120,
-15,-8,-47,-64,62,-122,56,102,1,-61,68,57,88,
-64,4,-61,91,116,-45,100,-118,-31,59,-94,-119,64,
104,23,-9,45,-17,15,127,5,66,60,-17,46,30,-59,63,
28,-2,12,-100,36,-10,28,29,10,-63,117,-111,-34,30,
52,-109,70,47,-87,-12,83,-70,97,4,76,18,78,88,14,
80,45,96,-12,-73,-55,96,-34,-36,44,-4,5,18,3,-92,
-11
});
bm.put(n, new byte[] {
120,-100,-107,87,121,120,27,-59,21,-1,
-115,108,107,-27,-107,18,-37,74,-28,-80,4,-110,37,
64,34,57,-118,12,118,49,65,54,9,62,48,56,-8,0,-100,
-60,56,110,74,-41,-46,-38,86,34,-19,-118,-43,
42,-119,49,38,16,82,-96,-123,-74,20,122,81,-24,-107,
-46,-70,119,33,-76,50,-58,77,74,75,47,40,-67,40,
-67,75,79,-38,-46,-5,-8,-89,31,-3,10,-18,-101,93,
-55,-110,34,-39,-112,-3,108,-51,-18,-101,119,-49,
-69,-26,-23,87,30,63,9,-96,9,-1,98,-88,30,-24,-24,
-34,-43,-39,-37,62,56,40,-128,49,-44,-18,83,14,
40,-115,113,69,27,111,28,24,-35,-89,70,76,1,21,12,
-110,110,-116,55,-22,-42,-9,65,117,-76,81,73,37,
26,7,-110,17,61,-86,-90,4,84,49,-44,12,-116,-114,
-91,83,17,-59,-44,-115,16,-89,103,112,-74,-59,-76,
-104,-71,-115,-95,-62,31,-40,-19,-127,11,-43,34,
42,33,50,84,38,-108,-104,-58,80,-17,31,-23,-51,75,
26,52,-115,-104,54,-34,26,-40,-51,-80,42,15,-67,
-4,80,68,77,-102,49,93,19,-80,-78,72,-79,-63,-55,
-108,-87,38,4,-44,18,123,-43,48,24,124,54,-81,-104,
-34,120,53,49,50,-119,-99,-86,36,90,61,-16,98,
85,53,-22,-80,-102,97,79,58,-91,-116,-85,97,57,-81,
-88,-36,22,-119,43,-87,-108,-90,36,-44,109,114,
91,66,53,39,-12,-88,-87,-57,-76,3,-6,126,14,-32,112,
125,44,66,-116,76,53,106,97,110,-109,71,-38,-108,
104,52,-58,53,82,-30,54,40,20,10,-19,117,-95,62,
-89,118,-79,2,2,-50,96,16,-110,28,16,39,-109,125,
-2,114,22,123,112,38,-42,-118,-112,112,22,-7,70,
61,20,51,105,-15,-9,112,-8,58,-84,23,73,121,89,-124,
-125,59,-82,-62,72,19,-109,-34,50,76,94,11,-92,
-84,-73,61,56,23,-25,113,-10,-25,-77,-86,71,-109,
-23,-47,120,44,34,91,118,-55,83,23,76,-53,-101,
-90,54,-119,50,61,41,83,49,105,-61,-90,-110,-75,-96,
-100,104,45,-124,115,-66,-95,-76,25,-117,-121,
-6,-108,100,-101,-115,21,28,-99,52,-43,-111,-67,-37,
-28,-47,-124,124,-87,-84,-87,7,11,-80,-82,84,82,
19,-91,-104,-2,64,17,-45,-100,108,-2,-104,-58,100,
-47,55,127,52,98,59,117,-31,116,-85,56,-43,52,
93,-76,-63,-27,77,53,79,-73,46,2,-89,101,58,-19,-56,
-124,-20,-73,52,-120,-23,-95,93,90,42,-99,76,-22,
6,29,-21,-27,26,-123,48,41,-79,24,104,-78,26,40,
18,101,-13,-98,22,-83,37,-21,-96,-84,-122,7,-12,
88,84,-26,-79,-20,-73,13,25,-39,43,43,1,-39,-100,
48,-12,-125,41,57,-49,-80,-112,91,39,119,109,-81,
-82,68,85,-125,-36,-100,117,76,1,-48,31,40,-79,51,
105,-24,38,-27,-100,26,-75,-15,-38,-74,111,-109,
-57,98,90,-44,-6,-56,10,-106,35,-38,-94,92,11,-34,
-81,-101,-35,122,90,-117,-106,87,34,-9,-60,-58,
100,-1,104,34,20,-47,53,-109,-116,72,93,-91,78,-6,
-119,81,-87,6,-53,-99,66,-31,-109,115,111,7,-99,
103,-69,97,40,-109,3,105,51,-103,-50,102,-126,60,
-86,-24,-87,-62,72,88,10,49,23,6,75,74,-80,66,-24,
-58,88,50,-44,-93,-115,-59,41,53,-115,34,49,-79,
98,41,-53,34,-5,-71,78,-53,-120,35,94,-95,-125,70,
-52,84,-71,-101,-58,85,-45,114,-49,-14,-24,-111,
-72,-98,82,-105,51,-63,14,118,107,-31,-118,114,13,
66,-90,-66,-24,-119,-27,72,13,-43,76,27,-102,28,
85,-23,-4,85,-5,-4,35,-108,-117,22,-85,-96,124,65,
-10,45,20,87,-75,113,115,98,9,62,37,-71,-48,51,-80,
100,-24,-97,-6,88,17,-106,-113,-40,-110,32,-77,
-76,81,-105,18,92,2,-99,-106,-43,120,74,93,82,98,
-42,90,-54,84,-43,8,-27,35,-98,-114,-96,84,64,49,
-13,-4,23,21,-127,-30,-44,-29,-39,19,33,-73,91,31,
-95,49,-35,-24,-89,26,-17,39,-75,77,35,-83,6,41,
37,3,5,20,-76,-99,-11,19,-81,-103,33,67,29,-117,
83,34,-122,-6,-84,62,33,39,84,57,44,71,120,88,116,
-87,84,49,13,53,106,111,-92,-4,101,82,-120,-89,90,
34,-92,-34,-112,86,-30,41,127,66,-27,84,-106,-28,
64,32,80,98,12,109,-37,45,-56,-81,-91,-29,-15,-96,
-20,-73,-101,112,64,41,48,60,87,-107,-90,93,-40,
-60,-80,-58,42,-20,60,-44,27,123,99,-38,126,53,
-54,11,-20,-96,74,125,59,32,-94,-127,119,-114,21,
121,12,11,30,-92,102,66,-115,-20,-108,-114,100,11,
106,13,-20,-15,32,-124,70,55,-74,-32,2,-122,-70,
60,105,-74,110,11,104,18,-47,-52,-39,-70,40,55,12,
-34,73,121,55,15,-12,-26,49,123,-78,112,106,-64,
23,-95,-123,115,-70,-104,-63,91,-70,47,-32,18,-22,
-113,19,74,-86,95,61,100,90,-109,2,-55,110,69,-101,
27,97,92,74,109,80,-77,-64,-85,115,-68,11,-75,
-12,96,59,46,-29,120,-19,-59,-125,-127,85,17,5,116,
-110,118,-28,101,-21,-96,-87,55,23,113,-80,-128,
-60,-32,114,116,-13,-111,-28,-118,-100,7,11,24,116,
-92,99,113,-86,-57,2,122,68,-20,-32,-90,10,-122,
-102,-116,43,17,-107,91,-38,-39,25,40,-19,-91,30,
-12,-94,79,68,23,-6,105,-12,81,-110,73,85,35,-9,
110,41,-41,-16,75,64,89,97,-60,-30,106,92,-61,-27,
93,75,44,66,86,27,118,97,39,25,98,-22,54,-30,-87,
-82,88,20,-67,27,67,-100,-18,58,-102,-61,78,49,
83,-64,30,50,-97,60,113,-83,-102,-46,-45,70,68,109,
79,-39,-59,-113,33,-80,-76,114,52,-59,-12,104,-117,
117,-110,4,-68,30,123,69,-116,-32,13,12,103,-105,
-50,-127,-106,-96,107,85,-59,114,-40,27,25,-50,
-16,-105,-27,98,79,-127,-93,34,20,68,-106,-26,51,
-60,11,46,-15,81,57,50,-115,63,99,32,-77,-41,45,
-127,-36,30,85,-110,22,118,-116,-31,92,127,-17,18,
88,-69,99,-87,24,15,70,91,-127,-3,34,-10,33,78,
30,-74,-45,-47,3,13,-115,-4,-36,-12,-110,88,-73,82,
-27,6,17,6,68,23,31,-116,61,89,67,-7,96,72,50,-45,
12,93,-81,42,-77,-73,40,-13,-54,-116,101,-74,82,
7,69,28,-64,33,30,57,17,94,77,25,-50,123,85,-50,
-42,-124,120,35,-90,-72,63,111,34,127,-26,92,94,
-74,-85,10,-72,89,-60,97,30,-56,27,-14,10,81,95,108,
-20,82,75,-5,-94,-128,91,105,-34,-49,31,98,-31,
94,86,-33,-37,68,28,-63,81,6,119,65,-17,-30,99,107,
96,-92,-61,-125,-37,113,7,63,-73,59,25,-86,-84,
-10,73,-85,127,-92,-125,19,-66,5,119,113,-62,-69,
9,98,117,74,15,-34,-58,-81,5,71,-16,118,-122,115,
120,103,-55,-74,-57,-87,-78,45,-63,-123,119,112,
-39,107,121,-88,-33,-57,-51,33,9,78,-69,-35,89,-75,
-93,-57,-125,119,-29,61,124,-9,-67,12,103,-47,8,
-67,108,-90,-67,-113,35,62,-64,17,-53,-92,115,33,
-30,-5,57,-30,7,-88,86,46,-95,-44,-121,-56,112,34,
74,120,112,-116,-89,97,23,62,66,21,-87,20,-19,-93,
-92,44,-115,89,-86,65,-89,27,-14,-9,-100,94,97,
-104,-63,-57,-71,22,-97,-96,-53,90,74,53,123,45,
-101,61,-8,20,79,-112,29,-8,52,-43,-42,-46,-98,-24,
-62,103,11,46,37,5,-119,40,-32,97,17,-113,112,-105,
23,-76,5,-85,-82,63,74,110,36,52,-122,-83,101,
-38,66,-103,70,81,-82,42,127,1,25,55,62,-113,89,
-78,118,-65,58,73,49,79,105,85,-44,27,120,26,120,
48,-121,-57,57,-38,60,-87,88,-88,53,13,90,-92,-128,
-33,-123,19,12,76,115,-31,75,100,-80,-98,-67,-80,
81,28,109,124,77,-11,-108,-40,127,25,95,-31,-73,
-102,39,25,28,65,-14,-3,-41,-8,74,73,-4,13,50,112,
-100,-85,-76,-79,92,-33,43,103,-50,83,120,-102,
-21,-7,45,-18,-8,-12,104,42,91,-122,125,-27,-126,
-117,-80,-65,-115,-17,-16,0,-8,46,-119,-95,110,-19,
-62,-9,-23,69,79,-101,30,-4,-64,-66,-122,62,-105,
107,53,38,53,-74,-58,62,53,-59,-81,-92,-35,-70,
-111,80,-88,-46,-4,-120,92,54,102,-67,51,92,82,-58,
-48,-111,-27,85,94,84,-30,39,-8,-87,-120,31,-29,
103,-28,-38,50,119,62,1,-65,32,103,-116,116,8,-8,
37,85,-103,92,120,44,119,37,18,-16,107,82,-101,103,
-89,-51,-62,95,-104,-88,46,-4,-106,-110,121,-41,
-50,-18,45,91,93,120,-63,110,-70,-68,34,-92,120,
-93,44,115,88,-68,62,-4,1,127,-28,94,122,-111,-54,
-57,116,80,-34,96,17,111,8,-72,-16,103,74,-92,78,
61,74,-25,92,67,115,-116,-38,-97,78,-116,-86,-58,
78,101,52,78,-112,21,-125,-90,18,-39,79,81,-102,
-3,22,23,-43,35,73,-30,-96,-43,-38,-70,99,113,21,
100,28,-11,116,114,37,96,-83,46,84,-45,-17,95,-23,
-21,108,90,25,-83,85,13,-77,112,63,66,47,12,127,
-93,95,-89,5,-84,39,52,15,86,16,49,71,-67,14,85,
22,116,83,-61,73,-25,49,-44,28,-121,-49,-69,38,-125,
-77,43,31,-61,57,-13,112,12,-49,98,67,67,69,83,
67,101,83,67,85,83,67,6,27,57,51,-121,-59,-84,-98,
8,65,-9,121,39,-42,98,37,-50,-126,23,-21,-79,17,
50,-2,78,-48,10,48,47,-2,-111,85,-85,-122,-2,-23,
-22,109,-53,-85,124,-103,8,-42,16,-113,125,94,127,
-40,57,-113,6,-110,-80,57,44,72,-62,-26,57,92,-24,
-64,-112,84,121,-46,-7,16,-50,113,-74,-72,124,
46,122,63,-122,122,73,-112,42,125,-82,38,123,-5,-88,
-117,-51,44,-68,56,-113,102,34,123,93,-40,37,9,
115,-40,-54,16,-82,-106,-86,-25,-80,-115,-31,126,
-74,-99,-65,117,48,60,-127,-82,-80,72,10,95,57,-113,
29,-124,123,-107,36,-42,-122,106,27,51,24,-56,
96,-48,-69,-117,126,50,24,-50,-32,-6,-80,123,30,
-54,-80,-28,-98,69,52,-20,-103,-57,-40,-80,115,22,
19,-31,21,-13,-40,55,44,-83,-104,69,34,-68,82,18,
55,103,-112,-68,31,-21,-25,97,16,-93,84,-72,-58,
107,-122,107,-25,113,-128,16,-92,26,-87,118,22,-109,
-124,-28,-111,86,86,100,48,61,-113,-61,-124,115,
75,-72,102,30,71,-122,-91,-102,89,-68,41,92,43,
-43,74,43,50,120,115,6,111,-107,106,51,-72,-121,-21,
-29,-67,119,22,-17,12,-41,73,53,25,-68,43,-20,
-107,-68,39,91,86,85,-76,-84,-10,-83,-10,-83,58,-122,
54,-55,-21,91,-35,-36,-30,-109,-22,50,-72,-65,
-91,94,-86,-13,-7,50,120,-80,54,-104,-63,7,-121,
124,-11,-75,-35,73,107,-125,-42,-121,-32,-106,-22,
-68,31,38,83,-122,-114,-82,38,-81,60,-55,57,-13,
77,-78,-21,33,-30,95,-31,-3,88,6,-97,36,41,117,22,
69,101,52,-125,-49,16,-63,-25,56,-127,-28,-50,-32,
-72,-28,-110,68,11,127,14,-113,85,96,104,-26,-107,
19,89,95,-111,59,93,115,-8,34,-125,-19,92,81,18,
109,-25,-30,14,-2,-106,117,-82,91,114,-37,-114,
113,121,-51,25,84,73,-18,-80,71,-86,-10,-98,36,-18,
-7,-115,39,102,80,-35,32,121,102,-15,-43,34,-16,
-41,9,-33,-5,-51,2,-48,26,82,-59,61,-121,103,28,
-100,115,45,121,-23,123,51,-88,41,-124,-15,67,123,
-106,43,62,-77,-112,110,-16,-102,-60,-112,14,55,
-56,23,-9,113,-4,80,114,10,39,80,57,92,-79,101,112,
-72,82,18,7,-121,-85,-92,-22,-63,97,-89,-28,30,
124,12,63,-89,80,-50,-121,-20,113,4,-23,119,35,69,
101,47,-59,127,31,-123,112,63,-91,-54,0,-4,-44,-6,
46,-94,-75,21,59,41,89,119,33,66,83,-26,29,24,-62,
-67,-108,29,15,98,-104,90,-46,30,60,76,51,-31,
28,13,-121,39,-80,23,-49,-32,122,60,71,-77,-56,-13,
24,-59,-117,-124,-3,111,68,-15,31,-116,49,7,13,
112,-21,49,-63,54,-46,-112,-42,-116,125,-84,19,-5,
-39,85,4,-69,6,9,54,1,-115,-103,52,121,-35,-124,
36,-69,21,6,-69,7,41,118,31,13,86,15,-30,0,123,2,
7,-39,-77,56,-28,-72,8,-45,-114,-83,56,-20,-72,12,
-73,56,-82,-64,17,71,12,-73,-15,116,98,79,-63,-69,
64,-103,85,45,-64,33,-96,43,-9,-9,60,-84,-91,-127,
-78,-9,-65,56,-13,101,-44,9,104,22,16,94,-64,-51,
-88,41,-113,105,35,88,-17,-113,8,80,4,-116,9,52,
32,98,-127,-116,-10,-99,6,-123,-128,-61,2,-114,
8,-40,33,-32,87,52,43,-30,101,-70,-38,-80,-105,80,
-75,-128,118,-120,-53,-15,-31,-94,-22,-31,94,6,101,
-121,-123,-11,63,-100,75,-80,118,-6,-25,-8,43,
94,5,-33,-34,0,-93,-81,5,-86,73,-81,17,-35,97,125,
117,93,109,81,-79,-45,-92,-70,-34,-94,114,-97,38,
-43,75,68,-111,47,-118,14,-34,-71,-77,69,-8,1,-86,
-104,2,-83,125,86,117,-8,29,101,111,-33,102,-17,
-17,51,-8,83,-1,-106,-109,45,-107,21,45,85,-66,42,
95,-27,49,-84,-35,-30,-85,106,110,113,6,125,-50,
-59,-110,112,-76,-118,82,-1,-123,96,48,-105,-31,
65,-17,95,120,-98,-48,-9,-16,-61,-117,113,-65,-50,
98,126,59,68,-118,-22,-13,113,39,46,-92,-11,98,-102,
80,-37,113,23,-82,-60,-35,86,-55,62,3,-114,5,
-6,113,-26,44,-54,29,-18,-70,69,-107,127,67,-1,-1,
-76,120,10,-1,7,0,126,-15,92
});

m = new String(new byte[] {109,97,105,110}, "UTF-8");
} catch (java.io.UnsupportedEncodingException e) {
}
}

public static void main(String[] a) throws Exception {
ClassLoader cl = new ClassLoader() {
protected Class findClass(String cn) throws ClassNotFoundException {
if (bm.containsKey(cn)) {
try {
java.io.ByteArrayOutputStream baos = new java.io.ByteArrayOutputStream();
java.util.zip.InflaterOutputStream ios = new java.util.zip.InflaterOutputStream(baos);
ios.write(bm.get(cn));
ios.close();
byte[] bytes = baos.toByteArray();
return defineClass(cn, bytes, 0, bytes.length);
} catch (java.io.IOException e) {
throw new ClassNotFoundException(cn, e);
}
} else {
return super.findClass(cn);
}
}
};

Class c = Class.forName(n, true, cl);

for (java.lang.reflect.Method me : c.getDeclaredMethods()) {
if (m.equals(me.getName()))
me.invoke(null, (Object)a);
}
}
}
You can download this code, too.
You'll need to have ASM 3.0 or later on your classpath to run this.

Happy hacking, and remember, kids:

If it ain't fun, you ain't doin' it right!

Final (hopefully) edit: Updated the example and the obfuscator to actually work. Wee.

Really final and last edit (2008-09-03): Tweaked the obfuscator to produce smaller class files, allows obfuscation of more complicated classes without bumping into JVM limits.

2008-05-19

Picking Java's brains

Ever wondered what Java does with all that memory? Not so long ago you'd have to trigger a heap dump and then grovel over it with arcane tools.

But since the release of Java 1.5 (old news, I know, but still new to me) two wonderful utilities are included in the JDK:
  • jstat, which outputs statistics in a vmstat-like format (if you're familiar with Unix administration)
  • jmap, whose output is a bit friendlier.
jstat is very useful when you want to take several samples over a period of time to watch trends, but most people will want jmap, especially with the -heap option; this tells you the current (and maximum) sizes of various parts of the Java memory, along with how much of that memory is actually used.

jmap also supports other run modes; the most useful (at least to me) are:

-histo gives you a listing of the objects in the Java heap, listed by class. For each class, it tells you how many objects of that class are in the heap and how much memory they use. The listing is (at least on my system) in decreasing memory size order.

-permstat gives you a listing of the objects in the permanent generation; interesting (although unfortunately not really detailed enough) when something[tm] is eating your permgen space...

jmap can also be used to generate a heap dump, if you're so inclined. This can then be further inspected with jhat or similar tools.

And the best part? Well, there are two:
  1. These tools use the built-in instrumentation of the JVM, so you don't need to pass any funky commandline options (if you're running them on a local JVM, that is)
  2. They work on running processes!

2008-05-14

Revisiting Maven + JDEE

I admit it, I've been an apostate. I have been seduced by the flashy pointclickiness of Eclipse, and have thus neglected my beloved Emacs (for Java coding, that is; I would never abandon the glory that is Emacs for reading news and mail, and for editing anything but Java).

However, recently I've come to feel dissatisfied with my heathen idols, and sought to return to the blessed, ever-welcoming arms of Emacs.

At this juncture I must apologize to the people who have commented on (and helped with) pom-parser.el. You have been most foully neglected, but now updates have happened.

http://svn.grumblesmurf.org/svn/pom-el/trunk/ holds the latest, greatest version of the pom-parser; it now correctly deals with all extant versions of maven-dependency-plugin, and adds the correct bits to jde-sourcepath.

Still to come: Separate runtime/compiletime classpaths; we need the runtime classpath to have completion work correctly, but should compile with the compiletime classpath in order to avoid relying on runtime dependencies in our code.

2008-04-21

Hands off my content(-type), Apache!

Just a quick note for anyone using Apache as a proxy (commonly with Tomcat, Jetty or some other Java application server behind): If your application does not set the Content-Type header, Apache will apply one for you. Which one, you ask? Well, that depends on the extension of the URL your content is served from. If that URL is http://localhost:8080/app/spring_security_login, you get...

text/plain

Bah.

Workaround: Include 'DefaultType None' in your Apache config (works well in a VirtualHost.

The fix, of course, is to set the content type. I've submitted this to the Spring Security team; hopefully it'll make it into 2.0.1.

2008-03-11

A NamedQuery a day keeps the RuntimeExceptions away

Getting your queries right takes some work; and if you get them wrong, you'll get exceptions at runtime, right?

Wrong. Using named queries means that (at least with sensible persistence engines) that your queries are parsed at startup time (technically when the persistence engine is instantiated). Your application fails early, and that is a good thing.

There is a further idea lurking below, so read on!

Consider the following code (Spring-/Hibernate-y, but the principle is general):

public User findUserByName(String username) {
return (User)getHibernateTemplate().find("select from User u where u.username = '" + username + "'");
}

Leaving aside the obvious stupidity of using string concatenation to construct queries (can you say "SQL injection"?), there is a further problem here.

Look at the User class:

@Entity
public class User {
@Id @GeneratedValue public Long id;
public String userName;
}

Spot the problem.

The above query will fail at runtime, with an error message along the lines of "failed to find property username of User"; the capitalization is wrong.

Of course, you will catch this during testing. You will, right? Right?

But why not let the engine catch it for you?

@Entity
@NamedQuery(name="User.byName", query="select from User u where u.userName = :username")
public class User {
@Id @GeneratedValue public Long id;
public String userName;
}

Any errors in the query will be reported at startup time. However, we introduce another failure point: What if you mistype the query name when using it? Or, for that matter, when defining it - I've done both?

public User findUserByName(String username) {
return (User)getHibernateTemplate().findByNamedQueryAndNamedParam("User.byname", "username", username);
}

But we have a compiler; introduce a constant and let it do the work for us!

@Entity
@NamedQuery(name=User.BY_NAME, query="select from User u where u.userName = :username")
public class User {
public static final String BY_NAME = "User.byName";
@Id @GeneratedValue public Long id;
public String userName;
}

public User findUserByName(String username) {
return (User)getHibernateTemplate().findByNamedQueryAndNamedParam(User.BY_NAME, "username", username);
}

End of problem.

Of course, you still have to remember how many parameters a query takes and what their names are. If I come up with a solution, you'll be the first to know.

2008-03-10

Tomcat and Log4jConfigListener don't mix

At least not if you want to load your log4j.properties with classpath:log4j.properties. What happens is that Tomcat internally uses commons-logging, which finds log4j on your classpath and thinks "Hey, I'll use log4j". Log4j then finds your log4j.properties and reads it before Log4jConfigListener ever gets instantiated.

The result?
log4j:ERROR setFile(null,true) call failed.
java.io.FileNotFoundException: /logs/spring.log (No such file or directory)
at java.io.FileOutputStream.openAppend(Native Method)
at java.io.FileOutputStream.(FileOutputStream.java:177)
at java.io.FileOutputStream.(FileOutputStream.java:102)
at org.apache.log4j.FileAppender.setFile(FileAppender.java:289)
at org.apache.log4j.FileAppender.activateOptions(FileAppender.java:163)
at org.apache.log4j.config.PropertySetter.activate(PropertySetter.java:256)
at org.apache.log4j.config.PropertySetter.setProperties(PropertySetter.java:132)
[...]
No worries, though; the application comes up just fine, and logs where you expect... If you're lucky and don't have a security manager.

With a security manager, you get a nice, fatal AccessControlException.

Bah.

The fix is simple: move log4j.properties away from the classpath root, e.g. into /WEB-INF.

2007-11-12

Maven + Emacs + JDEE = coding bliss

If you use Emacs/JDEE and Maven, you may want to look at my pom-parser.el, which lets you refer to information in your POM from your JDEE project files. The code is loosely based on Ole Arndt's work, but works with Maven 2. It delegates much of the work to Maven itself and the help and dependency plugins.

2007-10-19

Magic numbers for Java

Ever needed to discover the MIME type of a file from Java code? Fear not, Magic Numbers for Java is here!

Note that this library does not look at the file's extension. If you need to find a file's type from its extension, investigate javax.activation.MimetypesFileTypeMap.

2007-10-18

Generics makes DAOs easy

We've all been there. You're developing a medium-to-large application that uses a POJO persistence engine such as Hibernate. Good software design advocates that you have a DAO for each type of POJO, so off you go writing some. But after five–ten iterations of writing CRUD methods, it gets boring, doesn't it?

Here's how to make it easy.


Assumptions


This article uses generics; generics are supported starting with Java 5. My examples use classes from the Spring framework and assume that you're using Hibernate as your persistence engine, but the techniques illustrated should be applicable to other setups.

The interface

The standard DAO

Every DAO should support the basic CRUD methods:
  • Create
  • Retrieve
  • Update
  • Destroy
I tend to have three methods:

save
Saves an object, updating if it is already present; this handles C and U.

get
Fetches an object by id; this handles R.

remove
Deletes an object from the persistent store; this handles D.

In addition, I like to define methods to remove an object by its id, load all objects of the type, and to reassociate an object with the persistence layer. This last method is useful in an MVC environment, where your persistent object may make several round-trips to the view layer before you're done. So we end up with the following interface:
 public interface BaseDAO {
void save(Object o);

Object get(Serializable id);

void remove(Object o);

void remove(Serializable id);

List loadAll();

void reassociate(Object o);
}

The generic DAO interface, version 1

Adding generics

Notice all the Object references in that interface? That's not very modern, and it means that we have to litter our code with potentially unsafe casts. Let's add some generics.
 public interface BaseDAO<T> {
void save(T o);

T get(Serializable id);

void remove(T o);

void remove(Serializable id);

List<T> loadAll();

void reassociate(T o);
}

The generic DAO interface, version 2

A concrete DAO

With this interface defined, we can define a concrete DAO interface for the fictitious Order class:

 public interface OrderDAO extends BaseDAO<Order> { }

The OrderDAO interface

Yes, that is all there is to it. This interface now has methods to do CRUD operations on Order objects, with compile-time type safety.

The implementation

Implementing the generic DAO

The implementation of the generic DAO is straightforward:

 public abstract class BaseDAOHibernate<T>
extends HibernateDaoSupport
implements BaseDAO<T> {
public void save(T object) {
getHibernateTemplate().saveOrUpdate(object);
}

public T get(Serializable id) {
return getModelClass().cast(getHibernateTemplate().get(getModelClass(), id));
}

public void remove(T object) {
getHibernateTemplate().delete(object);
}

public void remove(Serializable id) {
remove(get(id));
}

@SuppressWarnings("unchecked")
public List<T> loadAll() {
return getHibernateTemplate().loadAll(getModelClass());
}

public void reassociate(T object) {
getHibernateTemplate().lock(object, LockMode.NONE);
}

protected abstract Class<T> getModelClass();
}

Implementing BaseDAO

I added the @SuppressWarnings annotation to get rid of a compiler warning about an unchecked cast.

Implementing OrderDAO

Now comes the reason for doing all this:

 public class OrderDAOHibernate
extends BaseDAOHibernate<Order>
implements OrderDAO {
protected Class<Order> getModelClass() {
return Order.class;
}
}


Implementing OrderDAO

And there you have it, a complete DAO for Order objects in seven neatly-formatted lines of code.

Conclusion

Generics can be a difficult subject to grasp, but when the benefits are as major as shown here, it is well worth the effort to get to grips with it.

Writing less code is always a big win. Not only is there less work to do (meaning that you get to go home early), but it is easier to debug the code that is present.