Home > Blog > Google collections and enhanced JavaBeans

Google collections and enhanced JavaBeans

November 4th, 2009

I’m a big fan of Google Collections. Functions and Predicates became my best friends to make Java’s syntax a bit functional-like. I like writing things like:

List<Contact> contacts = ...
List<String> toStrings = Lists.transform(contacts, Functions.toStringFunction());

and with the help of static imports:

List<String> toStrings = transform(contacts, toStringFunction());

If you use out-of-the-box Functions and Predicates, it’s a lot of fun. Now, let’s say, you want something more useful like:

List<String> names = transform(contacts, Contact.T0_NAME);

you need to accommodate with Java’s way of writing functions. That is write an inner class:

public class Contact {
...
public static Function<Contact, String> TO_NAME = new Function<Contact, String> {
    public String apply(Contact contact) {
        return contact.getName();
    }
}

It’s ok for one bean property, but writing functions for all of them is a lot of work.

What if we could write a JavaBean that would generate all these functions for us. Something like that:

public class Contact extends AbstractBean<Contact> {
public static final StringProperty<Contact> NAME = stringValue();
public static final IntegerProperty<Contact> AGE = integerValue();
public static final StringProperty<Contact> EMAIL = stringValue();

public Contact(String name, int age, String email) {
    super(NAME, name, AGE, age, EMAIL, email);
}

public String getName() {
    return get(NAME);
}

public Integer getAge() {
    return get(AGE);
}

public String getEmail() {
    return get(EMAIL);
}
}

Now, every property of my bean is also a Function converting a bean instance to it’s property value. To be clear:

Contact.NAME is a Function<Contact, String>
Contact.AGE is a Function<Contact, Integer>
Contact.EMAIL is a Function<Contact, String>

so that I can write:

List<Contact> contacts = ...
List<String> names = transform(contacts, Contact.NAME);
List<Integer> ages = transform(contacts, Contact.AGE);

Nice isn’t it?

Now, it can be even cooler. I can write something like that:

Iterable<Contact> david = filter(contacts, NAME.isEqualTo("david"));
... adults = filter(contacts, AGE.isGreaterThan(18));
... babies = filter(contacts, NAME.isEqualTo("baby").and(AGE.isLessThan(1)));

My bean properties are also Predicate factories!

With a custom utility class, I can even use a clearer syntax that Google Collection’s:

... ages = with(contacts).keep(NAME.isEqualTo("david")).to(AGE).list();

There are even more features. All AbstractBeans come with free equals(), hashCode() and compare().

The last neat feature is the ability to write a builder for any bean easily, with only one additional method:

public class Contact extends AbstractBean<Contact> {
...
static <V> BeanBuilder<Contact> with(BeanProperty<Contact, V> property, V value) {
    return new BeanBuilder<Contact>() {
        public Contact createBean(PropertyValues<Contact> values) {
            return new Contact(values.get(Contact.NAME), values.get(Contact.AGE));
        }
    }.with(property, value);
}

Now, I can write something like this:

Contact contact = with(NAME, "david").with(AGE, 34).with(EMAIL, "d@g.net").build();

Note, that all of the features are statically typed and don’t use reflection.

What do you think?

  1. Gabriel K.
    November 2nd, 2009 at 13:46 | #1

    J’aime bien!! Exactement le genre de choses qui me passe en tête quand pour la nieme fois il faut écrire un foreach/if/add… Mais ça garde quand même l’élégance pachydermique du java

  2. November 2nd, 2009 at 13:56 | #2

    Très élégant !
    Peux-tu nous mettre un lien vers ton fichier java complet pour avoir la “big picture” ?

    Dans le même esprit, en JavaScript, l’API LivePipe propose un module Event.Behavior:
    http://livepipe.net/extra/event_behavior

  3. November 2nd, 2009 at 14:15 | #3

    @Jean-Philippe Encausse C’est du code expérimental illisible mais je l’ai quand même mi ici: http://pastie.org/679917

  4. F. Degenaar
    November 2nd, 2009 at 14:16 | #4

    Have you tried out LambdaJ (http://code.google.com/p/lambdaj) yet? It seems to be capable of what you wish for without language extensions.

  5. November 2nd, 2009 at 14:23 | #5

    @F. Degenaar Thanks, lambdaj looks very nice. Will give it a try.

  6. November 3rd, 2009 at 08:18 | #6

    Looks really nice, I’d love to host a tutorial on my web 2.0 site if you’d ever be interested

  7. Sakuraba
    November 3rd, 2009 at 14:41 | #7

    Where is the source code for AbstactBean?

Comments are closed.