Core Java

Bloated JavaBeans – Don’t Add “Getters” to Your API

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). 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.
  4. 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).

  5. Finally, DO use “get” and “set” where you really want to emphasise the semantic of the ACTIONScalled “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!
 

Reference: Bloated JavaBeans – Don’t Add Getters to Your API from our JCG partner Lukas Eder at the JAVA, SQL, AND JOOQ blog.

Lukas Eder

Lukas is a Java and SQL enthusiast developer. He created the Data Geekery GmbH. He is the creator of jOOQ, a comprehensive SQL library for Java, and he is blogging mostly about these three topics: Java, SQL and jOOQ.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

4 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Dmitri
11 years ago

Very good suggestions and recommendations, thank you!

Ramesh
Ramesh
10 years ago

public static void setAttachment(File attachment){
attachment = attachment;
System.out.print(“in DATA class “+attachment);
}

public File getAttachment(){
return *****;
}

plz ans instead of *

Chris
Chris
9 years ago

As an admirer of clean, natural code, I really appreciate the attention to detail here. I would like to suggest though that most people write Java because they use it at work and would prefer something faster or dynamically typed for individual coding. You pointed out that Java is very backward compatible and I agree and the reason for that is because so many businesses use Java. So my point is, other people write code differently in my projects, they write over it, they do what they want and rules that break the industry convention are almost impossible to change… Read more »

Lukas Eder
9 years ago
Reply to  Chris

I think that the industry who uses JavaBeans style getters and setters (possibly each with Javadocs) across a whole Enterprise code base also still uses EJB 2.0. Working in such a place vs. in some other place is a choice everyone has to make.

Back to top button