casting base class to derived class via reflection - java

Hi I have to construct an object from an object. Since the base class has more than 50 fields i dont want to do things like
//obj1 is an instance of BaseClass
DerivedClass obj2 = new DerivedClass();
obj2.setField1(obj1.getField1());
obj2.setField2(obj1.getField2())
.... so on
As you see from the title i want to downcast my object but java does not allow this. Is there a utility library or smth that provides a method like
Object convert(BaseClass obj1, DerivedClass obj2)

You can use Apache Commons BeanUtils to do this. Using its BeanUtils class you have access to a lot of utility methods for populating JavaBeans properties via reflection.
To copy all the common/inherited properties from a base class object to a derived class object you can use its static copyProperties() method as
BeanUtils.copyProperties(baseClassObj, derivedClassObj);
From the BeanUtils.copyProperties() docs
Copy property values from the origin bean to the destination bean for all cases where the property names are the same.
If you don't want to use a third-party library, your next best option would be to provide a utility method on the derived class that initializes itself with all the properties of an instance of its parent class.
public void initFromParent(BaseClass obj) {
this.propOne = obj.getPropOne();
// ... and so on
}

You can downcast if the cast is valid:
BaseClass instance = new DerivedClass();
if(DerivedClass.class.isAssignableFrom(instance.getClass()) {
DerivedClass dc = DerivedClass.class.cast(instance);
}
But normally one would implement a constructor with the same arguments and call super().
Or even better, use composition, where instead of inheritance you have DerivedClass hold an instance of BaseClass and delegate calls for the fields to that object.

Related

ByteBuddy: Use new defined field in intercept during construction of class

I am looking at some ByteBuddy code from someone else. He uses ByteBuddy to generate runtime subclasses which are used as proxies to implement some management code of his runtime into specific objects.
Class<? extends T> newSubClass = new ByteBuddy(ClassFileVersion.ofThisVm())
.subclass(classType)
.defineField("_core", Object.class, Visibility.PUBLIC) //<---
.method(ElementMatchers.isDeclaredBy(classType))
.intercept(InvocationHandlerAdapter.of((proxy, method, m_args) -> {
//TODO: Need to replace core with _core as core is a function argument and will make it bound
return proxyHandler(core, method, m_args); //<--
}))
.make()
.load(roleType.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER)
.getLoaded();
T proxy = ReflectionHelper.newInstance(newSubClass, args);
newSubClass.getField("_core").set(proxy, core);
In order to not bind the core object directly into the lambda I want to use the new defined field _coreso I can reuse the generated class (and not regenerate it for every call of the function).
Is there a way to achieve this?
Thanks in advance.
You can define custom constructors just as you define methods. One important point for defining a constructor is that you require another constructor call as its first instruction. You can invoke a constructor using MethodCall::invoke which you can combine with FieldAccessor::ofField.
This way, you can define your class similar to the following:
new ByteBuddy(ClassFileVersion.ofThisVm())
.subclass(classType, ConstructorStrategy.Default.NO_CONSTRUCTORS)
.defineConstructor(Visibility.PUBLIC)
.withParameter(InvocationHandler.class)
.intercept(MethodCall.invoke(classType.getDeclaredConstructor())
.andThen(FieldAccessor.ofField("_core").setsArgumentAt(0)))
.defineField("_core", InvocationHandler.class, Visibility.PUBLIC)
.method(ElementMatchers.isDeclaredBy(classType))
.intercept(InvocationHandlerAdapter.toField("_core"))
.make();
This way, you can set a custom InvocationHandler per instance. If you want to only store the state in the _core field and access this field from your interceptor, have a look at MethodDelegation:
new ByteBuddy(ClassFileVersion.ofThisVm())
.subclass(classType, ConstructorStrategy.Default.NO_CONSTRUCTORS)
.defineConstructor(Visibility.PUBLIC)
.withParameter(Object.class)
.intercept(MethodCall.invoke(classType.getDeclaredConstructor())
.andThen(FieldAccessor.ofField("_core").setsArgumentAt(0)))
.defineField("_core", Object.class, Visibility.PUBLIC)
.method(ElementMatchers.isDeclaredBy(classType))
.intercept(MethodDelegation.to(MyHandler.class))
.make();
public class MyHandler {
#RuntimeType
public static Object intercept(#FieldValue("_core") Object value) { ... }
}
Other annotations you might need are #This, #AllArguments, #Origin and #SuperCall. The less you need, the more efficient your proxy will be. Especially #AllArguments is expensive due to its allocation requirements.
Note that in this case, your field is only set after the super constructor call. Also, you assume that there is a default constructor in the super type. Alternatively, you can implement a custom ConstructorStrategy.
As for caching, have a look at Byte Buddy's TypeCache.

Retrieving an instance using a string literal with Google Guice

I have multiple modules with service interfaces binding to their corresponding types and I am able to get an instance by using
injector.getInstance(MyServiceInterface.class)
I would like to retrieve the instance using
injector.getInstance("MyServiceInterface")
i.e. a string literal instead of the class type
How can I achieve this ?
To elaborate my question further - I can retrieve the Class object from the string literal using a Class.forName(literal) call and then use it to retrieve the instance with a injector.getInstance(clsInstance) .
After retrieving the instance which I receive in my base service type interface I need to use reflection to invoke the method of the service object.
so Service serv = injector.getInstance(MyCustomService.class)
Now I need to invoke myCustomMethod() present in MyCustomService through reflection since this invoker is generic and is intended to work with multiple services without being aware of their actual type.
I will also need the Method interceptors configured on the service interfaces to be invoked transparently when I invoke the method on this instance reflectively.
While I'm not certain if there's functionality for that built into Guice itself, you could try getting the relevant Class<?> object yourself.
Something along the lines of:
Class<?> myServiceInterfaceClass = Class.forName("path.to.MyServiceInterface");
injector.getInstance(myServiceInterfaceClass);
This does however require that the current Classloader can access that specific class, etc.
This can't be done within Guice... because it can't be done, period! Think about it, let's say you have two of the same class name in different packages. Which class would you instantiate?
So at the very least the String would have to have the fully qualified class name, e.g. instead of Integer, it would have java.lang.Integer.
However, if you know which classes you want to support in advance, you can use a MapBinder.
Tweaking their example to match your use case:
public class ServiceModule extends AbstractModule {
protected void configure() {
MapBinder<String, MyServiceInterface> mapbinder
= MapBinder.newMapBinder(binder(), String.class, MyServiceInterface.class);
mapbinder.addBinding("MyServiceInterface").to(MyServiceImpl.class);
bind(MyServiceInterface.class).to(MyServiceImpl.class);
}
}
Now you can inject like this:
class ServiceManager {
#Inject
public ServiceManager(Map<String, MyServiceInterface> services) {
MyServiceInterface service = stacks.get("MyServiceInterface");
// etc.
}
}
Please note when you call inj.getInstance() you do have to know the return type of the Object you're trying to create, unless you are planning on doing:
Object foo = inj.getInstance(myString);

Alternative way to instantiate a class not implements the parent interfaces

At somewhere, that I can not remember, I read about an alternative way to instatiate a object:
Generally, we instantiate (and assign) this way:
User userObj = new User();
userObj.setId(1);
userObj.setName("Foo");
An alternative way could be:
User userObj = new User()
{{
setId(1);
setName("Foo");
}}
I was using this alternative, and it works.
1) Anyone knows what is it? Where is Java documentation link that metion about it?
I stop to use this because I was having problems with interfaces that ClassName implements, but the alternative way don't implements. Oo
public class User implements Serializable
{
private int id;
private String name;
//public Getters and Setters
}
2) When I try to serialize and use it (passing from one activity to another, using:
putExtra(String, Serializable)
it will throw NotSerializableException. Why?
Edit 1: An anonnymous class also implements the parent 'implementations', like Serializable from ClassName?
You are using anonymous class with initialization block. So it's just an equivalent to the:
SubClass extends ClassName{
{
classObj.setParam1(1);
classObj.setParam2(1);
}
}
new SubClass();
There is nothing wrong with this construction - but please notice that you are not creating object of ClassName class, but object of SubClass class.
As I said you are using anonymous class (class without name). This is bad - cause while serialization / deserialization JVM should exactly know what is the class of serialization data, so basically - don't use anonymous classes if you want to serialize them.
Ad 1.: This construct ist called "anonymous class".
Ad 2.: I bet your class contains a field which is not Serializable.

How do I typecast an object created through reflection to run a method?

I'm having trouble to find how to typecast the dynamically created class while using reflection.
String s;
...
Class unknownClass = Class.forName(s);
Constructor defaultConstructor = unknownClass.getConstructor(null);
Object retobj = defaultConstructor.newInstance(null);
retobj.Writeout(); // This won't work since;
The object class does not have a method called Writeout, but that is the name of the method which is shared by nine other possible classes that is dynamically created here (needless to say every Writeout method does a seperate thing). Any suggestions ? Thx in advance for your time.
Use reflection Luke...
Method writeOutMethod = unknownClass.getMethod("Writeout", new Class[]{});
writeOutMethod.invoke(retobj, new Object[]{});
Or, ensure that your objects implement a well known interface (the clean approach).
The 9 classes should all implement a single interface (let's call it Output) which declares the writeOut() method. The code would thus be:
Output retobj = (Output) defaultConstructor.newInstance(null);
retobj.writeOut();
Note that you could just use unknownClass.newInstance() to invoke the no-arg constructor.
Side note: please respect tha Java naming conventions: methods start with a lower-case letter.
Cast it:
((YourObjectWithThatMethod) retobj).Writeout();
EDIT (see the comment from Kevin Welker):
If all of your 9 classes implement the same interface, you can cast every class to that interface:
((YourInterface) retobj).Writeout();
If all nine classes share a super-class or an interface which declares/implements writeOut then you can cast retobj to that interface and then call it.
public interface Writable {
public void writeOut();
}
Then each class needs to have in the class declaration.
class MyClass implements Writable {
}
Then you can say
((Writable) retobj).writeOut();

A way to use a string for creating new classes

I have a string with the name of a class, is there a way (writing in Java) to use that string when creating a new instance of that class, to do something like this:
object obj = new dataInString.
So the dataInString is parsed from the string.
Do you mean something like Class.forName(String)? Quoting the javadoc of the method:
Returns the Class object associated with the class or interface with the given string name. Invoking this method is equivalent to:
Class.forName(className, true, currentLoader)
where currentLoader denotes the defining class loader of the current class.
For example, the following code fragment returns the runtime Class descriptor for the class named java.lang.Thread:
Class t = Class.forName("java.lang.Thread")
A call to forName("X") causes the class named X to be initialized.
And then, call Class#newInstance() on the returned Class (it must have an empty constructor).
Creates a new instance of the class represented by this Class object. The class is instantiated as if by a new expression with an empty argument list. The class is initialized if it has not already been initialized.
Assuming that the class has a no-args constructor, then the following should do the trick
Class<?> clazz = Class.forName("someclass");
Object obj = clazz.newInstance();
If you need to create the object using a different constructor, then you will need to do something like this:
Constructor<?> ctor = clazz.getConstructor(ArgClass.class, Integer.TYPE);
Object obj = ctor.newInstance(arg, Integer.valueOf(42));
There are a number of checked exceptions that need to be handled in either case ...
You can use reflection.
Use reflections to instantiate objects. A simple class.forName("com.blah.blah") should be a good starting point to look for more information on reflections.

Categories

Resources