I find myself in the unfortunate position of using a lot of JavaBeans. I say unfortunate because I don't like that they are mutable. So after I create the beans (I am converting them from JSON using Jackson), I would like to "freeze" the beans at a specified moment to ensure they aren't mutated down the line.
I don't have the capacity to write Mutable/Immutable versions of each and every bean, nor custom Jackson factories, so I'm looking for a library or function call much like Collections.unmodifiableCollection(...);
but for beans.
(Yes I know that is not truly freezing it if the original bean gets leaked. But I'll wrap or freeze them right after creation and never use the original again.)
Any ideas?
Are you beans interface based or pojos ? If they're interface based, you could simply write a utility method:
public class ImmutableBean {
public static <T> T makeImmutable(T t) { ... }
}
You could then create a java.lang.Proxy instance which would either be specific to your bean, or look for patterns like methods starting with "set", and throw some particular exception. Here's a good short tutorial on creating a proxy instance: http://www.javalobby.org/java/forums/t18631.html
If they are pojo's, you should be able to use a library like javassist or cglib to create an enhanced version where your setters are stubbed to throw an exception.
Here's a javassist example:
public static <T> T makeImmutable(final T t) throws NotFoundException, InstantiationException, IllegalAccessException {
MethodHandler mh = new MethodHandler() {
@Override
public Object invoke(java.lang.Object self, java.lang.reflect.Method thisMethod, java.lang.reflect.Method proceed, java.lang.Object[] args) throws Throwable {
if (thisMethod.getName().startsWith("set")) {
throw new UnsupportedOperationException();
}
return proceed.invoke(t, args);
}
};
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setSuperclass(t.getClass());
Class<T> clazz = (Class<T>) proxyFactory.createClass();
T instance = clazz.newInstance();
((ProxyObject)instance).setHandler(mh);
return instance;
}
This does however, this will require that your original class have a no-arg constructor, so you might have to do a specific method for your class if you don't have a no arg constructor.
Google found this when I searched on "java beans jackson immutable":
http://www.cowtowncoder.com/blog/archives/2010/08/entry_409.html
I don't know if it works, but the article claims to be able to do it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With