Javier has posted 48 posts at DZone. View Full User Profile

Java Properties Without Getters and Setters

05.30.2009
| 39813 views |
  • submit to reddit

During the last Devoxx conference, Mark Reinhold, Sun's chief engineer for Java SE, gave a presentation on the latest directions for Java 7. (Hamlet D'Arcy's summary of Mark's presentation is available here.)

One of the features that was discussed for possible inclusion in Java 7, but won't find its way into the final release, is first class properties for Java. First-class support for properties would have gone beyond the simple setter and getter methods of the JavaBeans specification, and provided a succinct and elegant way for defining properties for Java objects.

Properties are already first-class elements of many modern languages, so this lack in Java 7 will be felt by many developers accustomed to other languages' property support. At the same time, Java developers can resort to a handful of other techniques in working with property-like Java attributes, and some of the possible techniques work even in Java 1.4. In the rest of this article, I will demonstrate one such technique use a simple aspect, with AspectJ, and some following some conventions.

Motivation

The idea for this solution arose while working with the OpenXava 3 framework. OpenXava defines a mechanism to develop Java Enterprise applications using Business Components. It's an alternative way to MVC: instead of organizing the code into Model, a View and a Controller, the code with OpenXava is organized around Invoice, Customer, Order, and similar business-centric objects. OpenXava initially used XML for defining components, but since version 3 the use of POJOs with Java 5 annotations also became available as the preferred way to define business components.

When using the XML-based object definition, you may specify a component in the following manner:

<component name="Teacher">

<entity>
<property name="id" type="String" key="true"
size="5" required="true"/>
<property name="name" type="String"
size="40" required="true"/>
<collection name="pupils">
<reference model="Pupil"/>
</collection>
</entity>

</component>

Using the annotation-based OpenXava 3, the same component would be defined as follows:

@Entity
public class Teacher {

@Id @Column(length=5) @Required
private String id;

@Column(length=40) @Required
private String name;

@OneToMany(mappedBy="teacher")
private Collection pupils;

public String getId() {
return id;
}

public void setId(String id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public Collection getPupils() {
return pupils;
}

public void setPupils(Collection pupils) {
this.pupils = pupils;
}

}

This illustrates some of the verbosity with the Java definition: 37 lines against the 13 of XML version. The problem occurs because of the getters and setters. The boilerplate code adds noise and increases the size of the file without increasing the information to the programmer. Use Java and annotations as a definition language in OpenXava would welcome a more succinct and elegant syntax.

A More Succinct Solution

A better solution can be obtained by defining the business component in this way:

@Entity
public class Teacher {

@Id @Column(length=5) @Required
public String id;

@Column(length=40) @Required
public String name;

@OneToMany(mappedBy="teacher")
public Collection pupils;

}

This makes Java more beautiful, succinct and elegant... just as XML.

With this, you have to use the following properties without getters and setters. That is, instead of:

teacher.setName("M. Carmen");
String result = teacher.getName();

you write:

teacher.name = "M. Carmen";
String result = teacher.name;

In this case name is not a field, but a property. You can refine the access to this property, and even create pure calculated properties.

For example, if you wanted a calculated property, you could define it in this way:

@Entity
public class Person {

...

public String name;
public String surname;


transient public String fullName; // (1)
protected String getFullName() { // (2)
return name + " " + surname;
}
}

In order to define a calculated property, you define a public field (1) and then a protected (or private, but not public) getter (2). This getter, getFullName() in this case, is for implementing the logic for the property fullName.

Using this property is simple:

Person p = new Person();
p.name = "M. Carmen";
p.surname = "Gimeno Alabau";
assertEquals("M. Carmen Gimeno Alabau", p.fullName);

When p.fullName is used, the method getFullName() is executed for returning the value. You can see that fullName is a property, not a simple field.

You can also refine access to writing and reading the properties. For example, you can define a property as following:

public String address;
protected String getAddress() {
return address.toUpperCase();
}

When address is used from outside the class the method getAddress() is used to obtain the result, but this method only returns the address with some refinement. As we use address field from inside getAddress() field address from inside of its class is used, and the getter is not called.

Now you can use this property as follows:

Person p = new Person();
p.address = "Av. Baron de Carcer";
assertEquals("AV. BARON DE CARCER", p.address);

As well, you can define setters, even for vetoing the data to be set, as in the next example:

public int age;
protected void setAge(int age) {
if (age > 200) {
throw new IllegalArgumentException("Too old");
}
this.age = age;
}

As in the case of the getter, if a setter method is present it will be executed to set the data, you can use this logic to set the data to the field or for any other logic you want. Now you can use this property in this way:

Person p = new Person();
p.age = 33;
assertEquals(p.age, 33);
p.age = 250; // Here an IllegalArgumentException is thrown

In summary:

  • Properties behave from outside of the class as public fields.

  • If no getter or setter for the field exists, a direct access for the field is performed.

  • If a getter exists for the field, it will be executed when trying to read the field from outside.

  • If a setter exists for the field, it will be executed when trying to write the field from outside.

  • From inside the class, all references to the field are direct access, without calling getter or setter.

This provides a simple and natural way to have properties in Java without unnecessary getters and setters.

Implementation

This simple mechanism is easy to implement using AspectJ and a simple aspect, and it will work even in Java 1.4.

For this to work, you only need to have an aspect in your project:

aspect PropertyAspect {


pointcut getter() :
get(public !final !static * *..model*.*.*) &&
!get(public !final !static * *..model*.*Key.*) &&
!within(PropertyAspect);
pointcut setter() :
set(public !final !static * *..model*.*.*) &&
!set(public !final !static * *..model*.*Key.*) &&
!within(PropertyAspect);

Object around(Object target, Object source) :
target(target) && this(source) && getter() {

if (target == source) {
return proceed(target, source);
}
try {
String methodName = "get" +
Strings.firstUpper(
thisJoinPointStaticPart.getSignature().getName());
Method method =
target.getClass().
getDeclaredMethod(methodName, null);
method.setAccessible(true);
return method.invoke(target, null);
}
catch (NoSuchMethodException ex) {
return proceed(target, source);
}
catch (InvocationTargetException ex) {
Throwable tex = ex.getTargetException();
if (tex instanceof RuntimeException) {
throw (RuntimeException) tex;
}
else throw new RuntimeException(
XavaResources.getString("getter_failed",
thisJoinPointStaticPart.
getSignature().getName(),
target.getClass()), ex);
}
catch (Exception ex) {
throw new RuntimeException(
XavaResources.getString("getter_failed",
thisJoinPointStaticPart.getSignature().getName(),
target.getClass()), ex);
}
}

void around(Object target, Object source, Object newValue) : target(target) && this(source) && args(newValue) && setter() {
if (target == source) {
proceed(target, source, newValue);
return;
}
try {
String methodName = "set" +
Strings.firstUpper(thisJoinPointStaticPart.getSignature().getName());
Class fieldType = ((FieldSignature)
thisJoinPointStaticPart.getSignature()).getFieldType(
Method method =
target.getClass().
getDeclaredMethod(methodName, new Class[] {fieldType});
method.setAccessible(true);
method.invoke(target, new Object[] { newValue } );
}
catch (NoSuchMethodException ex) {
proceed(target, source, newValue);
}
catch (InvocationTargetException ex) {
Throwable tex = ex.getTargetException();
if (tex instanceof RuntimeException) {
throw (RuntimeException) tex;
}
else throw new RuntimeException(
XavaResources.getString("setter_failed",
thisJoinPointStaticPart.getSignature().getName(),
target.getClass()), ex);
}
catch (Exception ex) {
throw new RuntimeException(
XavaResources.getString("setter_failed",
thisJoinPointStaticPart.getSignature().getName(),
target.getClass()), ex);
}
}
}

Having defined this aspect, you will need to compile your project using AspectJ.

The aspect intercepts all access to public fields in the model package, then use introspection to call to the getter or setter method if they exists.

Drawbacks

Unfortunately, this approach has at least two important drawbacks:

  1. It does not work when you access to the properties using introspection.

  2. With JPA, at least using the Hibernate implementation, lazy initialization does not work.

You may think that the introspection problem can be overcome with your own custom introspection code. But the man third party libraries, frameworks, and toolkits will not obey those rules. For example, if you are using a report generator that can generate a report from a collection of Java objects, the report generator may expect real public getters and setters in the objects.

The JPA the specification for Java Persistence API states that: 2.0:

"Instance variables must not be accessed by clients of the entity. The state of the entity is available to clients only through the entity methods i.e., accessor methods (getter/setter methods) or other business methods."

JSR 317 : JavaTM Persistence API, Version 2.0 - Public Review Draft - Section 2.1

That is, portable JPA code should not rely on direct access to properties.

Conclusion

This article presents a very simple way to work with properties in Java, even though the language doesn't support properties. If the AspectJ implementation is not practical, you can find other implementations of this idea using asm or cglib.

References

OpenXava - http://www.openxava.org/

AspectJ - http://www.eclipse.org/aspectj/

Published at DZone with permission of its author, Javier Paniza.

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

Comments

Nicolas Frankel replied on Sat, 2009/05/30 - 6:48am

If I remember well what I was taught a looong time ago, OOP is about 3 things: encapsulation, inheritance and polymorphism.

What I understand from this article is that the first one is about to get shot. A more OOP-friendly approach would be the under-the-hood creation of defaults getters/setters if none existed, just like the creation of a default constructor is handled by the compiler. With annotations to configure in case one property shouldn't be accessed.

But I'm perhaps too old to consider new approaches...

Jean-Philippe Toupin replied on Sat, 2009/05/30 - 9:20am

I totally agree with nfrankel and each and everytime I see talks about properties in Java 7 I'm wondering why is not one talking about this solution ? It would go like that:

public class Person {
    property String fullName;
}

If the gettter and setter are not there, the compiler adds them. If they are there, they are used. It is also backward compatible with Java 6-.

Francisco Gómez replied on Sat, 2009/05/30 - 10:46am

I don't like properties, I use properties every day on delphi, at first it seems a good thing but, changing this code

teacher.setName("M. Carmen");
String result = teacher.getName();

 by this other

teacher.name = "M. Carmen";
String result = teacher.name;
just would make you can't distinge at first glance if you are just asigning a value or calling a setter or a getter. Maybe you are typing less, but now you need to do more work for the same code, normal asignaments never throw an exception but a property could do it and you'll need to now what's a property and what isn't.

Raphael Miranda replied on Sat, 2009/05/30 - 1:52pm in response to: Francisco Gómez

I don't think it's confusing, I think it's a useful convention. 

teacher.name += " Sandiego"

You're always calling the setter and getter and must be explicit accessing a property directly(like groovy's @). The javaBeans protocol is implicit.

 

Artur Biesiadowski replied on Sun, 2009/05/31 - 6:04am

I don't think that getters and setters are so much OO. For me, exposing object state is breaking encapsulation, regardless if it is done by getter/setter or direct access. Even in this proposal, you can create non-trivial accessors if you wish to.

When java was starting, there was a big discussion about window.show()/window.hide() versus windows.setVisible(true/false). It is probably one of the best examples of misuse of property for something with heavy side-effect, something which is clearly a command.

Alessandro Santini replied on Sun, 2009/05/31 - 6:24am

I agree with nfrankel. It does seem like the solution is far worse than the problem: 1) it does not cover all classes (only those indicated by the pointcut definition) 2) Introduces code injection, which makes classes incompatible with some frameworks (but I see that has already been highlighted by the author) For now, I keep my good old set/get couple. I wish I could have property definitions like with C# but it seems like asking too much.

