patternjavaMinor
Dynamic data object generation
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 "
```
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
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
It may not be applicable for
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.