Eliyahu Machluf
Eliyahu Machluf

Reputation: 1401

Why Hamcrest `matches` method uses Object as input type and does not use generic type as input

I'm new to Java, learning Hamcrest framework.

I've read the code of the Matcher interface, and I don't understand the comment and the method signature of matches(Object actual). I expected it to be matches(T actual), and use the generic type T instead of Object which accept everything.

This is the source code: https://github.com/hamcrest/JavaHamcrest/blob/master/hamcrest/src/main/java/org/hamcrest/Matcher.java

for the matches method:

public interface Matcher<T> extends SelfDescribing {

/**
     * Evaluates the matcher for argument <var>item</var>.
     *
     * This method matches against Object, instead of the generic type T. This is
     * because the caller of the Matcher does not know at runtime what the type is
     * (because of type erasure with Java generics). It is down to the implementations
     * to check the correct type.
     *
     * @param actual the object against which the matcher is evaluated.
     * @return <code>true</code> if <var>item</var> matches, otherwise <code>false</code>.
     *
     * @see BaseMatcher
     */
    boolean matches(Object actual);

Reading the comment above the method, shows this is by intention, and I don't understand why. I know what is type erasure in java. But still I don't understand why the designer of Hamcrest thought it is better to have Object as input rather than generic type for interface which is declared to be generic public interface Matcher<T> extends SelfDescribing

Upvotes: 1

Views: 275

Answers (2)

Ben
Ben

Reputation: 3518

Q:

I don't understand why.

A: (from JavaDocs)

This is because the caller of the Matcher does not know at runtime what the type is (because of type erasure with Java generics). It is down to the implementations to check the correct type.

also from JavaDocs:

When using Hamcrest, there is no guarantee as to how often matches() or describeMismatch() will be called

You have to take a look at the Hamcrest-Libs implementation.
So, your matches() implementation is called internally by Hamcrest (with any Object). At runtime, Hamcrest has no chance to know (and find!) the correct matches(...) method, because the generics were cleared. You need to check yourself, if the object passed (by Hamcrest), really matches. This does not have much to do with Hamcrest.

Cheers!

Upvotes: 1

Nicktar
Nicktar

Reputation: 5575

You're right, you'd expect T at first instead of Object, but knowing that Generics are a compile time feature and not available during runtime (when the tests runs and needs the matcher) (see Type Erasure) it makes sense to highlight the fact that technically it could be something that's not T thus forcing you to check to create clearer error messages in that case.

Type Erasure (paraphrased from Oracle):

Type erasure makes sure that there are no additional classes generated for different generics. It

  • replaces all generic types by their boundary or Object.
  • introduces automatic casts
  • creates adapter methods to preserve polymorphism.

So that ther will be no runtime overhead.

Upvotes: 1

Related Questions