views:

563

answers:

9

I hate the JavaBeans pattern with a passion that burns like the fire of a thousand suns. Why?

  • Verbose. It's 2009. I shouldn't have to write 7 LOC for a property. If they have event listeners then hold on to your hat.
  • No type-safe references. There is no type-safe way to reference a property. The whole point of Java is that it is type safe, and its most popular pattern is not at all typesafe.

What I would like is something like:

class Customer {
    public Property<String> name = new Property();
}

I am a web developer mostly, so it needs JPA and Wicket support.

Help me off the javabean train!

+3  A: 

You may want to check out Groovy - a dynamically typed, JVM-based (and fully Java-compatible) language with "real" properties.

Michael Borgwardt
I second Groovy. +1
Adeel Ansari
Unfortunately Groovy is not an option for me at work.
SamBeran
A: 

You could also build a code generator which creates your .java classes from a DSL that you write. You could have some kind of markup that describes the name of your class, the properties you want, and their types. Then, process that file with a program that generates your javabeans. Or you could use annotation, and post-process the class files using something like ASM to inject the accessors & mutators. I believe also that Spring provides some of these kind of features, but I've not used them.

Arcane
Definitely an approach that would work, but I think it missed the point of the post: he finds JavaBeans too verbose and complex. Doesn't adding another layer via DSL or annotations and post-processing just make that worse?
Ian Varley
@ian: DSL may not be a bad idea, because using DSL tend to make things succinct and concise, exactly the goals of the poster.
Chii
@ian: In the short term, I would agree, because of the effort required to create the post-processor. However, once that's done the code which uses it would be simpler in the way requested.
Arcane
A: 

For the web, I would suggest JSON (JavaScript Object Notation),

a lightweight data-interchange format

. Here is a reference to a JSON?Bean translator.

WolfmanDragon
+7  A: 

I think you're pretty close with the declaration you have there (see below for a sketch). However, by using a non-beans approach, you'll probably lose support provided by most tools that assume the JavaBeans protocol is in effect. Please be kind. The code below is off the top of my head...

public class Property<T> {
    public final String name;
    T value;
    private final PropertyChangeSupport support;

    public static <T> Property<T> newInstance(String name, T value, 
                                              PropertyChangeSupport support) {
        return new Property<T>(name, value, support);
    }

    public static <T> Property<T> newInstance(String name, T value) {
        return newInstance(name, value, null);
    }

    public Property(String name, T value, PropertyChangeSupport support) {
        this.name = name;
        this.value = value;
        this.support = support;
    }

    public T getValue() { return value; }

    public void setValue(T value) {
        T old = this.value;
        this.value = value;
        if(support != null)
            support.firePropertyChange(name, old, this.value);
    }

    public String toString() { return value.toString(); }
}

and then go ahead and use it:

public class Customer {
    private final PropertyChangeSupport support = new PropertyChangeSupport();

    public final Property<String> name = Property.newInstance("name", "", support);
    public final Property<Integer> age = Property.newInstance("age", 0, support);

    ... declare add/remove listenener ...
}


Customer c = new Customer();
c.name.setValue("Hyrum");
c.age.setValue(49);
System.out.println("%s : %s", c.name, c.age);

So, now declaring a property is a single line of code and property change support is included. I called the methods setValue() and getValue() so it would still look like a bean to code like Rhino and stuff, but for succinctness, you could add just get() and set(). The rest is left as an exercise for the reader:

  • Properly handle serialization
  • Handle null value checking
  • Maybe add a specializations for atomic types if you care about autoboxing overhead.
  • ?? I'm sure there are more gotchas

Also note that you can subclass (usually as an anonymous class) and override setValue() to provide additional parameter checking.

I don't think you can really get away from "String references" since that's pretty much what reflection's all about.

Sadly though, in this day and age, this is still kind of like programming in assembly... Groovy, C#, etc, etc may still be a better choice, if you have a choice.

Dave Ray
I like this - I figured someone would have done this before, but I guess not...
SamBeran
I'm willing to bet that *many* people have done it before, forever entombed in internal corporate source code repositories ;)
Dave Ray
True that - maybe it's time for a google code project.
SamBeran
A: 

Try SEAM framework from JBoss, you should like it.

Maksim
A: 

Once I tried this:

interface IListenable {
    void addPropertyChangeListener( PropertyChangeListener listener );
    void removePropertyChangeListener( PropertyChangeListener listener );
}

abstract class MyBean extends IListenable {
    public abstract void setName(String name);
    public abstract String getName();

    // more things
}

public class JavaBeanFactory {

   public <T> Class<T> generate(Class<T> clazz) {
      // I used here CGLIB to generate dynamically a class that implements the methods:
      // getters
      // setters
      // addPropertyChangeListener
      // removePropertyChangeListener
   }
}

I used that as this (it is just an example):

public class Foo {
    @Inject
    public Provider<MyBean> myBeanProvider;

    public MyBean createHook(MyBean a) {
        final MyBean b  = myBeanProvider.get();
        a.addPropertyChangeListener(new PropertyChangeListener() {
             public void propertyChange(PropertyChangeEvent evt) {
                 b.setName((String) evt.getNewValue());
             }
        });
        return b;
    }
}
Banengusk
+2  A: 

Use the Spring Framework. Its purpose is to simplify Java development by abstracting a lot of the groundwork that you are complaining about.

You can use it with Hibernate which will ease interation with data sources for you.

Useful sites:

www.springsource.org/download

www.hibernate.org/

Lonzo
+3  A: 

Check out my Bean annotations at

http://code.google.com/p/javadude/wiki/Annotations

Basically you do things like:

@Bean(
  properties={
    @Property(name="name"),
    @Property(name="phone", bound=true),
    @Property(name="friend", type=Person.class, kind=PropertyKind.LIST)
  }
)
public class Person extends PersonGen {}

rather than defining all those extra get/set etc methods yourself.

There are other attributes to define equals/hashCode, observers, delegates, mixins, etc.

It's a set of annotations and an annotation processor that runs in eclipse or in a command-line build (in ant for example). The processor generates a superclass to contain all the generated code (annotation processors cannot change the class containing the annotations, btw)

Enjoy! -- Scott

Scott Stanchfield
+1  A: 

When I used C# the first times, I liked the properties, but now, after some time using them with VS 2008 I have to say that I prefer the set-/get-methods.

The main point is my personal way of working. When I have a new class and I would like to know what I can do with it, I just type classname.set and Eclipse shows me what "Properties" I can change. Same goes for get. Maybe its just the poor VS way but there the I have to scoll through a long list of this itelisense (where everything is mixed, instead of showing properties first) just to find out after I compiled that the property I wanted to set is readonly...doh!

Yes, in Java you need a lot of lines, but I just write my attributes and tell the IDE "please create getters and setters for me". But those methods tend to use a lot of space, thats why I would like to have regions in Java as well that I can fold in the IDE.

lostiniceland