Use instanceof in a generic way - java

Is there a way to use instanceof based on the passed argument of a method? Example
doSomething(myClass.class); /* I would like to call this also with other classes */
public void doSomething(/*generic parameter that accepts all classes, not just myClass */) {
if (myObject instanceOf /* the generic parameter */ == true) {...}
}
sometimes I'll call the method using myClass.class but other times I would like to call it using someOtherClass.class - I don't want to change the if condition though. Is that possible? If so, how? :)
Thanks

You're looking for the Class.isInstance() method.
public void doSomething(Class<?> c, Object myObject) {
if (c.isInstance(myObject)) {...}
}

This is the way to do it, as far as I know:
public static <T> boolean doInstanceOf(Object object,Class<T> clz) {
return clz.isInstance(object);
}
Usage:
System.out.println(doInstanceOf(myObject,MyClass.class));

Related

How to design a method that can deal with two different object types

I have two collections, that have almost similar attributes:
HashSet<BuyerUser>
HashSet<SellerUser>
I want to write a method that serializes the objects as JSON and sends it to a web API. My problem is, however, that i'm not able to write a method that is generic enough so that I don't have to repeat the code twice.
public void addToMetadata (Object users) {
if (users instanceof BuyerUser) {
// Do this
}
if (users instanceof SellerUser) {
// Do that
}
}
My problem is the instanceOf check that doesn't work the way I outlined it. I would have to do something like
if (users instanceof HashSet<BuyerUser>)
but that gives me an error:
llegal generic type for instanceof
Can that be solved in any way?
if (users instanceof HashSet<BuyerUser>)
You cannot do this, as generics are erased at runtime when the instanceof call is run
Instead, the better way to go would get to create either a parent class of BuyerUser and SellerUser or an interface that both BuyUser and SellerUser have that has a function like
public String toJSON ()
Since the parameterized type is lost on runtime, you cannot do it.
You can either create a wrapper for each HashSet and add a method to it which returns the type:
public class MySet<T> extends HashSet<T> {
private Class<T> type;
public MySet(Class<T> c) {
this.type = c;
}
public Class<T> getType() {
return type;
}
}
Or you can get the first element of the set and check the type of that:
if(set instanceof HashSet && !set.isEmpty() && set.iterator().next() instanceof BuyerUser) {
// BuyerUser set
}
Be aware the set may contain different types of objects like if it was defined as HashSet<Object>.

Passing Class object to the method

I have a library method, which returns a collection of Objects by class name.
For example
Iterable x = RunState.getInstance().getMasterContext().getObjects(XAgent.class);
would return a list of all Objects in Context which are InstanceOf XAgent.class
If use it in that way, it work very well. How ever I need a method to pass the class-name to.
public Iterable getObjectsFromContext(Class clazz) {
return RunState.getInstance().getMasterContext().getObjects(clazz);
}
getObjectsFromContext(XAgent.class);
And then it does not work any more, it returns All objects of context... so why it does not pass my "clazz" variable into getObjects() ?
here is the linkt ot javadoc of getObjects();
http://repast.sourceforge.net/docs/api/repast_simphony/repast/simphony/context/Context.html#getObjects-java.lang.Class-
IndexedIterable<T> getObjects(java.lang.Class<?> clazz)
update: this works:
public Iterable getObjectsFromContext(Class<?> clazz) {
return RunState.getInstance().getMasterContext().getObjects(clazz);
}
getObjectsFromContext(XAgent.class)
this worked for me:
public Iterable getObjectsFromContext(Class<?> clazz) {
return RunState.getInstance().getMasterContext().getObjects(clazz);
}
getObjectsFromContext(XAgent.class)
There was a right answer suggested, but I do not see it anymore to accept, that's why I post it on my own.
This won't work because your wrapper function, getObjectsFromContext, explicitly takes in a type of "Class".
Whatever you pass in, it will be interpreted as type "Class" and thus get passed into the getObjects() function as "Class". That will explain why the function returns all objects.
You'll need make your wrapper function generic.
public Iterable<T> getObjectsFromContext(T clazz) {
return RunState.getInstance().getMasterContext().getObjects(clazz);
}

Returning an object of any type

