I am the founder and CEO of Data Geekery GmbH, located in Zurich, Switzerland. With our company, we have been selling database products and services around Java and SQL since 2013. Ever since my Master's studies at EPFL in 2006, I have been fascinated by the interaction of Java and SQL. Most of this experience I have obtained in the Swiss E-Banking field through various variants (JDBC, Hibernate, mostly with Oracle). I am happy to share this knowledge at various conferences, JUGs, in-house presentations and on our blog. Lukas is a DZone MVB and is not an employee of DZone and has posted 248 posts at DZone. You can read more from them at their website. View Full User Profile

Bloated JavaBeans™, Part II – or Don’t Add “Getters” to Your API

01.17.2013
| 4018 views |
  • submit to reddit

I have recently blogged about an idea how JavaBeans™ could be extended to reduce the bloat created by this widely-accepted convention in the Java world.

That article was reblogged on DZone and got quite controversial feedback here (like most ideas that try to get some fresh ideas into the Java world):
http://java.dzone.com/articles/javabeans™-should-be-extended.

I want to revisit one of the thoughts I had in that article, which was given a bit less attention, namely:

Getter and Setter naming

Why do I have to use those bloated “get”/”is” and “set” prefixes every time I want to manipulate object properties? Besides, the case of the first letter of the property changes, too. If you want to perform a case-sensitive search on all usage of a property, you will have to write quite a regular expression to do so

I’m specifically having trouble understanding why we should use getters all over the place. Getters / setters are a convention to provide abstraction over property access. I.e., you’d typically write silly things like this, all the time:

public class MyBean {
    private int myProperty;

    public int getMyProperty() {
        return myProperty;
    }

    public void setMyProperty(int myProperty) {
        this.myProperty = myProperty;
    }
}

OK. Let’s accept that this appears to be our everyday life as a Java developer, writing all this bloat, instead of using standard keywords or annotations. I’m talking about standards, not proprietary things like Project Lombok. With facts of life accepted, let’s have a look at java.io.File for more details. To me, this is a good example where JavaBean-o-mania™ went quite wrong. Why? Check out this source code extract:

public class File {

    // This is the only relevant internal property. It would be "final"
    // if it wasn't set by serialisation magic in readObject()
    private String path;

    // Here are some arbitrary actions that you can perform on this file.
    // Usually, verbs are used as method names for actions. Good:
    public boolean delete();
    public void deleteOnExit();
    public boolean mkdir();
    public boolean renameTo(File dest);

    // Now the fun starts!
    // Here is the obvious "getter" as understood by JavaBeans™
    public String getPath();

    // Here are some additional "getters" that perform some transformation
    // on the underlying property, before returning it
    public String getName();
    public String getParent();
    public File getParentFile();
    public String getPath();

    // But some of these "transformation-getters" use "to", rather than
    // "get". Why "toPath()" but not "toParentFile()"? How to distinguish
    // "toPath()" and "getPath()"?
    public Path toPath();
    public URI toURI();

    // Here are some "getters" that aren't really getters, but retrieve
    // their information from the underlying file
    public long getFreeSpace();
    public long getTotalSpace();
    public long getUsableSpace();

    // But some of the methods qualifying as "not-really-getters" do not
    // feature the "get" action keyword, duh...
    public long lastModified();
    public long length();

    // Now, here's something. "Setters" that don't set properties, but
    // modify the underlying file. A.k.a. "not-really-setters"
    public boolean setLastModified(long time);
    public boolean setReadable(boolean readable);
    public boolean setWritable(boolean writable);

    // Note, of course, that it gets more confusing when you look at what
    // seem to be the "not-really-getters" for the above
    public long lastModified();
    public boolean canRead();
    public boolean canWrite();
}

Confused? Yes. But we have all ended up doing things this way, one time or another. jOOQ is no different, although, future versions will fix this.

How to improve things

