The Artima Developer Community
Sponsored Link

Artima Developer Spotlight Forum
Java Properties without Getters and Setters

14 replies on 1 page. Most recent reply: Feb 12, 2009 2:20 PM by Raoul Duke

Welcome Guest
  Sign In

Go back to the topic listing  Back to Topic List Click to reply to this topic  Reply to this Topic Click to search messages in this forum  Search Forum Click for a threaded view of the topic  Threaded View   
Previous Topic   Next Topic
Flat View: This topic has 14 replies on 1 page
Javier Paniza

Posts: 3
Nickname: javipaniza
Registered: Nov, 2005

Java Properties without Getters and Setters Posted: Jan 20, 2009 9:49 PM
Reply to this message Reply
Advertisement

During the recent 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 a 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/










Jess Holle

Posts: 20
Nickname: jessh
Registered: Jan, 2009

Re: Java Properties without Getters and Setters Posted: Jan 22, 2009 6:38 AM
Reply to this message Reply
I maintain that allowing aClass.propertyName syntax in Java is a very bad, bad thing.

Why? Because this produces subtle and tricky changes in meaning depending on the locality of the code in question. Today aClass.propertyName always means that propertyName is a field of aClass. If this is the property access syntax, however, it will mean field access sometimes and in other cases it will mean going through accessors, depending on where the code is located. Or in alternate proposals aClass.properyName always goes through the accessors and you have to do something special in aClass' implementation to do direct field access.

All of that is a non-starter.

I could certainly accept aClass->propertyName access, as this is clearly distinct from direct field access.

Overall saving me from getXXX() and setXXX() isn't very exciting -- on either side of the equation. I have no issue with it, but I can't get even remotely excited about it.

Javier Paniza

Posts: 3
Nickname: javipaniza
Registered: Nov, 2005

Re: Java Properties without Getters and Setters Posted: Jan 23, 2009 7:42 AM
Reply to this message Reply
Hi Jess

> Today aClass.propertyName always means that propertyName
> e is a field of aClass. If this is the property access
> syntax, however, it will mean field access sometimes and
> in other cases it will mean going through accessors,
> depending on where the code is located.

The idea is that outside the class you do not need to know if an accesor is used or not. You simply are reading or setting the state of the object.

Moreover, nowadays nobody uses public fields in Java, so public fields can be used, by convention, for properties, with no confusion.

paulo faria

Posts: 14
Nickname: i30817
Registered: Jun, 2007

Re: Java Properties without Getters and Setters Posted: Jan 23, 2009 9:11 AM
Reply to this message Reply
Well I'd be confused.
Between this, and # null pointer interception and {closures => blah}
I think that java two is a need, by now. If sun doesn't want to take the mantle i guess somebody will have to.

But not microsoft. I will never trust microsoft.

Anyway, my suggestion purely as syntax enhancement: ditch ";"
It's kinda useless in the common case. In fact i can only think of badly formatted code using it.

But contrary to python fascism, don't ditch {} and adopt whitespace scope, unless, it is absolutely necessary for sane closure syntax.
Make closures have exception composition maybe. Then identify all the buggy code in the jdk, or not ideal api. Cut them.

Voila. Java 2.

Morgan Conrad

Posts: 307
Nickname: miata71
Registered: Mar, 2006

Re: Java Properties without Getters and Setters Posted: Jan 23, 2009 9:48 AM
Reply to this message Reply
> Moreover, nowadays nobody uses public fields in Java

I sometimes use public final fields. And use a lot of non-publif final fields. How do all these "automatic setter/getters" handle finals?

Neal Gafter

Posts: 12
Nickname: gafter
Registered: Oct, 2003

Re: Java Properties without Getters and Setters Posted: Jan 23, 2009 5:38 PM
Reply to this message Reply
Saying that you can have properties in Java by using AspectJ is misleading to your readers. AspectJ is not Java.

Jess Holle

Posts: 20
Nickname: jessh
Registered: Jan, 2009