Greg Brown replied on Sun, 2009/05/31 - 2:48pm

When I first learned about C#'s support for properties, I lamented Java's lack of them. Having recently ported a large volume of C# code that makes heavy use of properties to Java, I now lament C#'s support for them.

At first, properties seem like a good idea, but they ultimately end up obfuscating the code. I don't want to see them added to Java.

Mohamed El-beltagy replied on Mon, 2009/06/01 - 6:09am

I totally agree with nfrankel. This is really what we have first learnt about OO and how much Java is OO based, encapsulation, inheritance and polymorphism.

I do not know what's the use of properties any way?? Really. Writing less code? Who writes setters and getters any more? Does any one do it by himself now? All the people I know are using IDEs to generate them. It's about a 3 mouse clicks if you are using Eclipse. Is that too much to do?

Calling them is the problem? Those additional three letters will differ with you?  i.e, 'set' and 'get'!!!

 

come on guys. We do not want to just do a change to the language just to have a new change?!! 

We do not want to be just like C# and stuff. If a change is 'really' needed, do it. We are all there following and supporting you. But is it's 'really' needed.

If you need to reduce the coding written, you can simply have the following solution using annotations, for example:

@setter @getter
private String someField;

And that the compiler would generate the normal setter and getter methods. I remember I read something like this somewhere before. The idea is not mine, but I really do not remember where I read it.

 

