Saturday, October 28, 2006

PropertyDescriptor in JavaBeans

Does the JavaBeans framework have too many assumptions exposed? Does it suffer from a lack of encapsulation? I'm not talking about JavaBeans, but the framework that enables JavaBeans. Go take a quick look at PropertyDescriptor and what do you see? It knows a lot of things including read and write methods. What could be so wrong? For one, it's a dumb object (ala data structure), but that's not a bad thing given its name. But, I think it's powerless. It exposes all of its internals and has no encapsulation. But, this is a simple framework, why is that bad?

OK, it's time for an example. Spring is all of the rage (and rightfully so) and injects by the exposed writer methods in an object. But, wouldn't be nice not to expose them, but give Spring priviledged access to these fields and basically disallow ordinary access. What if I could have a custom PropertyDescriptor for just those fields. Well....

Right now, I could have a private writer and have a custom PropertyDecsriptor to grant access to it. But, what if I didn't want to add unnecessary noise to my class? Besides, it seems like a lot of trouble. Let's dream for a bit shall we?

What if instead of having getReaderMethod() and getWriterMethod(), we had getPropertyAccessor()? What would this new method return? How about this:
public interface PropertyAccessor {
Object get(Object receiver);
void set(Object receiver, Object newValue);
}

And this would be the default implementation:
public class MethodPropertyAccessor implements PropertyAccessor {
private Method reader;
private Method writer;

public MethodPropertyAccessor(Method reader, Method writer) {
this.reader=reader;
this.writer=writer;
}
public Object get(Object receiver) {
try {
return reader.invoke(object, null);
} catch(...PlethoraOfReflectionExceptions) {
throw new RuntimeException(reflectionException);
}
}
public void set(Object receiver, Object newValue) {
try {
writer.invoke(object, new Object[] {newValue});
} catch(...PlethoraOfReflectionExceptions...) {
throw new RuntimeException(reflectionException);
}
}
}

More of the knowledge in how to get/set properties in the object are known to the PropertyAccessor. We could then provide our own PropertyAccessors like we could have one built by giving it the Field itself. Like this:
public class DirectAccessPropertyAccessor implements PropertyAccessor {
private Field property;

public DirectAccessPropertyAccessor(Field property) {
this.property=property;
this.property.setAccessible(true);
}
public Object get(Object receiver) {
try {
return property.get(receiver);
} catch(...PlethoraOfReflectionExceptions...) {
throw new RuntimeException(reflectionException);
}
}
public void set(Object receiver, Object newValue) {
try {
property.set(receiver, newValue);
} catch(...PlethoraOfReflectionExceptions...) {
throw new RuntimeException(reflectionException);
}
}
}

Users of the PropertyAccessor would not have to know how the field is accessed (whether via methods or direct access or by going through other objects). By hard-wiring to always use methods, the JavaBeans framework has exposed too much of its internal implementation to the outside world. If they would have hidden more, it would have been more flexible. Of course, the examples need more fleshing out to handle things like primitives (but, you're not using those anymore are you since you have autoboxing, right?).

I wanted to show this as a simple example of why encapsulation is good. I've made the code more flexbile, simpler, and easier to test even. The PropertyAccessor is simply a facade around the business of accessing a field. Pretty simple stuff.

Just think if you had this with so many java frameworks that use JavaBeans. Wouldn't it be nice?

No comments: