the blog for developers

Fluent Interface and Reflection for Object Building in Java

A post by Randy Patterson on creating fluent interfaces in C# got me thinking. Randy shows how to create a Fluent Interface to build an object. He uses a Person class (POJO) with setFirstName and a PersonFluentInterface class with firstName. Creating an object and setting some attributes needs quite a lot of code:

Person person = new Person();
person.setFirstName("Pat");
person.setLastName("Frank");
person.setAge(30);
person.setActive(true);

The alternative and the usual way is to use a constructor and set the attributes. Often this results in unreadable constructor calls when creating objects (no paramter names in Java):

Person person = new Person("Frank", "Pat", 30, true);

What is “Frank”, “Pat” and especially “true” ? In Groovy and other languages we could write:

Person person = new Person(firstName: "Frank",  lastName: "Pat", age: 30, active: true);

Indeed this is one of the best Groovy features and can be utilized when writing unit tests for Java classes. With a fluent interface the PersonFluentInterface class, which calls the setters on the POJO for him, Randy can write something similiar:

Person person = new Person();
person.Set.FirstName("Pat").LastName("Frank").Age(30).IsActive();

The set method in Person returns the PersonFluentInterface wrapped around the Person class. This looks more readable than calling lots of setters on an object and more readable than a large constructor call. We can do even a little better than Randy. With an additional method call we can combine the two lines in his example into one:

    Person person = Person.with()
      .firstName("Stephan")
      .lastName("Schmidt")
      .create();

Randys approach requires the developer to implement a PersonFluentInterface class which calls the correct setters on the object. The only thing we would need is the interface description of the Fluent Interface to enable the IDE to support code completion and provide static checking.

public interface PersonFluentInterface {
  public PersonFluentInterface firstName(String firstName);
  public PersonFluentInterface lastName(String lastName);
  public Person create();
}

I thought about a class which then maps the interface to a POJO with reflection. Some minutes later I was done. Voila!

public class FluentInterface<T> implements InvocationHandler {
  Object obj;

  public FluentInterface(Object obj) {
    this.obj = obj;
  }

  public static <T> T create(Object object, Class fluentInterfaceClass) {
    FluentInterface handler = new FluentInterface(object);
    @SuppressWarnings("unchecked")
    T fluentInterface = (T) Proxy.newProxyInstance(
       fluentInterfaceClass.getClassLoader(),
        new Class[]{fluentInterfaceClass},
        handler);
    return fluentInterface;
  }

  public Object invoke(Object proxy, Method m, Object[] args) throws Throwable {
    try {
      String name = m.getName();
      if ("create".equals(name)) {
        return obj;
      } else {
        String setter = "set" + name.substring(0, 1).toUpperCase()
          + name.substring(1);
        Statement stmt = new Statement(this.obj, setter, args);
        stmt.execute();
      }
    } catch (Exception e) {
      e.printStackTrace();
    } finally {
    }
    return proxy;
  }
}

Together with the interface we can now extend our Person POJO with an additional static method and we’re ready to use a fluent interface to create our POJOs.

public class Person {
  private String firstName;
  private String lastName;

  public static PersonFluentInterface with() {
    return FluentInterface.create(
      new Person(), PersonFluentInterface.class);
  }

  public Person() {
  }

  public void setFirstName(String firstName) {
    this.firstName = firstName;
  }

  public void setLastName(String lastName) {
    this.lastName = lastName;
  }
}

Some future ideas: when using byte code instrumentation instead of a proxy we could use a abstract class which extends Person and calls the setter on itself. This would allow us the drop the create() call and add custom builder methods like “isMemberOfGroup(group)”.

I’m quite satisfied with the results. Some lines could be tweaked and optimized, but overall the solution works. I’m going to use this for some time to decide if it’s worth writing and maintaining the additional interface. But most probably it will increase the readability of large constructor calls for others and for me – after I haven’t read the code in question for some weeks.

Thanks for listening.

Update: There is a small bug in the examples ;-)

You can leave a Reply here. Of course, you should follow me on twitter here.

You can share this post!
Do you want to tell others about this article? Use the social bookmark icons to submit this artice to the service of your choice. Thanks.

About the author: Stephan Schmidt is head of development at brands4friends. He has more than 15 years of internet technology experience and 10 years experience in agile. He was head of development, consultant and CTO and is a speaker, author and blog writer. He specializes in organizing and optimizing software development helping companies by increasing productivity with lean software development and agile methodologies. Want to know more? All views are only his own.
Leave a reply.

Comments

afsina

You may have a look at the Builder pattern introduced by Joshua Bloch. it is pretty good approach to this problem IMHO.
http://developers.sun.com/learning/javaoneonline/2007/pdf/TS-2689.pdf

stephan

Thanks, nice presentation, it looks interesting. I know the Builder pattern back from the GOF book and recently Groovy/Grails. Therefor I used the word “building” and not creating in the title. But I thought about how to implement this pattern with minimal implementation overhead, so I created the reflection solution.

Perhaps the presentation will help me get rid of the suppress warning annotation.

[...] Back to our example. I’ve recently shown how to create a fluent interface for object creation. One for Google Collections might look like this: [...]

Stephan,

Good idea.liked the implementation.BTW what’s the small bug?

Thanks
Prashant

stephan

Thanks :-) Can’t find it anymore.

Timo Westkämper

Nice idea. The following code

# public static PersonFluentInterface with(Person person) {
# return FluentInterface.create(
# person, PersonFluentInterface.class);
# }

might be a good addition. Because sometimes the instance is already available, but you still want to populate it fluently.

stephan

Yes, very nice idea to add and seems useful.

Your idea is a great idea.

I wrote created an opensource library for creating Builders with fluent interface based on your idea in this post.
I think I put the propert credits to you, if there are any problem let me know.

I have also extended the builder to manage object lists.
For example if Person has a property named ‘lovedThings’ of type List with the library I wrote you can write:

Person person = Person.builder()
.withFirstName(“John”)
.withLovedThings(“pizza”, “soccer”, “jogging”)
.build();

The library can be found at http://www.andreafrancia.it/articoli/fluent-builder

Uwe Langjahr

Hello Stephan,

how can you handle the modification of an instance with the fluent interfaces?

I have added a new method called “modify”, so that it is possible
to modify existing instances like:
person.modify().age(3).firstName(“Uwe”).lastName(“Langjahr”).active(false).age(109);

The method is implemented:
public PersonFluentInterface modify () {
return FluentInterface.create(this, PersonFluentInterface.class);
}

It works, but my problem is, that I’m not familiar with the reflection interface. Can you please
validate, that this implementation is correct (no unnecessary new instance are created etc.)

Greetings
Uwe

stephan

@Uwe: Yes, that should work.

Peace
-stephan

Hello,

You might be interested in op4j [http://www.op4j.org], a utility library for improving code readability and quality in Java based on the “Fluent Interface” concept.

Regards,
Daniel.

We’ve created an eclipse plugin that realizes the idea of fluent builder. It might be worth checking:

http://code.google.com/p/fluent-builders-generator-eclipse-plugin/

Leave a Reply

What people wrote somewhere else:

Additional comments powered by BackType

Guide to CodeMonkeyism

Over the last 4 years I wrote many articles on this blog. To make it easier for you to find the relevant ones, I've organized them into topics.

Top 10

6 reasons why my VC funded startup did fail

Go Ahead: Next Generation Java Programming Style

Java Interview questions: Write a String Reverser

The dark side of NoSQL

7 Bad Signs not to Work for a Software Company or Startup

Is Java dead?

Scala vs. Clojure

Never, never, never use String in Java

No future for functional programming in 2008 – Scala, F# and Nu

Clojure vs Scala, Part 2

Java Developer

Is Java Dead?

Go Ahead: Next Generation Java Programming Style

Be careful with magical code

All variables in Java must be final

Never, never, never use String in Java

Bending Java: More readable code with methods that do nothing?

NoSQL Guy

NoSQL: The Dawn of Polyglot Persistence

The dark side of NoSQL

Essential storage tradeoff: Simple Reads vs. Simple Writes

Sharding destroys the goals of your relational database

The unholy legacy of databases

Startup/CTO

Development Dream Teams

6 reasons why my VC funded startup did fail

American vs. European style of Software Development

12 Things to Reduce Your Lead Time and Time to Market

The high cost of overhead when working in parallel

Essential storage tradeoff: Simple Reads vs. Simple Writes

Job Seeker

Another Good (Java) Interview Question

7 Bad Signs not to Work for a Software Company or Startup

Java Interview questions: Write a String Reverser (and use Recursion!)

Java Interview questions: Multiple Inheritance

As a Manager: What I value in developers

Top 10 Tips (+1) to Get a Pay Raise

Agilist

What Developers Need to Know About Agile

5 Practices Better to Change in Your Scrum Implementation

Scrum is not about engineering practices

ScrumMaster and ZenMaster: The joke of certification

What is Trans-Scrum?