Skip to main content

Simplify JavaBean creation: provide derfault get/set equals and hashcode

29 replies [Last post]
patrikbeno
Offline
Joined: 2004-10-11
Points: 0

Do you also hate creating stupid getter/setter accessor methods for your private fields as well as writing equals and hashcode?
I know IDE can generate them all for you but this is workaround not solution.

I want this:

<br />
public class Person {<br />
   @property String name;<br />
   @property String surname;</p>
<p>   @equals<br />
   @hashcode<br />
}<br />

- there are private fields name and surname
- default getters and setters are provided
- in case of conflict, user-defined getter or setter is valid (and there is no default)
- just syntactic but useful sugar
- @equals inserts default equals() implementation
- @hashCode dttd

Easy data modelling :-)

P.S.
See http://forums.java.net/jive/thread.jspa?messageID=4067#4067 for proposal

Message was edited by: patrikbeno

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
monika_krug
Offline
Joined: 2004-10-14
Points: 0

What exactly are "properties" in VB or C#? What can be done with them that could not be done by simply making the object variable public?

Monika.

patrikbeno
Offline
Joined: 2004-10-11
Points: 0

[i]> that could not be done by simply making the object variable public?[/i]

Not an option. This proposal is about JavaBeans. And JavaBeans are about methods:

String getMyProperty()
void setMyProperty(String value)
boolean isEnabled()
void setEnabled(boolean value)

It makes no sense suggesting use of public variables here. It's not an option.

monika_krug
Offline
Joined: 2004-10-14
Points: 0

Aha, okay.

Monika.

vhi
Offline
Joined: 2004-10-11
Points: 0

In my opinion, it would be difficult to support obj.someProperty++ etc without deep language support. This cannot be done by simply generating getters and incrementing the value. For one, getSomeProperty()++ will not work, hence two methods would need to be generated and called. That is, one that increments the member and the other one a getter.

----
@Property int someProperty;
----

Results in following generated code:

----
public void incrementSomeProperty() {
someProperty++;
}
public void decrementSomeProperty() {
someProperty--;
}
public int getSomeProperty() {
return someProperty;
}
public void setSomePropert(int p) {
someProperty = p;
}
... and more...
----

And the statement:

----
obj.someProperty = value;
value = obj.someProperty;
value = obj.someProperty++; // Statement 3
----

Needs to be translated as:
----
obj.setSomeProperty(value);
value = obj.getSomeProperty();

obj.incrementSomeProperty(); // Statement 3
value = obj.getSomeProperty(); // Statement 3
----

In my opinion, such a scheme will introduce complexities and hidden surprises in the compiler (especially for native types like 'int', 'float' due to left-shift, logical-or etc.), and is not really worth the effort.

patrikbeno
Offline
Joined: 2004-10-11
Points: 0

[code]
obj.someProperty++ ==> obj.setSomeProperty(obj.getSomeProperty()++);

obj.someProperty += 10 ==> obj.setSomeProperty(obj.getSomeProperty()+10);
[/code]

others always the same, get() value, do operation, set() result. JVM does the same stuff all over again with every ordinary no-property [i]private int whatever[/i]: read/modify/write ...

What complexities? What surprises? What deep language suport?

vhi
Offline
Joined: 2004-10-11
Points: 0

obj.getSomeProperty()++ would not compile.

patrikbeno
Offline
Joined: 2004-10-11
Points: 0

yes, of course, sorry.
i meant obj.getSomeProperty()+1

So what's the deal?

vhi
Offline
Joined: 2004-10-11
Points: 0

You are right... I was drawing parellels between the code generation and the operator overloading, which lead me astray ;-) Mental blocks come in different forms ;-)

patrikbeno
Offline
Joined: 2004-10-11
Points: 0

[b]Proposal :-)[/b]

Benefits:
- type and identifier (name) of the property defined only once
- whole thing is just a very convenient a syntactic sugar, changes only needed to compiler, JVM is without modification
- compiler can generate getter and setter automatically with access modifiers as defined in @Property
- ability to define property that does not occupy space in the instance. (takes advantage of the single property name and type declaration)
- fully compatible with JavaBeans spec

[code]
enum Scope { PUBLIC, PROTECTED, DEFAULT, PRIVATE }

@interface Property {
Scope get() default Scope.PUBLIC;
Scope set() default Scope.PUBLIC;
boolean hasField() default true;
}