@Javier. I know what you are trying to say in the post is totally something different than the title. The title and your starting of the article talks about Java 7 and properties support. But what you are actually trying to say is that there are a couple of frameworks that are, almost, supporting the treatment of fields as if they were properties and you are sharing the info with us. Thank you very much for that.

But still, I do disagree, totally disagree to the presence of properties in Java. At least, that's my personal opinion.

Piero Sartini replied on Mon, 2009/06/01 - 7:12am

In Tapestry 5, getter and setter are created for fields annotated with @Property.

Ivan Lazarte replied on Mon, 2009/06/01 - 9:55am

When I started coding C# I was a little put off by the syntax of their property construct as well, but now it's cake. property.Name is really damn easy.

erwin de ley replied on Tue, 2009/06/02 - 4:22am

I think the focus on the getter/setter-methods versus properties approach is not what matters. There is indeed no real gain to be found there, only confusion.

On the other hand, having properties as 1st-class concepts would be a tremendous improvement in the space of all that's related to "binding".

With current Java provisions, it all finally boils down to specifying the bound property with its name in some string parameter.

e.g. something like (or whatever variation on the same theme)

public class Account {
private String userName;
private String password;

public String getUserName() {
return userName;
}

private void setUserName(String userName) {
this.userName = userName;
}
//...
}

 and

...
FieldBinding binding = new FieldBinding(myUiUserNameField, Account.class, "userName");
...

And then write some Java reflection code in the implementation of the binding tool, that's invoking the corresponding getter/setter-method. So the binding declaration code suffers from being error-prone, no compile-time checking, no type-safety, no refactoring-support etc.

On the other hand, when we could do something like below "natively" in the Java language

...
FieldBinding binding = new FieldBinding(myUiUserNameField, Account.userName);
...
we are really taking advantage of the concept of properties as 1st class things.

Hontvári József... replied on Tue, 2009/06/02 - 5:55am in response to: Mohamed El-beltagy

The problem with setters/getters is not writing but reading of them. The completely meaningless getter/setter code may be longer then the real logic in a class and you will read these functions many times even if you don't want to.

Hontvári József... replied on Tue, 2009/06/02 - 6:06am in response to: Mohamed El-beltagy

Sure, getters/setters have nothing to do with encapsulation. They exists only for technical reasons. Many useful framworks must intercept reading and writing from attributes. In Java that is not possible with class fields, so we must rely on ugly getter/setter methods. UI and persistence code unfortunately doesn't work well with the encapsulation features of today's Java.

Carla Brian replied on Tue, 2012/06/19 - 5:52pm

Aside from it is free, it is an effective software as well. It has good features and etc. - Instant Tax Solutions Scam

Comment viewing options

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