In my cache class, I'm going to have a function which writes the serialized version of an object (undecided type) to a file, something like this (generic function):
public <O> void write(O object) {
// ...
serialize(file, object);
// ...
}
Which works great, however, I'm unable to find a way to create a method which can return any object, like the write() method can take any object. Looking for something like this:
public <O> read() {
// ...
O object = unserialize(file);
// ...
return object;
}
Any suggestions on how to accomplish this is highly appreciated!
You specify the return type of type Object:
public Object function(...)
That way the return type will always be of type Object (since all objects are descendants of Object), so they will be accepted.
If you mean
public <O> O read() {
this is almost useless because it is much the same as
public Object read() {
Not sure if I understood the question correctly... You could wrap both methods inside a class and parametrize the class with the object's type, like this:
public class ReaderWriter <T> {
public ReaderWriter(File file) {...}
public void write(T object) {...}
public T read() {...}
}
I would do that by making the whole class generic
class Cache <O extends Serializable> {
public void write(O object) {
serialize(file, object);
}
public O read() {
O object = (O)unserialize(file);
return object;
}
}
Note the cast of the returned object.
Besides that you should use <O extends Serializable> instead of just <O>. This assures that your type parameter id a type that is serializable. This is needed if you want to save (serialize) objects and prevents later errors.
I'm assuming the caller to read() knows which type it expects to get. This is a reasonable assumption because he is going to assign the return value to some variable:
MyType o = read(...); // Caller knows he's going to get a MyType object
If this assumption is true, then you should change the read() method such that it takes a class object:
public<T> T read(Class<T> t) {
...
}
Then the call site will look as follows:
MyType o = read(MyType.class);
Yes,
public <O> O read()
is valid and will do what you want (return any type the caller wants). Whether this is a good idea is another matter

How to use Guava's ClassToInstanceMap<B>?

I try to work with Guava's ClassToInstanceMap<MyObject>.
I want to have my clients to use a method addMyObject(MyObject), so I tried to write these methods:
private final ClassToInstanceMap<MyObject> instances = MutableClassToInstanceMap.create();
public void addMyObject1(MyObject o) {
instances.putInstance(o.getClass(), o);
}
public <O extends MyObject> void addMyObject2(O o) {
instances.putInstance(o.getClass(), o);
}
But naturally, none of these two methods compile.
So, how to use this properly?
Since you know for sure that o is an instance of MyObject, you don't really need to use the type-safe putInstance method. You could just use the standard put():
private final ClassToInstanceMap<MyObject> instances = MutableClassToInstanceMap.create();
public void addMyObject(MyObject o) {
instances.put(o.getClass(), o);
}
The ClassToInstanceMap will do a runtime check on the instance's type anyway.
That said, I'm interested in a way to do this using the type-safe method. Maybe some Java generics magic :)
Just for the record, you can narrow the Class type using
o.getClass().asSubclass(MyObject.class)

Simple/elegant way to do object to object transformation in Java?

I have to take over and improve/finish some code that transforms Java objects from a third party library into internal objects. Currently this is done through a big if-else statement along the lines of:
if (obj instanceOf X)
{
//code to initialize internal object
}
else if (obj instanceOf Y)
{
//code to initialize different object
}
else if (obj instanceOf Z)
{
//more init code
}
...
Personally I don't find this solution satisfactory; it's long and messy and to make matters worse many of the if-else blocks contain more if-else blocks dealing with subclasses and edge cases. Is there a better solution to this problem?
Create an interface like this
public interface Converter<S,T> {
public T convert(S source);
}
and implement it for each object of X,Y,Z. Then put all known converters into a Map and get happy!
While it doesn't work for edge cases, building a Map between Classes and Converters
X.getClass() -> X Converter
Y.getClass() -> Y Converter
would get you a lot closer. You'd want to also check superclasses if the leaf class is not found.
Code like this, with all of its instanceof conditions, screams for an interface!
You may want to create a public interface Initializable, with a method public void initialize().
Then all if your if-else's simply resolve into a single obj.initialize() call.
If these internal objects present an interface to the application, rather than being used directly, adapt them rather than converting them.
That is, if you have something like this:
public class ThirdPartyClass { ... }
public interface InternalInterface { ... }
public class InternalClass { ... }
Internal foo(ThirdPartyClass thirdParty) {
InternalClass internal = new InternalClass();
// convert thirdPaty -> internal
return internal;
}
Then instead do something like this:
public class ThirdPartyClass { ... }
public interface InternalInterface { ... }
public class InternalClass { ... }
public class ThirdPartyInternalAdapter implements InternalInterface {
private final ThirdPartyClass thirdParty;
public ThirdPartyInternalAdapter(ThirdPartyClass thirdParty) {
this.thirdParty = thirdParty;
}
// implement interface in terms of thirdParty
}
It's not clear from your question if this applies, but if it does this may be easier and more efficient than direct object-to-object conversion.

Categories