Re: Java Properties without Getters and Setters Posted: Jan 24, 2009 6:33 AM
Reply to this message Reply
> The idea is that outside the class you do not need to know
> if an accesor is used or not. You simply are reading or
> setting the state of the object.
>
> Moreover, nowadays nobody uses public fields in Java, so
> public fields can be used, by convention, for properties,
> with no confusion.

To have the whole meaning of the code change because I move it from say a helper class to within the class is a non-starter.

Also there is code out that there that uses direct field access, especially for static inner classes, but even elsewhere. Subtly changing its meaning would be a really nasty thing.

Elizabeth Wiethoff

Posts: 89
Nickname: ewiethoff
Registered: Mar, 2005

Re: Java Properties without Getters and Setters Posted: Jan 24, 2009 11:44 AM
Reply to this message Reply
> How do all these "automatic setter/getters" handle finals?

I'm not familiar with AspectJ, but I'd be inclined to try these getter and setter specifications in aspect PropertyAspect:
// allow getting of non-static public fields
pointcut getter() : 
	get(public !static * *..model*.*.*) &&
	!get(public !static * *..model*.*Key.*) &&
	!within(PropertyAspect);
// allow setting of only non-final, non-static public fields
pointcut setter() : 
	set(public !final !static * *..model*.*.*) &&
	!set(public !final !static * *..model*.*Key.*) &&
	!within(PropertyAspect);

Then in my getter method for my final field, I would return a clone of the object if I want immutability. But I dunno, I'm just guessing.

> I maintain that allowing aClass.propertyName syntax in Java is a very bad, bad thing.

Depends on the conventions you're accustomed to. The aClass.propertyName syntax for getting and setting member variables via get/set methods is de rigeur in Ruby and quite common in Python.

Fred Garvin

Posts: 52
Nickname: fredgarvin
Registered: Jan, 2008

Re: Java Properties without Getters and Setters Posted: Jan 24, 2009 11:48 PM
Reply to this message Reply
Sadly, the laggard language that it has become I am not surprised Java 7 is without formal properties. Still as a Java programmer I am frustrated as hell.

How in 2009 can a modern OOP language not have properties? Properties are probably the most used design pattern of them all -- get/set methods representing a property. It's senseless that we are forced to write these methods when they exist only to wrap a private field. It's equally senseless to argue that such a private field should be public. A property is an abstraction and can be represented in an interface. Conversely, a field is an implementation detail that can only be exposed directly. For instance, I can define a simple interface (with wishful syntax) for a Contact:

public interface Contact
{
  String getset FirstName;
  String getset LastName;
  String get Name;
}

Very expressive. I can implement this like so:
public class Person implements Contact
{
  private String _firstName getset FirstName;
  private String _lastName getset LastName;
 
  public String get Name
  {
    return FirstName + " " + LastName;
  }
}

Compare this with the junked up code you'd have to write in real Java... I don't think the U.S. government could design a more bloated language.

The impact on the use-site is equally impressive:

Person person = getPerson();
person.setAge( person.getAge() + 1 );
vs.
Person.Age++;
 
getPanel().getToolbar().setColor( red )
vs.
Panel.Toolbar.Color = red

Aside from being much more readable, notice the benefit of having a property as an l-value.

As for the AspectJ idea, it may cause more harm than good. What troubles me most about it beyond the fact that it's AspectJ (another discussion) is reflection. Since the properties are a fabrication there's is no conventional representation for them when reflecting on a class. So classes employing AspectJ for properties will not be useful to third-party tools, scripting languages, and the like. If you're not dependent on reflection now, you may need to be in the not so distant future. These things tend to sneak up on you.

Jess Holle

Posts: 20
Nickname: jessh
Registered: Jan, 2009

Re: Java Properties without Getters and Setters Posted: Jan 25, 2009 6:27 AM
Reply to this message Reply
> > I maintain that allowing aClass.propertyName syntax in
> Java is a very bad, bad thing.
>
> Depends on the conventions you're accustomed to. The
> aClass.propertyName syntax for getting and
> setting member variables via get/set methods is de
> rigeur
in Ruby and quite common in Python.

Yes, but Java is not Ruby or Python. Changing the meaning of loads of existing code developed over the last decade is not cool, nor lending new meanings to existing syntax in some contexts and not others -- thereby confusing existing Java developers.

