Suppose I have a unknown interface, and I want to be able to construct an object which, when user calls some method from interface on it, returns something specified by that interface.
E.g. having a Class class object, representing unknown Interface, I want to be able to construct an Object, which behaves like something which correctly implements that Interface.
For instance, say I'm working on method
public <E> E myMethod(Class<E> class){
...
return res;
}
Where class is representation of an unknown interface, let for instance
public <E> interface Writer{
public String write(String s);
}
Class<E> class = Writer.class;
All I want now is that any call like
returnedFromMyMethod.write(s);
actually do the job, e.g. returns given string
I know that there's reflection to be used, because all of that is going on in runtime, we don't know what exactly the interface is. But can't figure it out. Any ideas?
EDIT: To avoid misunderstanding.
That's all going in runtime. I don't know what that interface is.
It can be Writer as possibly as Runnable, Comparable or any
other. It is for sure one interface.
Our object doesn't
exist, it hasn't got any of methods we want. It's like constructing
a new object (of parametrized type) from zero.
So question is about creating an object that imitates implementing all methods from given interface
You can create a dynamic proxy:
#SuppressWarnings("unchecked")
public static <E> E myMethod(Class<E> cls) {
return (E) Proxy.newProxyInstance(cls.getClassLoader(), new Class[] { cls },
(Object proxy, Method method, Object[] arguments) -> {
// handle the invocation of the given method
return null; // return something actual
});
}
Writer result = makeProxy(Writer.class); // e.g.
As long as you have a plan for how to handle the invocations. Of course there is no way to do that out 'automagically'.
Change your method and interface as
public <E extends Writer> E myMethod(Class<E> clazz) {
...
return res;
}
public interface Writer {
public String write(String s);
}
Now you will be able to call write(String s) method on the return value of myMethod(Class<E> clazz).
Writer w = myMethod(WriterImpl.class);
w.write("any string");
You can put that class into a java decompiler such as javadecompilers.com and then you can find out what interface it extends, or you can go the reflection route like this:
//Assuming the class only extends 1 interface you can do this
Class<?>[] interfaces = class.getClass().getInterfaces();
//Now since we know interfaces[0] is the desired interface, we can get its name
System.out.printLn(intefaces[0].getName()); //You don't have to print the name if you're just going to continue with reflection
//now we're going to define the s variable which will hold what the method returns
String result = "";
//Next using reflection we're going to get the desired method, invoke it, give reflection it's return type and your argument
try {
result = interfaces([0].getMethod("write").invoke(String.class, args);
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException
| SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
This is what you could do if you wished to use reflection.
On the contrary, if I have miss understood what the question was, any Class that implements an Interface automatically has those methods to be called. Therefore, doing class.write(s); would return a String just like normal.
Related
Say I have a 3 generic parameters:
public static interface Mapper<V,T,E> {
public void map(KeyValue<V> v, AsyncCallback<T,E> cb);
}
How can I make the parameters optional? How can I give the parameters default values if the user only supplies the first parameter?
Using TypeScript, that would look like:
public static interface Mapper<V,T = any,E = any> {
public void map(KeyValue<V> v, AsyncCallback<T,E> cb);
}
so if the user doesn't supply T and E, they default to any. Is there a way to do this with Java?
If what you have in mind is something along the lines:
Having a method that takes 3 (generic) parameters
But at times you'll want it to have 2 parameters
Then, the following is the way to approach this. Since otherwise making parameters optional is not allowed in my opinion.
interface InterfaceA<T, T> {
boolean myMEthod(T clazz, UserRef user, String type, T clazz2) {
return false;
}
}
interface InterfaceB<T> extends InterfaceA<T, T> {
default boolean myMEthod(T clazz, UserRef user, String type) {
return myMEthod(clazz, user, type, clazz);
}
}
This allows you to implement the InterfaceB whereever you want to skip a parameter.
You could pass same parameter (of same type) twice, pass null, or some default value.
I hope this works for your case.
I'd say no. Java enjoys it when all of it's variables are set as a certain type and never change. If you want to find the most flexibility, try finding the biggest possible superclass, as in maybe T = Object and E = Object. Later when you need to use the object you can typecast it into what you want? Maybe?
I see two ways of doing it (or at least workaround the problem):
The first way is to implement a method with all your parameters and pass null instead of the parameter if you don't need it. Then handle it in your method's body. This should look like this:
public void myMethod(Sometype param1, Sometype param2, Sometype param3) {
//Test if your paramaters are null or not then do what you want
}
And you can call your method like this (if you don't need the second parameter for example):
myInstance.myMethod(param1, null, param2);
You could do it like this, but I DON'T recommand using this trick, because it's
counterintuitive for the user, and your method will be verbose, and "unclean"...
There's a second way to do it. even if it's way more verbose than TypeScript or Kotlin, you can simply define several methods with the required parameters. For example one method with only the second parameter, one with the first and the third parameter, etc... It's just basic method overloading, but it works perfectly! I think it's one of the most "java-friendly" way to do it.
I hope I helped you
Like many languages, there is no optional or gradual typing in Java. The typing rules are probably complicated enough as it is. Nor are there default type arguments, but that doesn't seem to be the major issue here.
In your case, it looks like making the typing more client friendly solves the problem without having to go further. I am assuming the E in AsyncCallback is for "exception" and T is, as in GWT's AsyncCallback, for a method parameter.
public static interface Mapper<V,T,E> {
public void map(KeyValue<V> v, AsyncCallback<? super T,? extends E> cb);
}
That allows any particular Mapper to take any applicable AsyncCallback.
We can be more explicit about the exception - useful if we need to define a throws anywhere.
public static interface Mapper<V,T,E extends Throwable> {
If a reference to a Mapper could take any AsyncCallback, declare it of type Mapper<V,Object,Throwable> for some V.
If you desperately wanted a short form of Mapper with a concise declaration for you could introduce an adapter.
public class MapperAny<V> implements Mapper<V,Object,Throwable> {
private final Mapper<V,Object,Throwable> target;
// A static creation method would be nicer, but ctor conventional.
public MapperAny(Mapper<V,Object,Throwable> target) {
this.target = target;
}
public void map(KeyValue<V> v, AsyncCallback<T,E> cb) {
target.map(v, cp);
}
// unwrap
public Mapper<V,Object,Throwable> mapper() {
return target;
}
}
If you wanted the same thing for AsyncCallback, it's a bit more difficult. There is no denotable opposite of Object (i.e. the type of null).
You can´t do it with one class, but you can partially solve it using inheritance. Say you have
interface Mapper<V,T,E> {
public void map(KeyValue<V> v, AsyncCallback<T,E> cb);
}
You can then have interfaces that specialize this, like so:
interface MapperWithObjectValue<T,E> extends Mapper<Object, T, E> {
}
interface MapperWithObjectResult<V,E> extends Mapper<V, Object, E> {
}
etc.
It´s not all that useful in this way, as the user could just as well pass Object as the type parameter, but it does have its uses for retroactively generifying an interface. Say you have
interface Foo {
Object getFoo();
}
You then realize that you´d like that return type be a generic type, but you´ve already committed this interface as part of your stable API. You can then use specialization via inheritance to solve it, like so:
interface GenericFoo<T> {
T getFoo();
}
interface Foo extends GenericFoo<Object> {
}
Existing code can keep using Foo just like before, and code that has a need for a different return type can use GenericFoo instead.
Problem:
I want to create a generic function which will return me strogly typed object.
Function :
public <T > T GetPet(AnimalKingdom allAnimals,int id) {
return (T) allAnimals.getAnimalsManager().findAnimalById(id);
}
The above function will return a strongly typed object or throw error.
Usage :
GetPet<Tiger>(thisZoo,tigersId).Roar();
Coming from C# background. Googled for the same but was not able to find a solution, it seems that I need to pass the generic type in function for it to work.
How can the above scenario implemented in java.
In Java, you explicitly specify the type arguments of the generic method before the method name. For example:
class Example {
public static <T> T getPet(AnimalKingdom allAnimals, int id) {
return (T)allAnimals.getAnimalsManager().findAnimalById(id);
}
}
Then to invoke:
Example.<Tiger>getPet(thisZoo, tigersId).roar();
Alternatively, you can use type inferencing:
Tiger tiger = Example.getPet(thisZoo, tigersId);
tiger.roar();
By the way, your getPet method is not very safe because there is no runtime check performed to ensure the object returned is actually an instance of Tiger. In fact, the Java compiler gives a warning on this line:
return (T)allAnimals.getAnimalsManager().findAnimalById(id);
The reason is because the cast to (T) is unchecked due to type erasure.
To strengthen your code, I suggest the following change:
class Example {
public static <T> T getPet(Class<T> clazz, AnimalKingdom allAnimals, int id) {
return clazz.cast(allAnimals.getAnimalsManager().findAnimalById(id));
}
}
Then to invoke:
Example.getPet(Tiger.class, thisZoo, tigersId).roar();
The benefit of passing in the class object (Tiger.class) is that:
It provides the compiler the type to use for <T> (again via type inferencing).
You can add your own explicit runtime type check by calling the Class.cast method. The Java compiler warning goes away, and type safety is restored. For example, if findAnimalById mistakenly returns an instance of Bear when you expected Tiger, you will get a ClassCastException.
please try something like
Tiger tiger = GetPet(thisZoo,tigersId);
tiger.Roar();
Using a generic is simply the wrong choice here. You should take a look at inheritance, virtual function, abtract classes and interface.
As SylvainL said, generics is not the right choice here. This looks like a simple inheritance / interface problem to me.
New getPet method:
public Animal getPet(AnimalKingdom allAnimals, int id)
{
return allAnimals.getAnimalsManager().findAnimalById(id);
}
Using inheritance:
class Animal { void Roar() { throw new Exception("This animal cannot roar!"); } };
class Tiger extends Animal { #Override void Roar() { ... }; ... };
Usage:
getPet(thisZoo, tigersId).Roar();
OR Using an interface: (a little more complicated but probably generally better)
Note: you don't really need Animal in this case, you can just use Object
class Animal { ... }; // no Roar method
interface Roarer { void Roar(); };
class Tiger extends Animal implements Roarer { #Override void Roar() { ... }; ... };
Note: You can stick either of the below usages into a method to just end up with something like:
roar(getPet(thisZoo, tigersId));
Usage: (you can remove the try {} catch, but this is generally not a good idea)
try
{
((Roarer)getPet(thisZoo, tigersId)).Roar();
}
catch (ClassCastException e) { /* handle error */ };
Usage alternative: (to safely avoid try {} catch, haven't tried this yet, but I think it might work)
Animal animal = getPet(thisZoo, tigersId);
if (Roarer.class.isAssignableFrom(animal.class))
((Roarer)animal).Roar();
else
// handle error
I want to use the class information that was captured by the setup of a generic method in Java to potentially create an instance. But I can't see how to reference the class without an actual instance. Is it possible?
public class Fancy {
static public <TypeToFind> TypeToFind createInSomeCase() {
// any type of logic with TypeToFind "class" generic will do, I just want to reference it.
// the below code is invalid, I could also declare a variable, but can't always create an instance to get the class
if (TypeToFind.getClass().equals(Something.class)) {
return TypeToFind.getInstance();
}
}
}
... so later on I could do:
TheResultIsTheParameter t = Fancy.createInSomeCase();
... instead of
TheResultIsAParameter t = Fancy.createInSomeCase(TheResultIsAParameter.class);
... or
TheResultIsAParameter t = Fancy.createInSomeCase(t);
Am I making this too complicated?
You can't do it, because generics are lost at runtime (due to type erasure). You have to pass a Class<?> parameter
Well, you require somethink that is logical, unfortunattelly generics in Java are only a syntactic sugar for reflection.
List<MyClass> list;
(...)
MyClass my = list.get(0);
will compile to
MyClass my = (MyClass) list.get(0);
and this is what will you see in bytecode.
What is more, using reflection or casting to untyped list you can put any object into list and in both codes you'll get ClassCastException.
So the generics exists only on compiler level. A big feature which adds nothing new, only shortens a code in most cases.
As long as you do not try and statically (at compile time) reference any particular class, nothing prevents you from doing something like this:
public class GenericsTest {
#Test
public void testMe() {
GenericsTest test = new GenericsTest();
System.out.println(test.get("Hello").getClass());
}
public GenericsTest() {
super();
}
public <T extends Object> T get(T entity) {
return newInstanceForClass((Class<T>)entity.getClass());
}
public <T extends Object> T newInstanceForClass(Class<T> clazz) {
try {
return clazz.newInstance();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
But as you can see, you need to pass in an object of the class you are trying to instantiate, which might not be want you are after. In which case the only other option is to pass in a Class parameterized with the generic type, for reasons that other posters have eloquently stated.
I've got the following method of an public abstract class Model { //impl } (declared exactly like this):
protected <T extends Model> HashMap<String, Model> resultsetMap(ResultSet res) {
HashMap<String, Model> data = new HashMap<String, Model>();
try {
while(res.next()) {
Model obj = T.getNew(res);
data.put(obj.toString(), obj);
}
} catch(SQLException e) {
return null;
}
return data;
}
T is supposed to tell the caller the concrete class it should use. Is this possible?
How would I call this method from another method of a subclass of Model? I've tried with resultsetMap<Course>(res); but it looks like a syntactic error
Since the method is inherited, you can call it either as super.<ConcModel>resultsetMap(/* arg */); or this.<ConcModel>resultsetMap(/* arg */);. Second or first respectively based on whether the subclass is overriding it or not.
Tutorial on how to call a generic method.
You can't call T.getNew() because the type of T is erased at runtime. You can pass in a Class object if you need to call Class methods.
In your code 'T' describes a type, it's not an instance of anything so you can't call methods on it. If it was an instance of an object you would need to pass it into the method anyway, if it's meant to be a static method it cant be overrided.
I would consider using the factory pattern, i.e. pass in a model factory to this method.
I have a method that looks like this
public static <T extends MyClass, X extends AnotherClass> List<T> (Class<T> aParameter, X anotherParameter)
Now if AnotherClass is an abstract class that does NOT Have getId defined, but every single class that extends this interface does. (Don't ask me why it is designed this why, I did not design the abstract class, and I am not allowed to change it).
How can I do something like this
anotherParameter.getId();
I know I have to cast it to the class, but then i have to do an instanceof check for every possible class and then cast it.
So right know i have something like:
if (anotherParameter instanceof SomeClass)
((SomeClass)anotherParameter).getId(); //This looks bad.
Is it possible to cast this dynamically?, to whatever anotherParameter is at runtime?.
Can you modify derived classes? If so, you could define an interface for this (syntax maybe wrong):
public interface WithId {
void getId();
}
...
public class MyDerivedClass1 extends AnotherClass implements WithId {
...
}
...
public class MyDerivedClass2 extends AnotherClass implements WithId {
...
}
and then, inside your method do:
...
if (anotherParameter instanceof WithId) {
WithId withId = (WithId) anotherParameter;
withId.getId();
}
...
If you can change your method's signature, maybe you can specify an intersection type:
public static <T extends MyClass, X extends AnotherClass & WithId> List<T> myMethod(Class<T> aParameter, X anotherParameter)
and then you would have getId() available directly inside your method.
I would say no, since due to type erasure, X is actually just Object at runtime. You could try doing something with reflection to test if anotherParameter has getId() and if so, call it.
You could use reflection to invoke the method at runtime if it exists.
try {
Method m = anotherParameter.getClass().getMethod("getId", null);
Object result = m.invoke(anotherParameter, null);
}
catch (NoSuchMethodException e) {
// ... and several other exceptions need to be caught
}
The concept of casting something at runtime doens't really make sense, as you have an instance, and it can tell you what class it is. You will need to use reflection, for example using the Introspector class.
private Integer getId(final X anotherParameter) {
final BeanInfo beanInfo = Introspector.getBeanInfo(anotherParameter.getClass());
for (MethodDescriptor methodDescriptor : beanInfo.getMethodDescriptors()) {
final Method method = methodDescriptor.getMethod();
if ("getId".equals(method.getName())
&& method.getParameterTypes().length == 0) {
return (Integer) method.invoke(anotherParameter);
}
}
return null;
}
As others here have said, reflection is the only practical solution to this, but I would enhance this a little bit by caching the reflection metadata (perhaps a map keyed by the class+methodName), as that part of reflection isn't completely cheap. You can't help the "invoke()" part.