I need to create immutable copy of an object in runtime with Java. I made use of org.springframework.cglib.beans.ImmutableBean, which can create immutable copy of an object using CGLIB.
But the problem is that it provides "first-level" immutability: it disallows change of an input object's properties, but it allows to change inner objects (e.g. get collection and add an element to it or get inner object and modify it's parameters etc.)
So the question is: what's the correct way of creating deep (recursive) immutable copy of an object so that one can't change inner objects also (at any level of nesting)?
You may traverse the object tree and use CGLIB to make each object immutable by using interceptor which skips required methods. The tough part though is to determine all methods which modify the object's state - for each object in the tree.
package ut.test;
import static org.junit.Assert.assertEquals;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import org.junit.Test;
import com.google.common.collect.Lists;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
public class MyTest {
public static class Inner {
private String data = "hello";
public Inner() {}
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
#Override
public String toString() {
return data;
}
}
public static class Outer {
private List<Inner> list = Lists.newArrayList(new Inner());
public Outer() {}
public List<Inner> getList() {
return list;
}
public void setList(List<Inner> list) {
this.list = list;
}
}
public static class GetOnlyDelegatingMethodInterceptor implements MethodInterceptor {
private Object delegate;
public GetOnlyDelegatingMethodInterceptor(Object delegate) {
this.delegate = delegate;
}
#Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
if (method.getName().startsWith("get")) {
return makeImmutable(proxy.invoke(delegate, args));
}
if (method.getName().equals("toString")) {
return proxy.invoke(delegate, args);
}
if (method.getDeclaringClass().equals(Object.class)) {
return proxy.invoke(delegate, args);
}
// you may check for other methods here
// skip all others
return null;
}
}
private static Object makeImmutable(Object obj) {
if (obj == null) {
return obj;
}
Enhancer e = new Enhancer();
e.setSuperclass(obj.getClass());
e.setCallback(new GetOnlyDelegatingMethodInterceptor(obj));
return e.create();
}
#Test
public void testImmutable() {
Outer outerImmutable = (Outer) makeImmutable(new Outer());
// this is initial state
assertEquals(outerImmutable.getList().toString(), "[hello]");
// trying to set empty list
outerImmutable.setList(new ArrayList<>());
// but it's still the same
assertEquals(outerImmutable.getList().toString(), "[hello]");
// going deeper
outerImmutable.getList().get(0).setData("bye!");
// but still no changes
assertEquals(outerImmutable.getList().toString(), "[hello]");
}
}
You can use ImmutableProxy of the reflection-util library.
Example:
public class Inner
{
private String data = "hello";
// getters and setters
}
public class Outer
{
private List<Inner> list = Arrays.asList(new Inner());
// getters and setters
}
Outer outerImmutable = ImmutableProxy.create(new Outer());
Inner firstElement = outerImmutable.getList().get(0)
// this is initial state
assertThat(firstElement.getData()).isEqualTo("hello");
// throws UnsupportedOperationException
outerImmutable.setList(…);
// throws UnsupportedOperationException
firstElement.setData("bye!");
Related
I have a problem that I cannot understand. First of all, I want to denote my structure:
I have a class named ClassMetadata. It is metadata about class values:
public class ClassMetadata<T extends Object> {
private int serviceId;
private int typeId;
private int revisionId;
#SuppressWarnings("rawtypes")
private Class clazz;
private ClassAttribute[] classAttributeArray;
private ClassMetadata() {
}
public ClassMetadata(int serviceId, Class<T> clazz) {
this();
this.serviceId = serviceId;
this.clazz = clazz;
}
#SuppressWarnings("unchecked")
public Class<T> getClazz() {
return clazz;
}
// getters and setters
}
Argument is a class that responsible from conveying class argument to a function:
public class Argument<T> {
private ClassMetadata<T> classMetadata;
private T sample;
public Argument(ClassMetadata<T> classMetadata, T sample) {
super();
this.classMetadata = classMetadata;
this.sample = sample;
}
// getters and setters
#SuppressWarnings({ "rawtypes", "unchecked" })
public boolean isAssignableFrom (Class classInstance) {
if (classInstance == null || this.classMetadata == null)
return false;
Class localClassValue = this.classMetadata.getClazz();
if (localClassValue == null)
return false;
return localClassValue.isAssignableFrom(classInstance);
}
}
I have an IRepositoryEntityFramework interface that manages database interactions of a project:
package authority.core.dataaccess.entityframework;
import java.util.List;
import javax.persistence.PersistenceException;
public interface IRepositoryEntityFramework<T> extends AutoCloseable {
void add(T value) throws PersistenceException;
void update(T value) throws PersistenceException;
void delete(T value) throws PersistenceException;
//commit
void save() throws PersistenceException ;
List<T> readList(SQL sqlClause) throws IllegalStateException, PersistenceException;
}
I have a IAuthorityDetailRepository that responsible specifically AuthorityDetail entity's database operations:
package authority.repository.conceptual;
import authority.core.dataaccess.entityframework.IRepositoryEntityFramework;
import authority.entities.concrete.AuthorityDetail;
public interface IAuthorityDetailRepository extends IRepositoryEntityFramework<AuthorityDetail> {
}
When I call the clauses below, isAssignableFrom returns false:
IAuthorityDetailRepository authorityDetailRepository = DependencyResolver.getSample().resolve(IAuthorityDetailRepository.class);
ClassMetadata<IAuthorityDetailRepository> authorityDetailRepositoryMetadata = new ClassMetadata(3,IAuthorityDetailRepository.class );
Argument<IAuthorityDetailRepository> authorityDetailRepositoryArgument = new Argument<IAuthorityDetailRepository>(authorityDetailRepositoryMetadata, authorityDetailRepository);
authorityDetailRepositoryArgument.isAssignableFrom(IRepositoryEntityFramework.class);
However, the clauses below return true;
#SuppressWarnings("rawtypes")
Class localClassValue = IAuthorityDetailRepository.class;
#SuppressWarnings("rawtypes")
Class argumentClassValue = IRepositoryEntityFramework.class;
localClassValue.isAssignableFrom( argumentClassValue);
What am I missing?
Thanks in advance.
Update-1
As Mr. Sergey Kalinichenko pointed out that Argument was missing, which implements the failing isAssignableFrom method.
As java.lang.Class#isAssignableFrom JavaDoc says:
Determines if the class or interface represented by this Class object is either the same as, or is a superclass or superinterface of, the class or interface represented by the specified Class parameter. It returns true if so; otherwise it returns false.
So, it returns true when called next way:
Base.class.isAssignableFrom(Child.class); // true
In your case, you're calling
IAuthorityDetailRepository.class.isAssignableFrom(IRepositoryEntityFramework.class)
Since IAuthorityDetailRepository is a child of IRepositoryEntityFramework, method returns false. If you intended different behaviour, just swap localClassValue and classInstance.
return classInstance.isAssignableFrom(localClassValue);
I'm using an external library that provides tightly related classes (generated from some template), but unfortunately without a shared interface, e.g.
public class A {
public UUID id();
public Long version();
public String foo();
public String bar();
}
public class B {
public UUID id();
public Long version();
public String foo();
public String bar();
}
public class C {
public UUID id();
public Long version();
public String foo();
public String bar();
}
// ... and more: D, E, F, etc.
Given I have no influence over the external library, what's the idiomatic way to write logic common to a group of classes that share the same method signatures (at least, for the methods being used by the common logic)?
Currently I do one of three things, on a case-by-case basis:
I write helper methods that take the primitive results from each object, e.g.
private static void myHelper(UUID id, Long version, String foo, String bar) {
...
}
This way I can "unpack" an object regardless of its type:
myHelper(whatever.id(), whatever.version(), whatever.foo(), whatever.bar());
But that can get very wordy, especially when I need to work with many members.
In the scenario where I'm only working with getters (i.e. only need to access current values of the objects), I've found a way to use mapping libraries like Dozer or ModelMapper to map A or B or C to my own common class, e.g.
public class CommonABC {
UUID id;
Long version;
String foo;
String bar;
}
By playing with configuration, you can get these libraries to map all members, whether method or field, public or private, to your class, e.g.
modelMapper.getConfiguration()
.setFieldMatchingEnabled(true)
.setFieldAccessLevel(Configuration.AccessLevel.PRIVATE);
But this was kind of a "broadsword" approach, a hack that IMO isn't clearly justified merely to factor out duplicate code.
Finally, in certain other scenarios it was most succinct to simply do
private static void myHelper(Object extLibEntity) {
if (extLibEntity instanceof A) {
...
} else if (extLibEntity instanceof B) {
...
} else if (extLibEntity instanceof C) {
...
} else {
throw new RuntimeException(...);
}
}
It's obvious why this is bad.
In enterprise situations where you have to live with a library that is this way, what would you do?
I'm leaning toward writing a very explicit, if verbose, mapper (not using a generic mapper library) that translates these entities from the start. But, I wonder if there's a better way. (Like, is there a way to "cast" an object as implementing a new interface, in runtime?)
An option that is (under the hood) likely similar to the second approach, but comparatively lean and flexible, is to use Dynamic Proxy Classes. With only a few lines of code, you can let any object "appear" to implement a certain interface, as long as it has the required methods. The following is an MCVE that shows the basic approach:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.UUID;
public class DelegatingProxyExample {
public static void main(String[] args) {
A a = new A();
B b = new B();
C c = new C();
CommonInterface commonA = wrap(a);
CommonInterface commonB = wrap(b);
CommonInterface commonC = wrap(c);
use(commonA);
use(commonB);
use(commonC);
}
private static void use(CommonInterface commonInterface) {
System.out.println(commonInterface.id());
System.out.println(commonInterface.version());
System.out.println(commonInterface.foo());
System.out.println(commonInterface.bar());
}
private static CommonInterface wrap(Object object) {
CommonInterface commonInterface = (CommonInterface) Proxy.newProxyInstance(
CommonInterface.class.getClassLoader(),
new Class[] { CommonInterface.class }, new Delegator(object));
return commonInterface;
}
}
// Partially based on the example from
// https://docs.oracle.com/javase/8/docs/technotes/guides/reflection/proxy.html
class Delegator implements InvocationHandler {
private static Method hashCodeMethod;
private static Method equalsMethod;
private static Method toStringMethod;
static {
try {
hashCodeMethod = Object.class.getMethod("hashCode", (Class<?>[]) null);
equalsMethod = Object.class.getMethod("equals", new Class[] { Object.class });
toStringMethod = Object.class.getMethod("toString", (Class<?>[]) null);
} catch (NoSuchMethodException e) {
throw new NoSuchMethodError(e.getMessage());
}
}
private Object delegate;
public Delegator(Object delegate) {
this.delegate = delegate;
}
public Object invoke(Object proxy, Method m, Object[] args) throws Throwable {
Class<?> declaringClass = m.getDeclaringClass();
if (declaringClass == Object.class) {
if (m.equals(hashCodeMethod)) {
return proxyHashCode(proxy);
} else if (m.equals(equalsMethod)) {
return proxyEquals(proxy, args[0]);
} else if (m.equals(toStringMethod)) {
return proxyToString(proxy);
} else {
throw new InternalError("unexpected Object method dispatched: " + m);
}
} else {
// TODO Here, the magic happens. Add some sensible error checks here!
Method delegateMethod = delegate.getClass().getDeclaredMethod(
m.getName(), m.getParameterTypes());
return delegateMethod.invoke(delegate, args);
}
}
protected Integer proxyHashCode(Object proxy) {
return new Integer(System.identityHashCode(proxy));
}
protected Boolean proxyEquals(Object proxy, Object other) {
return (proxy == other ? Boolean.TRUE : Boolean.FALSE);
}
protected String proxyToString(Object proxy) {
return proxy.getClass().getName() + '#' + Integer.toHexString(proxy.hashCode());
}
}
interface CommonInterface {
UUID id();
Long version();
String foo();
String bar();
}
class A {
public UUID id() {
return UUID.randomUUID();
}
public Long version() {
return 1L;
}
public String foo() {
return "fooA";
}
public String bar() {
return "barA";
}
}
class B {
public UUID id() {
return UUID.randomUUID();
}
public Long version() {
return 2L;
}
public String foo() {
return "fooB";
}
public String bar() {
return "barB";
}
}
class C {
public UUID id() {
return UUID.randomUUID();
}
public Long version() {
return 3L;
}
public String foo() {
return "fooC";
}
public String bar() {
return "barC";
}
}
Of course, this uses reflection internally, and should only be used when you know what you're doing. Particularly, you should add some sensible error checking, at the place that is marked with TODO: There, the method of the interface is looked up in the given delegate object.
The only technique not tried:
package aplus;
public interface Common {
...
}
public class A extends original.A implements Common {
}
public class B extends original.B implements Common {
}
I have an third-party RPC-API that provides an interface similar to that of java.sql.ResultSet (for reading values) and java.sql.PreparedStatement (for writing values). Assume it looks something like this:
public interface RemoteDeviceProxy {
public void setBoolean(Boolean value);
public void setInteger(Integer value);
// ...
public Boolean getBoolean();
public Integer getInteger();
// ...
}
I want to write a wrapper for this API that uses generics to create instances of specific types:
public class <T> RemoteVariable {
private final RemoteDeviceProxy wrappedDevice;
public RemoteVariable(RemoteDeviceProxy wrappedDevice) {
this.wrappedDevice = wrappedDevice;
}
public T get() {
// should call wrappedDevice.getBoolean() if T is Boolean, etc.
// how to implement?
}
public void set(T newValue) {
// should call wrappedDevice.setBoolean(newValue) if T is Boolean, etc.
// implement using instanceof
}
}
How can I implement the getter in my generic wrapper? I have found this answer which explains a similar scenario in depth, but I am not able to transfer this to my problem. Specifically, when I write this:
public T get() {
Type[] actualTypeArguments = ((ParameterizedType) getClass())
.getActualTypeArguments();
}
I get a compiler error saying I cannot cast to ParameterizedType, and I do not understand why. Can anyone explain how to achieve this?
Here is one way:
public class <T> RemoteVariable {
private final RemoteDeviceProxy wrappedDevice;
private final Class<T> clazz;
public RemoteVariable(RemoteDeviceProxy wrappedDevice, Class<T> clazz) {
this.wrappedDevice = wrappedDevice;
this.clazz = clazz;
}
public T get() {
if(clazz == Boolean.class){return clazz.cast(wrappedDevice.getBoolean());}
else if(clazz == Integer.class){return clazz.cast(wrappedDevice.getInteger());}
// ...
}
// ...
}
I thought over this quite a while and finally came up with a different approach:
First I added a getter to you RemoteVariable class:
protected RemoteDeviceProxy getWrappedProxy() {
return wrappedProxy;
}
Second I created a builder interface that will be used by a factory later:
public interface RemoteVariableBuilder {
public <T> RemoteVariable<T> buildNewVariable(RemoteDeviceProxy wrappedProxy);
}
Then I created non generic sub classes for Boolean...
public class RemoteBooleanVariable extends RemoteVariable<Boolean> implements RemoteVariableBuilder {
public RemoteBooleanVariable(RemoteDeviceProxy wrappedProxy) {
super(wrappedProxy);
}
#SuppressWarnings("unchecked")
#Override
public <T> RemoteVariable<T> buildNewVariable(RemoteDeviceProxy wrappedProxy) {
return (RemoteVariable<T>) new RemoteBooleanVariable(wrappedProxy);
}
#Override
public Boolean get() {
return getWrappedProxy().getBoolean();
}
#Override
public void set(Boolean value) {
getWrappedProxy().setBoolean(value);
}
}
... and Integer ...
public class RemoteIntegerBuilder extends RemoteVariable<Integer> implements RemoteVariableBuilder {
public RemoteIntegerBuilder(RemoteDeviceProxy wrappedProxy) {
super(wrappedProxy);
}
#SuppressWarnings("unchecked")
#Override
public <T> RemoteVariable<T> buildNewVariable(RemoteDeviceProxy wrappedProxy) {
return (RemoteVariable<T>) new RemoteIntegerBuilder(wrappedProxy);
}
#Override
public Integer get() {
return getWrappedProxy().getInteger();
}
#Override
public void set(Integer value) {
getWrappedProxy().setInteger(value);
}
}
actually eclipse created most of the code once it knew base class and interface.
The final step was to create a factory
public class RemoteVariableFactory {
private static final Map<String, RemoteVariableBuilder> BUILDERS = new HashMap<>();
static {
BUILDERS.put(Boolean.class.getName(), new RemoteBooleanVariable(null));
BUILDERS.put(Integer.class.getName(), new RemoteIntegerBuilder(null));
// add more builders here
}
public static <T> RemoteVariable<T> getRemoteVariable(RemoteDeviceProxy wrappedProxy, Class<T> typeClass) {
RemoteVariableBuilder remoteVariableBuilder = BUILDERS.get(typeClass.getName());
if (remoteVariableBuilder == null) {
return null; // or throw an exception whichever is better in your case
}
return remoteVariableBuilder.buildNewVariable(wrappedProxy);
}
}
Now we are ready to create new RemoteVariables...
RemoteVariable<Boolean> var1 = RemoteVariableFactory.getRemoteVariable(new RemoteDevice(), Boolean.class);
RemoteVariable<Integer> var2 = RemoteVariableFactory.getRemoteVariable(new RemoteDevice(), Integer.class);
To conclude this let's do a quick comparison to the answer of Eng.Fouad:
Disadvantage:
you need to create a new class for every datatype you provide
Advantage:
you only have to add one line to the static block of the factory and not two new if blocks to the getter and setter in RemoteVariable
get and set do not have to work through the if-else-blocks every time
I have a primary class as below:
public class classB{
public classC getObject(String getstring){
return new classC(getstring);
}
}
The classC has a contructor:
public class classC{
String string;
public classC(String s){
this.string = s;
}
public methodC(int i){
<using the `string` variable here>
}
}
Now I've a classA which will be using the object created in classB(which is of course, an instance of classC).
public classA{
int a = 0.5;
<Get the object that was created in classB>.methodC(a);
}
This is needed as a variable is created on some actions from the user and stored in classB and this would be further used in classC's methods. Creating a new object will render my variable in classB set to null which isn't intended.
How can I achieve this?
Assume the Brand is a lightweight objects and Run is heavyweight then creating a field with the container for the lightweight objects and hiding it is a good idea.
But the Brand needs access the container it belongs to it could be done with the mapping but we are simply inject the Run to the Brand so it's better implement the Runable or annotate it with JSR330. And accessing the container through the Run in the normal way.
class MainClass {
public static void main(String[] args) {
Run r = new Run();
}
}
class Run {
private Container con1 = new Container();
public Run() {
Brand cola = new Brand("Coca Cola");
Brand pepsi = new Brand("Pepsi");
// Creates the container object "con1" and adds brands to container.
add(cola);
add(pepsi);
}
public void add(Brand b){
con1.addToList(b);
b.setRun(this);
}
public Container getContainer() {
return con1;
}
}
class Brand {
// In this class I have a method which needs to accsess the con1 object
// containing all the brands and I need to access the method
private String name;
private Run run;
public Brand(String name){
this.name = name;
}
public void brandMethod() {
if(getRun().getContainer().methodExample()) { // Error here. Can't find "con1".**
System.out.println("Method example returned true.");
}
}
public Run getRun() {
return run;
}
public void setRun(Run run) {
this.run = run;
}
}
class Container {
// This class is a container-list containing all brands brands
private ArrayList<Object> list = new ArrayList<Object>();
public boolean methodExample(){
return false;
}
public void addToList(Object o) {
list.add(o);
}
}
If you want to get the object created in classB a static field should do the job
public class classB {
public static objectCReference;
public classC getObject(String getstring){
objectCReference = new classC(getstring);
return objectCReference;
}
}
Then you can access the reference in A
public classA {
int a = 0.5;
if (classB.objectCReference != null) { // Make sure to null check
classB.objectCReference.methodC(a);
}
}
Also please follow the language conventions and start your class names with capital letters.
The JDK Proxy class only accepts interfaces in the factory method newProxyInstance().
Is there a workaround available, or alternative implementations?
The use cases are limited if I have to extract methods to an interface in order to enable them for use with a proxy. I would like to wrap them to apply annotation based actions during runtime.
public static <T> T getProxy(T obj) {
InvocationHandler ih = new InjectProxy( obj );
ClassLoader classLoader = InjectProxy.class.getClassLoader();
return (T) Proxy.newProxyInstance( classLoader, obj.getClass().getInterfaces(), ih );
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
}
You can use cglib like this:
import java.lang.reflect.Array;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
public class AbstractFactory {
#SuppressWarnings("unchecked")
public static <A> A createDefaultImplementation(Class<A> abstractClass) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(abstractClass);
enhancer.setCallback(new MethodInterceptor() {
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
if (!Modifier.isAbstract(method.getModifiers())) {
return methodProxy.invokeSuper(proxy, args);
} else {
Class type = method.getReturnType();
if (type.isPrimitive() && !void.class.equals(type)) {
return Array.get(Array.newInstance(type, 1), 0);
} else {
return null;
}
}
}
});
return (A) enhancer.create();
}
#SuppressWarnings("unchecked")
public static <A> A createDefaultImplementation(String className) throws ClassNotFoundException{
return (A) createDefaultImplementation(Class.forName(className));
}
}
This for example lets you build abstract classes with a default implementation method. But you can change the enhancer to what ever you want.
Is there a workaround available..?
Yeah. There is. Extract interface from existing classes.
upd
If you need it for some specific classes, you can write smt like
//interface that already exists
public interface IDomain {
String foo();
}
//your class
public class Domain implements IDomain{
public String foo(){
return "domain foo";
}
//method that doesn't placed in IDomain
public String bar(){
return "domain bar";
}
}
//So you need create new interface with bar()
//it can extend IDomain
public interface ExtendedIDomain extends IDomain {
public String bar();
}
//than your wrapper factory will be like this
public class Proxifier {
public static ExtendedIDomain getProxy(Domain obj) {
InvocationHandler ih = new InjectProxy( obj );
ClassLoader classLoader = InjectProxy.class.getClassLoader();
return (ExtendedIDomain) Proxy.newProxyInstance( classLoader, new Class[]{ExtendedIDomain.class}, ih );
}
static class InjectProxy implements InvocationHandler {
private final Domain domain;
private InjectProxy(Domain domain){
this.domain = domain;
}
public String invoke(Object proxy, Method method, Object[] args) throws Throwable{
for(Method m : domain.getClass().getMethods()){
//TODO: check signature(name, args etc) or implement some logic with annotations
if(m.getName().equals(method.getName())){
return "wrapped " + m.invoke(domain, args);
}
}
throw new IllegalArgumentException();
}
}
}
//test
public static void main(String[] args) {
ExtendedIDomain d = Proxifier.getProxy(new Domain());
System.out.println(d.foo());
System.out.println(d.bar());
}
If you need some "universal" stuff you should use AOP as #Peter Lawrey allready said.
or alternative implementations
You can use cglib.
Similar posts on alternatives to cglib : Are there alternatives to cglib?