The Source for Java Technology Collaboration
User: Password:



Graham Hamilton

Graham Hamilton's Blog

My Favorite (Dead) Java Boilerplate

Posted by kgh on November 13, 2005 at 04:03 PM | Comments (31)

In the Java platform we have tended to focus on adding lots of power and flexibility. That's great, but sometimes that power and flexibility can get in the way of doing common tasks. As part of the Ease-of-Development initiative we have been focusing on simplifying common tasks and getting rid of unnecessary boilerplate code.

Here are my five of my favorite cleanups so far:

#1: Opening a Text File

In JDK 1.1 to 1.4, in order to open a simple text output file you needed to do:

    FileWriter fout = new FileWriter("fred.txt");
    BufferedWriter bout = new BufferedWriter(fout);
    PrintWriter pout = new PrintWriter(bout);

Say what? Why are we having to type three "new"s in order to do what should be a simple operation?

In Tiger we have finally added direct support for the common case and now you can do:

    PrintWriter pout = new PrintWriter("fred.txt");

This is an interesting example of a common glitch in our thinking. In the Java platform we often like to provide lots of well designed, well separated components that can be plugged together in interesting ways. In fact some people might argue be that the design is cleaner if the PrintWriter class doesn't know anything about files. Well, personally, I don't think so. I think it is good to provide clean, well separated components, but we also need to provide simple shortcuts to support the most common use cases.

#2: Avoiding the Content Pane Pain

In JDK 1.1 to 1.4, if you wanted to add a Swing GUI component to a container you simply said container.add(component). Well, yes, except that if the container happened to be a JFrame you would get a helpful runtime exception saying that you ought to be saying

    frame.getContentPane().add(component);

Umm, say what? Rather than raising the exception, couldn't the JFrame.add method itself call JFrame.getContentPane().add()? Yes it could. And in Tiger it does. Now you can just call add, as you would with any other container object.

    frame.add(component);

This only saves a few keystrokes, so is this really a big deal? Yes. The real saving is that you can avoid having to learn a whole new unnecessary concept. The reason that the JFrame.add method originally threw an exception was because JFrames actually support three different panes (content, glass and root), and it was considered important to educate developers about those choices. Well, I've written various Swing applications over the years and I've never actually found the need to exploit the various different panes. The old behavior of JFrame.add forced me to go away and learn about panes. And that was distracting and unhelpful. The lesson here is that (once again) it is normally better to provide simple sensible defaults and to avoid forcing people to learn about complex options.

#3: Self Registering JDBC Drivers

Since JDK 1.1, in order to load a JDBC driver, you needed to do:

    Class.forName("com.fred.FredDriver");
    Connection con = DriverManager.getConnection("jdbc:fred:fredsite.com");

Umm, what exactly is that Class.forName doing there?

This one is my fault. Back in the early days of JDBC, we needed a way for the JDBC DriverManager to locate drivers. We arranged that newly loaded driver classes would register with the DriverManager. And then we asked that developers call "Class.forName" to force the driver class to be loaded. Mustang.gif

Sigh. This is an ugly wart. I'm happy to report that this one is going away as part of JDBC 4.0 in Mustang. The JSR-221 Expert Group is adding a new mechanism so that the JDBC DriverManager can locate and load driver classes without the need for developers to explicitly type Class.forName. So you will be able to just do the obvious:

    Connection con = DriverManager.getConnection("jdbc:fred:fredsite.com");

#4: Locating Resources in J2EE

In J2EE 1.4, if you wanted to locate a reference to a remote EJB you needed to type:

     Context context = new InitialContext();
     Object obj = context.lookup("fred");
     FredHome fred = (FredHome) PortableRemoteObject.narrow(obj, FredHome.class);

Yikes. What on earth is going on with that PortableRemoteObject.narrow? I have to confess that I'm one of the prime culprits here and, given some of the constraints, it may have been unavoidable. But I think this one definitely does win "Ugly Boilerplate of the Year".

As part of Java EE 5, there are now specific mechanisms for dependency injection, so you can now replace that code with a simple annotated field definition:

     @Resource FredHome fred;

And then the Java EE runtimes will take care of locating the resource, doing the "narrow" for you and injecting the resource object into your field. By default the resource name is inferred from the field name and the type is inferred from the field type.

This is an example of using JSR-175 annotations to restructure how we handle a common task so that it can become much simpler. I'm very excited with what is happening with annotations as part of Java EE 5 - I think it is allowing us to greatly simplify Java EE programming. And I'd like to find more ways to use annotations in Java SE, too.

