HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavaMinor

Dynamic data object generation

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
objectdatagenerationdynamic

Problem

Last weekend I had an idea: Why not remove dozens of classes by removing all the basic get/set/equals/hashCode implementation of my data object interfaces? I tend to code against interfaces, so I normally end up, for example, with an "Account" interface and at least one implementation (AccountImpl), etc. But most of the time these implementations are horribly boring (member, get, set, equals, hashCode, done), so why not free up the disk space (just joking) and remove the explicit code, replacing it by a dynamic object (I had the idea when reading about project Lombok, which sounds cool, but seems to rely on some "hacks")?

```
import java.io.Serializable;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.Map;

public class ProxyUtil {

public static T createDataObject(final Class dataClassInterface) {
return dataClassInterface.cast(Proxy.newProxyInstance(dataClassInterface.getClassLoader(), new Class[] { dataClassInterface }, new DataInvocationHandler(dataClassInterface)));
}
}

class DataInvocationHandler implements InvocationHandler, Serializable {

private static final long serialVersionUID = 8288151104916240843L;
private final Map variables = new HashMap();
private final Class interfaceClass;

DataInvocationHandler(final Class interfaceClass) {
this.interfaceClass = interfaceClass;
}

DataInvocationHandler(final Class interfaceClass, final Map variables) {
this(interfaceClass);
if (variables != null) {
this.variables.putAll(variables);
}
}

@Override
public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {

final String methodName = method.getName();

if (methodName.startsWith("get")) {
final String variable = methodName.substring("get".length());
return this.variables.get

Solution

I have the nagging feeling that it's not something you "should" do.

For starters, getters and setters are often used to provide some kind of field validation, or to return read-only views on the underlying field. More importantly, you will totally lose the ability to make thread-safe immutable classes instances using this approach. Sure, if you realized all you are dealing with are nothing more than a skeleton of getters and setters, this proxy-based approach might seem plausible, but you will be trading flexibility for functionality...

Code-wise, may I suggest that you flip the constructor-chaining of DataInvocationHandler so that the one will the least arguments 'pass-through' to the next?

DataInvocationHandler(final Class interfaceClass) {
    this(interfaceClass, null);
}

DataInvocationHandler(final Class interfaceClass, final Map variables) {
    this.interfaceClass = interfaceClass;
    if (variables != null) {
       this.variables.putAll(variables);
    }
}


It may not be applicable for DataInvocationHandler since it does not have final fields that needs to be set upon object instantiation, but flipping the constructor-chaining lets you centralize all the fields to set in one single constructor, eliminating compiler errors that tell you about fields not being set.

Code Snippets

DataInvocationHandler(final Class<?> interfaceClass) {
    this(interfaceClass, null);
}

DataInvocationHandler(final Class<?> interfaceClass, final Map<String, Object> variables) {
    this.interfaceClass = interfaceClass;
    if (variables != null) {
       this.variables.putAll(variables);
    }
}

Context

StackExchange Code Review Q#100455, answer score: 3

Revisions (0)

No revisions yet.