class Bean {
/**
* ordinary property with default public getter and setter
*/
@Property String first;

/**
* similar as first but setter is made protected (static import used for PROTECTED enum)
*/
@Property(set=PROTECTED) String second;

/**
* property with custom setter. generated setter has following signature:
* setThird(String value)
* annotation like syntax for '@set' is chosen instead 'set' to avoid new keywords.
* Method parameter has implicit identifier 'value'
*
* When code defined by the custom setter finishes, object actually assigned to the implicit
* variable (parameter) named 'value' is written to field reserved for this property.
* Thus, there is no need to do explicit assgnment
* this.third = value;
* Compiler generates this assignment code (chosen to decrease verbosity)
*/
@Property String third {
@set {
if (value == null) throw new IllegalArgumentException();
value = whatever.normalize(value);
/* this.third = value; - not needed (invalid, in fact) */
}
}

/**
* JavaBean property which does not introduce field into class. Both setter and getter must be
* provided.
* Advantage is that you declare name and type only once and you have both accessor implementations
* on the same place.
*/
@Property(hasField=false) String fourth {
@get {
return (String) whatever.read();
}
@set {
whatever.write((String) value);
}
}
}
[/code]

Message was edited by: patrikbeno

patrikbeno
Offline
Joined: 2004-10-11
Points: 0

So how do you like the proposal's syntax and mentioned benefits? Worth it or not?

ricky_clarkson
Offline
Joined: 2004-06-28
Points: 0

If you specify your beans via an interface:

interface ACrazyBean
{
int getX();
int getY();
//etc

void setX(int x);
void setY(int y);
}

You can use the java.lang.reflect.Proxy class to create a Map-backed implementation of ACrazyBean at runtime, and live happily ever after. If you need null-checking, you can have it, it's pretty easy.

patrikbeno
Offline
Joined: 2004-10-11
Points: 0

I used this approach in some situations and it's really poweful.
but how does it solve this problem?

Imagine I have to model complex domain data model as regular JavaBeans (get/set accessors) with real fields in every class (reason for real fields can be persistence).
This is classic situation, something that Java should be ready for out of the box.

Your design pattern is not an option here.

Besides this, in your example JavaBean properties' names and types are duplicated (get+set definitions). That's what I am trying to eliminate.

jbetancourt
Offline
Joined: 2003-07-30
Points: 0

Is this similar to the 'properties' capability that C# has?

I think even VisualBasic and LotusScript has this. Don't remember if Perl or Python has it.

To me its not an issue of the effort in using getter/setter, after all as has been posted, IDEs can do this and also annotations. Rather, is there a real 'problem' in what properties are and should be handled in the underlying OO model that Java instantiates?

patrikbeno
Offline
Joined: 2004-10-11
Points: 0

Repeating myself but so be it:

1) using getter and setter is OK though I can imagine a better way

2) IDEs can do this, but its a workaround not solution: more code, more maintenance requirements, more potential troubles. If something can be generated by IDEs, it can be generated by the compiler. Why should I be bothered with keeping my getters/setters/variables names and types in sync?

3) Annotations cannot do anything alone, you need tool that processes them. So far its not a problem but you cannot use getter or setter which does not yet exits - you have to generate source code (unnecessary overhead)

[b]Compiler could do all this, so it should.[/b]

Sorry, I am not really sure I understand the last sentence: [i]Rather, is there a real 'problem' in what properties are and should be handled in the underlying OO model that Java instantiates?[/i]. Would you mind explaining?

Message was edited by: patrikbeno

tsinger
Offline
Joined: 2003-06-10
Points: 0

To be honest, I don't see the point that the compiler should generate plain getters/setters. Why then you don't make the fields public? If this is not useful, why you don't use a code-generation framework, which will produce the code for you? Why cluttering the [b]language[/b], because you are just lazy?

Tom

patrikbeno
Offline
Joined: 2004-10-11
Points: 0

- Not making fields public is a design pattern, design choice.
- I want to create whole bunch of regular JavaBeans, thus I have to use getters/setters. Also design choice.
- Code generation is unnecessary and useless overhead in this scenario. Consider refactoring, maintenance costs etc.
- this kind of laziness always moved things further.
- AFAIK hand-crafted getters/setters clutter language, my proposal cleans it up.

rreyelts
Offline
Joined: 2003-06-10
Points: 0

How about this instead,
[code]
@bean public class Person {
@property( write=false ) String name;
@property( read=false ) String surname;
}[/code]A getter is provided for name, a setter is provided for surname, and since no equals or hashcode methods were specified, they are also generated.

God bless,
-Toby Reyelts

patrikbeno
Offline
Joined: 2004-10-11
Points: 0

[b]Two more things to solve:[/b]

a) better syntax for accessing properties. using get/set calls really sucks somtimes. we need standard field access equivalent:
[code]
obj.someProperty = value;
value = obj.someProperty;
obj.someProperty++;
[/code]
Internally, they're still get/set calls. Suggest something :-)

b) how to keep together property declaration and read/write (get/set) definitions?
[code]
/* I don't like this: duplicate definitions (type, name: 3x */
@property String name;
public void setName(String name) {...}
public String getName() {...}

/* maybe need something like this */
@property String name
@read { return name; }
@write { this.name = name; /*arg named as property*/ }
[/code]

Yet again, suggest something. :-)

rreyelts
Offline
Joined: 2003-06-10
Points: 0

> a) better syntax for accessing properties

I don't see that as an issue.

> b) how to keep together property declaration

The @property annotation generates the getters and setters. If you need your getters and setters to do something else besides directly access the field, don't use the annotation.

God bless,
-Toby Reyelts

patrikbeno
Offline
Joined: 2004-10-11
Points: 0

a) it may become an issue if you do huge amount of property read/write operations:
[code]
obj.setProperty(another.getproperty()); // imagine 20 such lines in a row

obj.property = another.property; // much readable
[/code]

b) I'd like to avoid declaration duplicity when overriding default get/set implementations.

[code]
@property String name; // all neded is here

/* now i need to override setName() (I'm ok with default get() */
public void setName(String name) {
if (name==null) throw new NPE(); /* whatever */
this.name = name;
}
[/code]
When providing my own setter, property type is duplicated and so is the name. After accidental refactoring I may end up with two properties operating on the same data member. i want to avoid this if possible. Even if you consider this not an issue, duplicate declarations always have their maintenance cost. Let's avoid this if we can (and we eventually can if language changes are to be introduced in Mustang)
[code]
@property String fullname;
public void setName(String name) { /* property name working on fullname */
this.fullname = name;
}
[/code]

rreyelts
Offline
Joined: 2003-06-10
Points: 0

> a) it may become an issue if you do huge amount of property read/write operations:

I disagree.

> b) I'd like to avoid declaration duplicity when overriding default get/set implementations.

I think you missed my point. I don't like the idea of "overriding" the annotation's get/set implementation. If you don't like what it generates, don't use it for that property.

God bless,
-Toby Reyelts

patrikbeno
Offline
Joined: 2004-10-11
Points: 0

b) And I think you missed my point :-)

I like generated getter. I just need to hook into setter, e.g. insert null-checking code into setter. Must I write it all myself just because of this?

Must be a better way...

rreyelts
Offline
Joined: 2003-06-10
Points: 0

> b) And I think you missed my point

Sounds like we just disagree.

> Must I write it all myself just because of this?

That's my current opinion, yes.

patrikbeno
Offline
Joined: 2004-10-11
Points: 0

Well, we disagree, stuff happens :-)

Just think about the fact that we do not just introduce some annotation but we require special support for this (from compiler, from source manipulating tools, etc). Why not to design the proposed feature to the end, as a whole, without compromise?

Why not? You just disagree. But try to argue. Give me a reason.

patrikbeno
Offline
Joined: 2004-10-11
Points: 0

I can't believe this proposal gains so little interest. Don't you waste your time creating getters/setter for your data objects?

tim12s
Offline
Joined: 2004-02-02
Points: 0

Time is all relative and I'm definately against this enhancement because its such a simple issue. Now its obviously possible for this to be implemented.

PRO:

1. Save a bit of time.
2. You see the exceptional cases that are not simple cases alot easily.

CON:
1. Java AST requires more semantical interpretation.
2. Seems more like macro expansion.
3. Method <---> Variable understanding becomes a syntactic issue.

---

A question, are there currently any annotations that java expands to more complex classes, unlike the interpretation of methods at runtime?

---

While I'd like to see code dissapear... I dont want to end up with Perl.

If I were to choose one, I'd prefer "Runtime Type Safety and Inheritance for Generics". RTSIG seems to have more real relevance than java properties. If we were to have a java property mechanism, I'd _DEFINATELY_ prefer a java keyword than an annotation.

patrikbeno
Offline
Joined: 2004-10-11
Points: 0

If you prefer java keyword to an annotation, the only difference is that annotation is backwards compatible and keyword is NOT.

value is the same.

So are you sure you never coded 1000 JavaBeans with had-crafted getters/setters? And are you sure you never maintained such code whenyou had to rename variable as well as both getter and setter in a bean?

- it saves a lot of time when you create domain model (of couse it can be generated but yet again, generating such source code is workaround, not asolution

- less code, better readability and less maintenance requirements

For me, this need is as obvious as runtime support for generics, although I am in fact not not sure HOW this should be implemented.

ahoma
Offline
Joined: 2003-06-20
Points: 0

I would rather have this as a language extension, let the compiler generate the right code.
But I can live with the annotation

patrikbeno
Offline
Joined: 2004-10-11
Points: 0

Language extension means new keywords and so on. Ypou have to be careful. Annotation does not break anything