Class.isInstance does what you want.
if (Point.class.isInstance(someObj)){
...
}
Of course, you shouldn't use it if you could use instanceof instead, but for reflection scenarios it often comes in handy.
Class.isInstance does what you want.
if (Point.class.isInstance(someObj)){
...
}
Of course, you shouldn't use it if you could use instanceof instead, but for reflection scenarios it often comes in handy.
I want to check if an object o is an instance of the class c or of a subclass of c. For instance, if p is of class Point I want x.instanceOf(Point.class)
Um... What? What are o, p and x?
I want it to work also for primitive types. For instance, if x is an integer then x.instanceOf(Integer.class) and also x.instanceOf(Object.class) should be true.
No. It shouldn't even compile. Primitives are not objects, and you cannot call methods on them.
Anyway, there are three things, one of which can definitely achieve what you want (they differ somewhat in where exactly the apply:
- The
instanceofoperator if you know the class at compile time. - Class.isInstance() if you want to check an object's class against a class not known at compile time.
- Class.isAssignableFrom() if you want to check the assignability given two class objects.
Videos
If you want to add a method to a class hierarchy without actually adding the method, consider the Visitor Pattern. You could create a validation visitor, and let each entity select the appropriate method of the visitor.
First, your ParentEntity class hierarchy would need a bit of boilerplate to support visitors:
interface EntityVisitor<T> {
T visitA(AEntity a);
T visitB(BEntity b);
}
class ParentEntity {
<T> T accept(EntityVisitor<T> v);
}
class EntityA extends ParenEntity {
...
@Override <T> T accept(EntityVisitor<T> v) {
return v.visitA(this);
}
}
Next, we can implement and use a visitor that performs validation.
class Validation implements EntityVisitor<Void> {
EntityRepository repository;
...
@Override Void visitA(AEntity a) { ... }
@Override Void visitB(BEntity b) { ... }
}
class EntityRepository ... {
void save(List<ParentEntity> list) {
list.ForEach(e -> {
e.accept(new Validation(this));
...
});
}
}
The validation visitor can have access to both the entity and the repository (in order to make further queries), and will therefore be able to perform the full validation.
Using such a pattern has advantages and disadvantages compared to an instanceof check and compared to moving the validation logic into the entities.
An instanceof is a much simpler solution, especially if you only have very few entity types. However, this could silently fail if you add a new entity type. In contrast, the visitor pattern will fail to compile until the accept() method is implemented in the new entity. This safety can be valuable.
While this pattern ends up having the same behaviour as adding a validate() method to the entities, an important difference is where that behaviour is located and how our dependency graph looks. With a validate() method, we would have a dependency from the entities to the repository, and would have referential integrity checks intermixed with actual business logic. This defeats the point of an Onion Architecture. The visitor pattern lets us break this dependency and lets us keep the validation logic separate from other business logic. The cost of this clearer design structure is extra boilerplate in the form of the EntityVisitor interface and the accept() method that must be added to all entities in the relevant class hierarchy.
Whether these trade-offs are worth it is your call. You know your codebase best, and you have the best idea how it might evolve.
However, performing validation based on the result of multiple queries can lead to data integrity problems. The repository should either make sure to use database transactions (and offer an API that clearly communicates when modifications have been committed), or the relevant integrity checks should be done within the database, e.g. using constraints in an SQL database. In some cases, the validation checks can also be expressed as part of an insert or update query.
I know what I am about to answer is not exactly good practice but if you want to avoid instanceof's and have a generic way to call the respective method for that subclass you could use reflection:
Method m = EntityRepository.class.getMethod("validate", e.getClass());
m.invoke(this, e);
Of course, this will have a negative effect on performance and in some ways maintainability (with the only upside being less code).
Regarding the performance overhead, you can somewhat mitigate it by loading all the methods at startup:
Map<Class<?>, Method> methods = new HashMap<>();
Reflections reflections = new Reflections(ParentEntity.class, new SubTypesScanner());
Set<Class<? extends Animal>> subclasses = reflections.getSubTypesOf(ParentEntity .class);
for (Class<?> c : subclasses) {
methods.put(c, Solution.class.getMethod("makeTalk",c));
}
Where Reflections comes from the Reflections library
And then just call the method using:
methods.get(e.getClass()).invoke(this, e)
What is the difference between "Parent" and "Parent.class"?
The latter is a class literal - a way of accessing an object of type Class<Parent>.
The former is just the name of a class, which is used in various situations - when calling static methods, constructors, casting etc.
Does the second 'instanceof' make more sense from the view of strict programming?
Well not as the language is defined - instanceof only works with the name of a type, never an expression. If you could write
if (a instanceof Parent.class)
then I'd expect you do be able to write:
Class<?> clazz = Parent.class;
if (a instanceof clazz)
... and that's just not the way it works. On the other hand, there is the Class.isInstance method which you can call if you want.
What do you mean by "the view of strict programming" in the first place?
Parent is a class, so the second example doesn't make more sense that the first. You're asking if the instance is an instance of the class, a instanceof Parent is a pretty direct expression of that.
Parent.class is an instance of Class, so even if the second example compiled (it doesn't, the right-hand of instanceof can't itself be an instance), it wouldn't check what you want it to check. :-)