Java – create immutable objects using JAXB
I am using JAXB to create Java objects from XSD files I'm creating immutable wrappers to hide JAXB generated objects (I was updating JAXB objects to implement immutable interfaces and return to the client, but I realized that changing automatically generated classes is not good, so I used wrappers)
For now, I return these non - convertible wrappers to the client application Whether there are any options so that the automatically generated class will be immutable, it will avoid the extra work of creating immutable wrappers Encourage any other method
>Thank you
Solution
You can create a proxy server for you before returning the bean to the client You will need javassist to create proxies from classes (directly from Java se to create proxies from interfaces)
Then, if you call a method starting with "set", you can throw an exception
This is a reusable class that can wrap "any" POJO methods:
import java.lang.reflect.Method; import javassist.util.proxy.MethodFilter; import javassist.util.proxy.MethodHandler; import javassist.util.proxy.Proxy; import javassist.util.proxy.ProxyFactory; public class Utils { public static <C> C createInmutableBean(Class<C> clazz,final C instance) throws InstantiationException,illegalaccessexception { if (!clazz.isAssignableFrom(instance.getClass())) { throw new IllegalArgumentException("given instance of class " + instance.getClass() + " is not a subclass of " + clazz); } ProxyFactory f = new ProxyFactory(); f.setSuperclass(clazz); f.setFilter(new MethodFilter() { public boolean isHandled(Method m) { // ignore finalize() return !m.getName().equals("finalize"); } }); Class c = f.createClass(); MethodHandler mi = new MethodHandler() { public Object invoke(Object self,Method m,Method proceed,Object[] args) throws Throwable { if (m.getName().startsWith("set")) { throw new RuntimeException("this bean is inmutable!"); } return m.invoke(instance,args); // execute the original method // over the instance } }; C proxy = (C) c.newInstance(); ((Proxy) proxy).setHandler(mi); return (C) proxy; } }
Here is a sample code Make employees your beans:
public class Employee{ private String name="John"; private String surname="Smith"; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getSurname() { return surname; } public void setSurname(String surname) { this.surname = surname; } };
Here is a test case that shows that you can create a proxy for POJO and use its getter, but not its setter
@Test public void testProxy() throws InstantiationException,illegalaccessexception{ Employee aBean = new Employee(); //I can modify the bean aBean.setName("Obi-Wan"); aBean.setSurname("Kenobi"); //create the protected java bean with the generic utility Employee protectedBean = Utils.createInmutableBean(Employee.class,aBean); //I can read System.out.println("Name: "+protectedBean.getName()); System.out.println("Name: "+protectedBean.getSurname()); //but I can't modify try{ protectedBean.setName("Luke"); protectedBean.setSurname("Skywalker"); throw new RuntimeException("The test should not have reached this line!"); }catch(Exception e){ //I should be here System.out.println("The exception was expected! The bean should not be modified (exception message: "+e.getMessage()+")"); assertEquals("Obi-Wan",protectedBean.getName()); assertEquals("Kenobi",protectedBean.getSurname()); } }