Ruby is heavily weighted towards code authoring. Similar looking code can mean all sorts of things -- depending on what the code author was up to. Not so in Java.

Elizabeth Wiethoff

Posts: 89
Nickname: ewiethoff
Registered: Mar, 2005

Re: Java Properties without Getters and Setters Posted: Jan 25, 2009 10:33 AM
Reply to this message Reply
> Yes, but Java is not Ruby or Python. Changing the meaning
> of loads of existing code developed over the last decade
> is not cool, nor lending new meanings to existing syntax
> in some contexts and not others -- thereby confusing
> existing Java developers.

Hmm. Let's say you have a Java field public String foo. Let's say it has a simple getter method getFoo(). And let's say setFoo(string) is defined to throw an exception every time it's called.

Then let's say you do some property-defining magic such that System.out.println(thing.foo) automatically invokes getFoo, and thing.foo = "bar" automatically invokes setFoo. The assignment statement will bomb and the print statement will succeed.

Such behavior is normal in Python and Ruby. But, yes, I concede the assignment bomb will be surprising to the Java mindset, considering an IDE says foo is public, and public normally means get and set at will.

> Ruby is heavily weighted towards code authoring. Similar
> looking code can mean all sorts of things -- depending on
> what the code author was up to. Not so in Java.

I agree Ruby can be loony to read. Python less so, I think.

Thomas Mueller

Posts: 18
Nickname: thomasm
Registered: Jan, 2009

Re: Java Properties without Getters and Setters Posted: Jan 27, 2009 7:49 AM
Reply to this message Reply
If you don't like 'get' and 'set', why not just remove those?
public class Person {
    private int _age;
    public int age() { return _age; }
    public void age(int x) { _age = x; }
    public static void main(String[] args) throws Exception {
        Person p = new Person();
        p.age(30);
        System.out.println(p.age());
    }
}

Only one character more than -> and works with Java 1.0.

Javier Paniza

Posts: 3
Nickname: javipaniza
Registered: Nov, 2005

Re: Java Properties without Getters and Setters Posted: Jan 27, 2009 9:55 AM
Reply to this message Reply
> If you don't like 'get' and 'set', why not just remove
> those?
>
> public class Person {
>     private int _age;
>     public int age() { return _age; }
>     public void age(int x) { _age = x; }
> public static void main(String[] args) throws
> rows Exception {
>         Person p = new Person();
>         p.age(30);
>         System.out.println(p.age());
>     }
> }
> 

> Only one character more than -> and works with Java 1.0.

But in this solution you still need two methods for each property, though these methods do not add any significant logic. Your solution is just setters and getters using other name convention.

Thomas Mueller

Posts: 18
Nickname: thomasm
Registered: Jan, 2009

Re: Java Properties without Getters and Setters Posted: Jan 27, 2009 11:35 AM
Reply to this message Reply
> But in this solution you still need two methods for each
> property, though these methods do not add any significant
> logic. Your solution is just setters and getters using
> other name convention.

Sure. But it can be implemented differently, and overloaded. I argue it's more readable than getAge / setAge, almost like using the field directly. There is no new syntax and no magic, it's fast and compatible. This convention is not new: Object.hashCode(), String.length(), the Javadoc/Doclet API. If you want, you can implement only one method.

The example above:
p.name = "..";
p.surname = "..";	
assertEquals(".. ..", p.fullName);

becomes
assertEquals(".. ..", p.fullName());

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

becomes
teacher.name("M. Carmen");
String result = teacher.name();

Raoul Duke

Posts: 127
Nickname: raoulduke
Registered: Apr, 2006

Re: Java Properties without Getters and Setters Posted: Feb 12, 2009 2:20 PM
Reply to this message Reply
ha ha, and here i thought somebody would have the balls to get rid of them!

http://typicalprogrammer.com/?p=23

Flat View: This topic has 14 replies on 1 page
Topic: Kaazing's Ric Smith on WebSockets Previous Topic   Next Topic Topic: The Adventures of a Pythonista in Schemeland: Pattern Matching

Sponsored Links



Google
  Web Artima.com   

Copyright © 1996-2019 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use