How can you pass a List<objects that implement an interface> to a method?

Windle picture Windle · Apr 10, 2012 · Viewed 9.1k times · Source

I have a servlet with several methods that get a list of objects from the DAO, turn the list into JSON, and send it back in the response. Every list is made of objects that have a method:

public String getAsJson(){...}

And the servlet has a bunch of mostly identical methods that look like:

private String getUserListAsJson() {
    List<User> userList = this.dao.getUsers();
    StringBuilder builder = new StringBuilder();
    builder.append('[');
    // loops over the list appending the value of each objects getAsJson()
    builder.append(']');
    return builder.toString();
}

The problem is that I have about 6 methods (and growing) that look exactly like that except for different DAO queries. My idea was to create an interface that only had the definition for the getAsJson() method, make each bean implement that, and then have another method in the servlet that took objects that implemented that interface. Ended up looking like this:

public Interface JsonEnabled {
    public String getAsJson();
}

public class User implements JsonEnabled {
    ....
    @Override
    public String getAsJson() {...}
}

public class TheServlet {
    ...
    private String getUserListAsJson() {
        List<User> userList = this.dao.getUsers();
        return this.getListAsJson(userList);
    }
    private String getListAsJson(List<? implements JsonEnabled> list) {
        // The loop code that is in each method.
    }
}

That doesn't compile though. After looking up some documentation from Oracle, you can only have extends and not implements for generic parameters. Making all the classes extend from an Abstract Class that just has the getAsJson() method doesn't make sense semantically (the classes are unrelated).

I haven't found a good solution on SO or just googling around, so any help/insight would be appreciated.

Answer

Paul Bellora picture Paul Bellora · Apr 10, 2012

For generic wildcards the keyword extends works for both classes and interfaces:

private String getListAsJson(List<? extends JsonEnabled> list) { ... }

extends has slightly different meaning when used for defining generic bounds - it essentially translates to "is, or extends, or implements".