Not all libraries and APIs are flawed in this way. Java has come a long way and has been written by many people with different views on the subject. Besides, Java is extremely backwards-compatible, so I don’t think that the JDK, if written from scratch, would still suffer from “JavaBean-o-mania™” as much. So here are a couple of rules that could be followed in new APIs, to get things a bit cleaned up:

  1. First off, decide whether your API will mainly be used in a Spring-heavy or JSP/JSF-heavy environment or any other environment that uses JavaBeans™-based expression languages, where you actually WANT to follow the standard convention. In that case, however, STRICTLY follow the convention and don’t name any information-retrieval method like this: “File.length()”. If you’re follwoing this paradigm, ALL of your methods should start with a verb, never with a noun / adjective
  2. The above applies to few libraries, hence you should probably NEVER use “get” if you want to access an object which is not a property. Just use the property name (noun, adjective). This will look much leaner at the call-site, specifically if your library is used in languages like Scala. In that way, “File.length()” was a good choice, just as “Enum.values()”, rather than “File.getLength()” or “Enum.getValues()”.
  3. You should probably ALSO NOT use “get” / “set” if you want to access properties. Java can easily separate the namespace for property / method names. Just use the property name itself in the getter / setter, like this:
    public class MyBean {
        private int myProperty;
    
        public int myProperty() {
            return myProperty;
        }
    
        public void myProperty(int myProperty) {
            this.myProperty = myProperty;
        }
    }
    

    Think about the first rule again, though. If you want to configure your bean with Spring, you may have no choice. But if you don’t need Spring, the above will have these advantages:

  • Your getters, setters, and properties have exactly the same name (and case of the initial letter). Text-searching across the codebase is much easier
  • The getter looks just like the property itself in languages like Scala, where these are equivalent expressions thanks to language syntax sugar: “myBean.myProperty()” and “myBean.myProperty”
  • Getter and setter are right next to each other in lexicographic ordering (e.g. in your IDE’s Outline view). This makes sense as the property itself is more interesting than the non-action of “getting” and “setting”
  • You never have to worry about whether to choose “get” or “is”. Besides, there are a couple of properties, where “get” / “is” are inappropriate anyway, e.g. whenever “has” is involved -> “getHasChildren()” or “isHasChildren()”? Meh, name it “hasChildren()” !! “setHasChildren(true)” ? No, “hasChildren(true)” !!
  • You can follow simple naming rules: Use verbs in imperative form to perform actions. Use nouns, adjectives or verbs in third person form to access objects / properties. This rule already proves that the standard convention is flawed. “get” is an imperative form, whereas “is” is a third person form.
Consider returning “this” in the setter. Some people just like method-chaining:
public MyBean myProperty(int myProperty) {
    this.myProperty = myProperty;
    return this;
}

// The above allows for things like
myBean.myProperty(1).myOtherProperty(2).andThen(3);

Alternatively, return the previous value, e.g:

public int myProperty(int myProperty) {
    try {
        return this.myProperty;
    }
    finally {
        this.myProperty = myProperty;
    }
}

Make up your mind and choose one of the above, keeping things consistent across your API. In most cases, method chaining is less useful than an actual result value.

Anyway, having “void” as return type is a waste of API scope. Specifically, consider Java 8′s lambda syntax for methods with / without return value (taken from Brian Goetz’s state of the lambda presentations):

// Aaaah, Callables without curly braces nor semi-colons
blocks.filter(b -> b.getColor() == BLUE);

// Yuck! Blocks with curly braces and an extra semi-colon!
blocks.forEach(b -> { b.setColor(RED); });

// In other words, following the above rules, you probably
// prefer to write:
blocks.filter(b -> b.color() == BLUE)
      .forEach(b -> b.color(RED));

Thinking about this now might be a decisive advantage of your API over your competition once Java 8 goes live (for those of us who maintain a public API).

Finally, DO use “get” and “set” where you really want to emphasise the semantic of the ACTIONS called “getting” and “setting”. This includes getting and setting objects on types like:

  • Lists
  • Maps
  • References
  • ThreadLocals
  • Futures
  • etc…

In all of these cases, “getting” and “setting” are actions, not property access. This is why you should use a verb like “get”, “set”, “put” and many others.

Summary