#5: Iterating over Collections

My last example is from Tiger. We've all been used to typing some standard boilerplate for iterating over collections, such as:

    Vector<Wombat> v = getWombats();
    Enumeration<Wombat> e = v.elements();
    while (e.hasMoreElements()) {
	Wombat w = e.nextElement();
        ...
    }

Josh Bloch successfully argued for a language change to make it easier to iterate over both collections and arrays, so now in Tiger we can do:

    Vector<Wombat> v = getWombats();
    for (Wombat w : v) {
        ...
    }

We all knew this would be useful, but I have been really surprised by how much I have enjoyed using it, for both arrays and collections. This has turned into one of my favorite Tiger features. The resulting code is distinctly easier to read, partly because we have managed to eliminate an unnecessary local variable.

This is an example of fixing a boilerplate problem we barely realized we had. I'd like to find a few more things like this!

To be continued...

I'll continue this topic in my next blog.

  - Graham


Bookmark blog post: del.icio.us del.icio.us Digg Digg DZone DZone Furl Furl Reddit Reddit
Comments
Comments are listed in date ascending order (oldest first) | Post Comment

  • #1 is a useful enhancement, yet you still can't create a FileReader/FileWriter with a specific encoding, hence:

    InputStream in1 = new FIleInputStream(file);
    InputStreamReader reader = new InputStreamReader(in1, encoding);

    plus, potentially a BufferedReader/Writer...

    Posted by: scolebourne on November 14, 2005 at 06:54 AM

  • scolebourne ,

    Did you see the PrintWriter constructor that takes a file name and charset?

    public PrintWriter(String fileName, String csn)

    Posted by: rufus on November 14, 2005 at 07:56 AM

  • That's some really special code you've got there in those PrintWriter constructors.

    If the OutputStreamWriter throws UnsupportedEncodingException, OutOfMemoryError, NullPointerException or something else, then the FileOutpuStream is not closed. Nor is there any way for client code to close it.

    Posted by: tackline on November 14, 2005 at 09:09 AM

  • We used to have lots of boilerplate code for our applications like follows:


    IProcessingDialog dialog = ProcessingDialogFactory.createDialog(
    "Doing something","Some long message", getSomeIcon());

    Runnable task = new Runnable(){
    public void run(){
    try{
    dialog.open();
    // do some processing work
    doWork();
    dialog.setProgress(50);
    doNextWork();
    dialog.setProgress(100);
    }catch(Exception1 e){
    // show an error with bug reporting
    ErrorManager.getInstance().showErrorWithBugReport(e,
    "User explanation");
    }catch(Exception2 e2){
    // show some error without bug reporting
    ErrorManager.getInstance().showError(e, "User explanation");
    }finally{
    dialog.close();
    }
    }
    };

    TaskRunner.runInAppropriateThread(task);


    The above workflow is quite common when developing java applications and can easily be refactored to make it an easy one liner. If there was a standard mechanism (pluggable of course) that could be used to automate this workflow beginners would be much more inclined to make "safe" gui apps, enhancing the user experience of java apps in general.

    Another area is that of actions. We built our own Action factory for easily creating actions, which enables the simple creation of actions with icons, tooltips, mnemonics etc. Not only should it do this, but enhance user experience. For example, if you watch users interact with your applications you will find the odd user who always double clicks everything. This may wreak havoc in some circumstances, so you dont want your action to run twice. The action factory should make it easy to specify the minimum time between successive clicks. It should also handle disabling the action after it is clicked and while any tasks are running so the user knows it is unclickable or processing. Also, cursor management should be included. All the things that matter to users, and are possible with java but left up to the developer.

    The inclusion of boilerplate like this in the jre with smart defaults will drastically improve the user experience of java applications out of the box, and the development speed of beginning users in my opinion.

    Posted by: profiler on November 14, 2005 at 03:37 PM

  • How about dropping the need for generics in the new enchanced for loop. Really the compiler should be able to do the downcasting for me.

    regards,
    Kirk

    Posted by: kcpeppe on November 15, 2005 at 12:53 AM

  • Would like to second the comment by "profile"; but I would also like to add a comment about internationalizing Swing UI components. For each component you might have to make two or more method calls. Instead we use a class called ResourcePicker to apply the resources direct from the ResourceBundle using the Component "Name" property to look them up. You can see some more details in RFE 6313125.

    Also using the "Name" property allow you to create UI tests in tools such as Abbot that are locale independant.

    Posted by: gdavison on November 15, 2005 at 05:05 AM

  • Hi Graham,

    Groovy has a lot of features that boost productivity by making complex tasks simpler to achieve and simple tasks a breeze. Having real closures would make iterating over collections simpler without the need for additional artificial constructs (for loops). Coupled with some ruby style convenience methods, and strong autoboxing - the for loop could be replaced with the likes of:-

    int x = 10;

    x.times ({ count | System.out.println(" counting " + count)});

    and iteration over a collection

    map.each({key, value | System.out.println("key = " + key + ", value = " + value)});

    More powerful reflection utils would open up the possibility of developers producing simpler APIs for complex tasks. E.g. a mechanism for adding "virtual" methods to a class would enable groovy style builders in Java.

    An application-wide flag for converting Checked exceptions into RuntimeExceptions could be useful too. A large percentage of Java code seems to be cluttered boiler plate try/catch/finally code that rarely does anything useful with the caught exceptions.

    The Xml apis are powerful, but verbose. A simpler api for the 90% of simple day to day tasks would be appreciated - building an XML document and writing it as a string etc. Take a look at REXML for an example of how easy it could be. And while we're looking at files how about file.getText() - again from Groovy - as a convenvience method?

    It's great to see someone at Sun looking into this - after ten years Java needs to move up to a higher level of abstraction!

    Posted by: johnmcclean on November 15, 2005 at 05:17 AM

  • It's easy to create a default button on a JDialog that has it's action invoked when the enter key is pressed. Why not have an easy way of mapping a cancel button as well? This is an ease of use thing that would help out quite a bit.

    Posted by: rabbe on November 15, 2005 at 05:19 AM

  • Some small things:

    accessing the last element of a List:
    instead of using get(list.size()-1) add a simple method as: getLast()

    a simple filter method maybe (i did not think of the details of it)?
    public List filter(Comparator c)
    if the elements in the list complies the comparator result as 0, it returns a sublist of them.
    this can be a part of Collection interface or Collections class.


    i think language level changes (like Groovy) should not be included that fast. i am happy with Java's consistency and simplicity. well thought Convenience methods are better.

    Posted by: ahmetaa on November 15, 2005 at 07:39 AM

  • 'profiler' beat me to it. I've long thought a really useful addition to the language would be the ability to just spawn a block of code off into its own thread.


    // Do something
    thread
    { // Create a new Runnable with this code and start it
    }
    // Do more things


    In the above I've used a new keyword thread, but I'm sure an intuative syntax could be agreed upon which didn't have this drawback. Now if Java also had the in-built notion of a queue of Runnables, then we could do...


    thread(queue)
    { // Create a Runnable and append it to the end of worker thread 'queue'
    }


    This would make writing certain network code and most event handlers a lot easier, clearer, and hopefully promote good practice.

    Posted by: javakiddy on November 15, 2005 at 08:38 AM

  • Quoting JohnMcClean "... after ten years Java needs to move up to a higher level of abstraction! ..."

    On the contrary, I think the level Java's abstraction should be lowered. What we have today is a higly abstract api (for ex: as Graham pointed, the java.io is a thing of OO Beauty). However, common coders (not even programmers) do not understand that high a level of abstraction (and the design patterns) used.

    What we need is a set of Helper, Utility or Convenience classes and/or methods in the **standard Java API**. For example, sending a simple email with attachments should be a walk in the park without having to learn 10 different classes and writing 40 lines of code.

    One special request from my side: While you are at this Ease-of-development, for heaven's sake, please provide some appenders/handlers that are similar to Log4J. That way, we can all burry the ugly, Jakarta Commons Logging classes!

    Posted by: chakrayadavalli on November 15, 2005 at 01:23 PM

  • There are a few things I miss in Java:
    Easy use of hashmaps:

    HashMap myMap = new HashMap();
    myMap["background-color"] = "red";
    myMap["foreground-color"] = "black";

    Easy use of transactions:

    transaction
    {
    Runtime.getRuntime().exec("format c:");
    }
    commit
    {
    System.out.println("Done");
    }
    rollback(RollbackException e)
    {
    System.out.println("Hard drive saved!");
    }

    Posted by: weelink on November 15, 2005 at 01:38 PM


  • How about allow a counter to be specified in the enhanced for loop?:

    Collection c = new Collection();
    for(String s : c : int i) {
    System.out.println(i + " " + si);
    }

    Posted by: abruegl on November 15, 2005 at 03:22 PM

  • In #4 you had: @Resource FredHome fred;

    But 'Resource' is a very abstract kind of concept. It could mean anything from memory to disk space to something I expect the system to go get for me, to configuration settings.

    Wouldn't it be much cleaer to say something like:

    @EJB FredHome fred;

    I confess to not having looked at that part of the annotations spec recently, so I realise that @EJB is probably used somewhere else already?

    ... which makes me wonder whether some kind of dot notation would be cool for annotations (I'm thinking here of some kind of IDE integration, so you could start typing @EJB.r and it pops up a list of options like... umm... remoteReference, remoteInterface... etc.

    Whereas obviously having to type in in full @EJB.remoteReference would be bothersome.

    Is there a good explanation of annotations, which doesn't involve handwaving and 'and then the magic happens'? I confess to liking the concept a lot, but not being a fan of black boxes, especially magic black boxes.

    Maybe I need to play around with writing my own annotations, is there a tutorial for that?

    Posted by: rickcarson on November 15, 2005 at 05:46 PM

  • Oh, those wishes!
    Graham, the beautiful language of yours, it's pure joy.
    And the enhancements and simplifications of another beautiful language - Java. It's great and it's getting greater.
    I really like the idea of "default behaviors" of complex components, but I would miss the fexibility I get by composition. For example I like the I/O constructs and I certainly like to target the different panes in the JFrame - it's an excellent architecture to play with.
    So to keep the the flexible and complex constructs, while offering simple and stright forward ways of doing things in the standard cases is the way to go.
    Thanks for an enlightening article!
    /Bertil

    Posted by: petit on November 15, 2005 at 05:48 PM

  • How about a language construct or annotation that makes explicitly creating getters and setters for fields in a JavaBean unnecessary?

    Posted by: barin on November 15, 2005 at 07:39 PM

  • I'm responsible for the JFrame.add() boilerplate item (#2). Since it
    seems to have come in for the harshest criticsm ("distracting and
    unhelpful" - ouch), I thought I'd explain why it was there.
    See
    JFrame.add() contentPane Pain: The Complete Story.

    Posted by: hansmuller on November 16, 2005 at 11:42 AM

  • Easy delegator/wrapper implementations:

    class WrapperImpl implements Type {
    @Delegator Type member
    WrapperImpl(Type target) {
    this.member = target;
    }
    }


    All calls to the wrapper impls should automatically delegated to member, except if a method have been explicitly implemented.

    Posted by: joehni on November 16, 2005 at 11:54 AM

  • A shorthand notation for anonymous inner classes that only have one method. This would be ubiquitous in scope.

    Up to 1.5:

    Thread t = new Thread(new Runnable() {
    public void run() {
    // Do something
    }
    });


    Proposal for Mustang:

    Thread t = new Thread(new Runnable() {
    // Do something
    });


    The anonymous inner class syntax is so ugly, that it really discourages good practice is many cases. e.g. using something like Jakarta Commons Collections Predicate to filter a collection is not really a viable alternative to a for loop due to ugly syntax.

    Up to 1.5:

    Collection items = ...
    CollectionUtils.filter(items, new Predicate<String>() {
    public boolean evaluate(String item) {
    return item.equals("hello");
    }
    });

    Proposal for Mustang:

    Collection items = ...
    CollectionUtils.filter(items, new Predicate<String>(item) {
    return item.equals("hello");
    });


    The Predicate example also shows the proposed syntax for when the method has parameters.


    The scope for removing boiler plate code by the above syntax is enormous.


    Implement this in Mustang and I'll buy you a beer! :-)

    Posted by: andrewom on November 16, 2005 at 08:55 PM

  • hi :

    how about this??


    Proposal for Mustang:

    Collection items = ...
    CollectionUtils.filter(items, new Predicate().evaluate(String item) {
    return item.equals("hello");
    });

    Posted by: fcmmok on November 16, 2005 at 10:57 PM

  • Also, how to improve these codes?
    Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
    this.setLocation((int)screenSize.getWidth()/2, (int)screenSize.getHeight()/2);

    &&

    while (fin.hasNext()) {
    line = fin.nextLine();
    line = line.trim();
    if (!"".equals(line)) {
    String[] tokens = line.split("\t");
    for (String s : tokens) {
    s = s.trim();
    }
    myCollection.add(tokens);
    }
    }

    Posted by: fcmmok on November 17, 2005 at 11:25 AM

  • I can second the delegate suggestion but expand it for dynamic proxies for the purpose of unit testing.

    From my perspective, I like to use dependency injection, and inject mock-object implementation of a dependency that returns some canned data to the object that I am testing. Often the test case will end up calling only one method on the mock, so I want to implement that, but I don't want to bother implementing all the other methods defined in the interface.

    So to do this, I end up writing the invocation handler, then the instatiation of the mock. This amounts to a lot of lines of code just to make a mock that returns some canned value:


    class MockDynamicProxyInvocationHandler implements InvocationHandler
    {
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
    {
    final String methodName = method.getName();
    if (methodName.equals("methodToTest"))
    {
    mMessageObj = (Serializable) args[0];
    return "Canned Value"; // some canned value for test
    }
    throw new RuntimeException(
    "TestCase error: unanticipated method call in InvocationHandler:" + methodName);
    }
    }

    MyInterface mockObject =
    (MyInterface) Proxy.newProxyInstance(
    Thread.currentThread().getContextClassLoader(),
    new Class[]{MyInterface.class},
    new MockDynamicProxyInvocationHandler ());


    What I really want is to create my mock on the fly as an anonymous inner class by not have to implenent all the methods defined in the interface. Let other methods throw an exception if called. It would make unit testing a lot easier.

    Posted by: msimpson4 on November 18, 2005 at 05:47 PM

  • I've always thought that the JDBC-driver was an brilliant example of plugin-design, with the small wart of having to load the class, and I have used similar mechanisms whenever possible. How are you able to omit the Class.forName? Do you scan all the classes in the classloader for implementations of JDBC drivers? Isn't that very costly?

    I'd also like to second andrewom's proposal. Easier closures address almost half the complaints on this thread.

    rickcarson @EJB is horrible compared to @Resources. Good annotations decribe intent, not mechanism. (Example: @Confidential is much much better than @Encrypted, @ReadOnly rather than @Getter)

    Posted by: jhannes on November 19, 2005 at 05:30 AM


  • I've read over the suggestions here and I liked the idea of the thread keyword, though perhaps it is a little before it's time. Some of the other ideas seemed very domain-specific, some, perhaps, trite.


    I was really excited many moons ago about the notion of JavaBeans, however, the cumbersome nature of them as well as the disparate nature of their intended use makes them an unfeasible paradigm for many developers, our loss.


    BeanBuilder is still in beta (or something), indicating to me that the deployment strategy for this component has deviated somewhat. The bean "concept" is confused by EJB, by Swing type beans, and by a TON of "mandatory" boilerplate. Perhaps annotations will save the day here, who knows?


    To further the "bean cause" we'd likely need a slew of event handlers pre-defined in a baseclass: This would likely slow the whole system down in some n-bean manner. A static event bitset could help, perhaps, by reducing the number of tests for handlers and by reducing unneeded object loads. It might not be necessary for every bean to have a vetoablePropertyChangeListener for every data member, however, if it cost little more than extending, say, BaseBean, or implementing a "smart" interface, then it would matter little to the average developer.


    The other suggestion I liked was getting rid of the getters and setters, a language idiom would suffice, and we're long past the day when the (rather, if not, highly) specific rationale for insisting on their use was commonly useful. My suggestion is to use the following convention for replacing them:

    class Test {
    Integer one;
    }

    class Main {
    public void main() {
    Test t = new Test();

    int x = t.one(); // the implied getter
    x += 22;

    t.one( x ); // the implied setter.
    }
    }

    Another language feature I miss is the inherited constructor. It is probably called something else, but rears up nowadays with some of the exception handling and re-handling: If I write a constructor MyError(String), do I really wan't to write a constructor in each subclass? Eek! Perhaps they are called fall-through constructors. I realize there are very good reasons for having this particular language feature, and, no doubt there are many workarounds that promote better design and instill more advanced language-use.


    One last feature is some type of copy-like constructor,. To avoid a complicated use scenario and description; I'll off the cuff with an example. Classes Y and Z, each derived from base-class B. Having an array of Z, I'd also like an array of Y, each with the same parent as a corresponding Z. My only real option here is to use a copy constructor to get the B part of Y from Z. I'm not sure if there is a real advantage to having the parent object of Y and Z be the same, likely just the opportunity to confuse things in an additional manner (and the opportunity to create circular-constructor-synchronization-deadlock). It presents an implied facade/decorator/visitor pattern which likely isn't more useful than less complicated. For large objects, there could be some performance viability in lieu of creating and copying some hundreds of data member references (and managing those references in the gc). Seems a highly specialised suggestion, perhaps not useful (inner classes serve me fine).


    I think that the java platform is great, improving, and I also think that Sun has taken some really courageous, wise, and useful approaches to the Java language without giving up the esoteric power we all love about it!


    Thanks,
    Andrew Waddington

    P.S. One other feature would be to replace some of the more mundane exceptions (ClassCast, ArrayIndex, NullPointer) with built-in assertions, perhaps with some "deploy mode" to bypass them for tested code.

    Posted by: amfwaddi on November 29, 2005 at 05:27 PM

  • Have the compiler consume a new code-generating annotations.

    Define a number of useful annotations that abbreviate code by having the compiler generate bytecode.

    interface SomeInterface {
    void a();
    void b();
    }

    @IsAdapter(UnsupportedOperationException.class)
    class Test implements SomeInterface {
    private @BeanProperty(BeanProperty.READ_ONLY) String name;

    public void a() { ... }
    }

    produces bytecode equivalent to...

    class Test implements SomeInterface {
    String name;

    public String getName() { return name; }

    public void a() { ... }
    public void b() { throw new UnsupportedOperationException(); }
    }


    Likewise the suggested Delegator annotation is just a compiler instruction to produce the appropriate wrapper methods to perform delegation.

    Posted by: talden on June 19, 2006 at 06:05 PM

  • [Ugh don't I wish I'd clicked preview instead...]

    Have the compiler consume a new code-generating annotations.

    Define a number of useful annotations that abbreviate code by having the compiler generate bytecode.

    EG.


    interface SomeInterface {
    void a();
    void b();
    }

    @IsAdapter(UnsupportedOperationException.class)
    class Test implements SomeInterface {
    private @BeanProperty(BeanProperty.READ_ONLY) String name;

    public void a() { ... }
    }


    produces bytecode equivalent to...


    class Test implements SomeInterface {
    String name;

    public String getName() { return name; }

    public void a() { ... }
    public void b() { throw new UnsupportedOperationException(); }
    }


    Likewise the suggested Delegator annotation is just a compiler instruction to produce the appropriate wrapper methods to perform delegation.

    Posted by: talden on June 19, 2006 at 06:10 PM

  • Getting rid of the endless typing of getters and setters would be my #1, (don't start with "the EDI can do that") but the annotations must not be just as much to type as the regular getter-on-one-line, so maybe:


    @Prop String name; // simple set and get
    @ReadProp String name3; // only get
    @BoundProp String name2; // get and set, where set fires PCE
    @VetoBoundProp String name3; // get and set, where set fires VPC and PCE


    Or maybe the annotation can analyze the class it is in and can search for a "firePropertyChange(...)" method. If present it will generate the call, if not, it will not.

    Posted by: tbee on June 22, 2006 at 06:37 AM


  • I don't like the proposed solution for the JDBC driver instantiation boilerplate.
    It sounds as if the solution would introduce a lot of overhead, since the candidates for JDBC driver classes on the classpath will have to be enumerated one by one. Additionally, there might be different versions of a driver, or different drivers that support the same URL scheme, so it is unclear which driver will eventually be loaded...
    I'd think of a "clean" factory pattern. It should not extend to the degree that we have in the XML and Transformer APIs, but a simple method like DriverManager.registerDriver(String driverClassName) instead of the registerDriver that takes the driver instannce as an argument would do fine, wouldn't it?
    Another reason for JDBC boilerplate is that e.g. ResultSet is not java.util.collections compatible. Why not introduce an Iterable<Map<String,?>> implementation of this thing?
    Talking of XML: The XML APIs contain loads of boilerplate code. Adherence to W3C DOM is fine, but usability is another issue.
    Again, make e.g. NodeList java.util.collections compatible and use generics where appropriate...

    Just my $0.2...

    Posted by: mklemm on November 09, 2006 at 03:57 AM

  • amateur sex porn

    Posted by: teddy_k on December 15, 2006 at 05:24 PM

  • mature sex granny

    Posted by: teddy_k on December 17, 2006 at 03:48 PM

  • XXX Disney Porn
    INCEST
    Gary Roberts Art & Comics

    Posted by: qspider on February 23, 2007 at 06:07 AM





Powered by
Movable Type 3.01D
 Feed java.net RSS Feeds