Duck typing in Java ? Well, not exactly

According to Wikipedia duck typing is:

style of dynamic typing in which an object’s methods and properties determine the valid semantics, rather than its inheritance from a particular class or implementation of a specific interface

In simplier words

When I see a bird that walks like a duck and swims like a duck and quacks like a duck, I call that bird a duck

In languages with dynamic typing this feature allows creating function that are not checking type of passed object but instead rely on existence of particular methods/properties within it and throws runtime exception when those properties not found. For instance, in groovy we could have method for printing info about some entity

def printEntity = {entity ->
 println 'id: ${entity.id}, name: ${entity.name}' 
}

Let’s say we have following class

class Entity {
 Long id
 String name
}

So we can invoke our function

printEntity(new Entity(id: 10L, name: 'MyName1'))
id: 10, name: MyName1

But the same time we could pass map as argument

printEntity(['id':10L, 'name':'MyName2'])
id: 10, name: MyName2

Using some metaprogramming magic we could write even following

class Ghost {
 def propertyMissing(String name) {
  if (name == 'id') {
   return -1L
  } else if (name == 'name') {
   return 'StubName'
  }
 }
}

And we will be still able to call our function

printEntity(new Ghost())
id: -1, name: StubName

Welcome to the real world

Fortunately this concept can be used not only for languages with dynamic typing but for ones with more strict typing model, as Java. Wikipedia has good example of duck typing implementation in Java using Proxy class.

Well, you say, what is the practical usage of this except feeling oneself the wisest guru :) Let me show some real life task that was solved in Java using duck typing technique.

From the beginning I had simple report generator that queries DB of products and outputs id and name of certain entity. But then customer says: ‘I’d like to also have link to the entity detail page at our site. Beautiful, SEO friendly link. Could you do it to me’. ‘Sure ‘, I said. After digging our codebase I’ve discovered cool function generateSeoUrl() that does the job. The function takes one argument of type Entity, which is interface. So my intention was to observe implementations of Entity and try to use one of them for the report generation. How surprised was I after discovering that all of them are part of some self made ORM tool and their constructors accept query DB to get the entire information about product.

So if I were using Entity implementations I had to deal with one extra query per row of my report and this is unacceptable since report was comprised of huge number of rows. So I decided to try other approach and implement Entity interface, overriding methods that are used by generateSeoUrl(). I clicked my IDE shortcut and got surprised again. Entity had about 50 (!!!) methods. Well, I already knew that only getEntityId() and getName() are used by generateSeoUrl() function, but then again, having new class with 50 empty methods just to override 2 of them doing useful action seemed not good idea for me.

Thus I’ve decided stop trying coding and start to think :) Extend some of the Entity implementation to prevent querying DB or copy + paste generateSeoUrl() and adopt it for my needs were the options but still it was not beautiful. Especially when I reminded duck typing. I said to myself, we have a function that takes instance of Entity but only uses two method of this interface, so to complete my task I need something that looks like Entity and able to handle getEntityId() and getName() methods.

Since entityId and name were already present in data used for generating my report I could reuse them in my new class to stub data for getEntityId() and getName(). To achieve duck typing we need to create Proxy that also implements InvocationHandler interface and static method to retrieve instance of Proxy. Final code of my class looks like

public class ReportEntitySupport implements InvocationHandler {

    public static Entity newInstance(Long entityId, String name) {
        return (Entity) Proxy.newProxyInstance(
                Product.class.getClassLoader(),
                Product.class.getInterfaces(),
                new ReportEntitySupport(entityId, name)
        );
    }

    private final String name;
    private final Long entityId;

    private ReportEntitySupport(Long entityId, String name) {
        this.name = name;
        this.entityId = entityId;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if (method.getName().equals('getName')) {
            return this.name;
        } else if (method.getName().equals('getEntityId')) {
            return this.entityId;
        }
        return null;
    }
}

So how to use it ?

Inside my report generator class while iterating over ResultSet I’m using following

Long entityId;
String name;
....
Entity entity = ReportEntitySupport.newIntance(entityId, name);
String seoUrl = generateSeoUrl(entity);
....

P.S.

This post just illustrates that some uncommon for Java language concepts could be successfully applied for completing real life tasks improving your programming skills and making your code more beautiful.

Reference: Duck typing in Java ? Well, not exactly from our JCG partner Evgeny Shepelyuk at the jk’s blog blog.

Do you want to know how to develop your skillset to become a Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you two of our best selling eBooks for FREE!

JPA Mini Book

Learn how to leverage the power of JPA in order to create robust and flexible Java applications. With this Mini Book, you will get introduced to JPA and smoothly transition to more advanced concepts.

JVM Troubleshooting Guide

The Java virtual machine is really the foundation of any Java EE platform. Learn how to master it with this advanced guide!

Given email address is already subscribed, thank you!
Oops. Something went wrong. Please try again later.
Please provide a valid email address.
Thank you, your sign-up request was successful! Please check your e-mail inbox.
Please complete the CAPTCHA.
Please fill in the required fields.

Leave a Reply


9 − six =



Java Code Geeks and all content copyright © 2010-2014, Exelixis Media Ltd | Terms of Use | Privacy Policy | Contact
All trademarks and registered trademarks appearing on Java Code Geeks are the property of their respective owners.
Java is a trademark or registered trademark of Oracle Corporation in the United States and other countries.
Java Code Geeks is not connected to Oracle Corporation and is not sponsored by Oracle Corporation.
Do you want to know how to develop your skillset and become a ...
Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you two of our best selling eBooks for FREE!

Get ready to Rock!
You can download the complementary eBooks using the links below:
Close