Be creative when designing an API. Don’t strictly follow the boring rules imposed by JavaBeans™ and Spring upon an entire industry. More recent JDK APIs and also well-known APIs by Google / Apache make little use of “get” and “set” when accessing objects / properties. Java is a static, type-safe language. Expression languages and configuration by injection are an exception in our every day work. Hence we should optimise our API for those use cases that we deal with the most. Better, if Spring adapt their ways of thinking to nice, lean, beautiful and fun APIs rather than forcing the Java world to bloat their APIs with boring stuff like getters and setters!

Published at DZone with permission of Lukas Eder, author and DZone MVB. (source)

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Tags:

Comments

Fabrizio Giudici replied on Thu, 2013/01/17 - 7:59am

I must say I find this post pretty confusing. First you advocate against using "non standard" tools such as Lombok. Apart from the fact that the term "proprietary" is plain wrong, as Lombok is FLOSS, what is your definition of "standard"? I mean: once upon a time most of the Java ecosystem was made by official tools and APIs made by Sun. This is no more true since quite a few years, considering that there are plenty of things such as Spring, GWT, Guice, the whole huge bag of products made by Apache Software Foundation, etc. So "standard" is not really a valuable criterion to pick software, while popularity, well estabilished communities, maintenance, etc... are the good criteria to use.

On the other hand, there are de-facto standards that help in reducing entropy and integrating things, and the getter/setter convention is just one of those. It's not only used by Spring or JSF, but by a whole bag of other products, such as JPA, Swing, XStream, and again here the list is long. We should give up with this in change of what? The "get" and "set" semantics are quite clear, while e.g. the idea of having a property() method that returns the <i>previous</i> value is quite obscure (and useless, I can't think of a popular, useful use case). Good idea to allow method chaining, in fact many people do that with regular getters/setters, but again I'd advice against making it a standard, since you have to deal with a few of important things, such as the choice of returning "this" or a cloned object. So, I'd use chainable setters when needed, when it's properly documented, and using a specific naming convetion (withProperty() is a good one).

I think it would be a good thing to have a language extension that allowed calling getters/setters with a shorter syntax as you propose (e.g. property = 5), but in this case the way getters/setters are named is not important since it's hidden by the compiler...

So I really can't understand your points...

Robert Saulnier replied on Thu, 2013/01/17 - 9:53am in response to: Fabrizio Giudici

I agree with Fabrizio.

Also, java.io.File was part of Java before the JavaBeans spec came out, so it's not surprising that there are some inconsistencies.

Robert Saulnier replied on Thu, 2013/01/17 - 12:31pm

Usually, the way to distinguish between get and to methods:

Getters return a property of the object

To methods return the object as another type of object, i.e toString(), toURI(), toPath().

Greg Brown replied on Thu, 2013/01/17 - 12:42pm

"Expression languages and configuration by injection are an exception in our every day work."

Maybe they are exceptions in your everyday work, but not mine...

 

Loren Kratzke replied on Thu, 2013/01/17 - 2:48pm

 Not to defend setters and getters (and I do think a couple of the suggestions in the post are interesting) but quite frankly, I like the way setters and getters sort alphabetically in my hint dialog and method listings. Removing get/set from the method names will blow that up and the sort will be by property name (mixed with other methods) which is quite useless when a hint for recalling the name of the property is what I really need. Otherwise, yes, a tad bloated. But it does not bother me. I prefer to err toward verbosity.

Jacek Furmankiewicz replied on Thu, 2013/01/17 - 6:04pm

OR...a better idea is that you discover Lombok and then your entire JavaBean dilemma is reduced to a single class-level annotation: @Data.

http://projectlombok.org/features/index.html

Lombok has done more to reduce Java verbosity than Sun/Oracle have done in the last decade.

Mark Unknown replied on Fri, 2013/01/18 - 1:58pm in response to: Greg Brown

"Maybe they are exceptions in your everyday work, but not mine..."


Typically this is because they just cannot visualize the need.   Sometimes they choose to ignore reality.   In software development we have all kinds of people. Most people fail to realize that, for instance, what makes a person a good developer doesn't make them a good tester (although they can be).  So if you are not a good "X", then you will not realize "Y".

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.