arashja / hamcrest

Automatically exported from code.google.com/p/hamcrest
0 stars 0 forks source link

hasProperty produces IllegalAccessException for anonymous classes #26

Closed GoogleCodeExporter closed 8 years ago

GoogleCodeExporter commented 8 years ago
If you try to use the hasPropery(String,Matcher) matcher for an anonymous 
or inner class implementing a property of its interface, the matcher gets 
an IllegalAccessException and then reports a spurious failure.

For example:

interface IX {
    int getTest();
}

package com.mypackage;
public void TextX
{
    @Test
    public void test() {
        class X implements IX {
            public int getTest() {
                return 1;
            }
        }

        X x = new X();
        assertThat(x, hasProperty("test", equalTo(1)));
     }
}

This reports:

  java.lang.AssertionError: 
  Expected: hasProperty("test", <1>)
       got: <com.mypackage.TestX$1X@fd68b1>

The actual cause was an exception at:

     return readMethod != null
            && value.matches(readMethod.invoke(argument, NO_ARGUMENTS));

with Description:

    Class org.hamcrest.beans.HasPropertyWithValue can not access a member 
of class com.mypackage.TestX$1X with modifiers "public"

Original issue reported on code.google.com by neil.gg%...@gtempaccount.com on 5 Dec 2007 at 12:46

GoogleCodeExporter commented 8 years ago
I've added a test for this, but it works in my environment. Can you tell us 
more about your platform/runtime?

I'll close it for now until we can reproduce the failure.

Original comment by smgfree...@gmail.com on 18 Oct 2008 at 8:06

GoogleCodeExporter commented 8 years ago
The test might well work if it's in the same package as the getter, as the test 
then
has permissions that a test in another package does not.  Is your test in the 
same
package?

I've certainly had this problem in our environment (plain old JRE v5) and in 
fact
have had to write our own alternative Matcher to get round the problem.  The 
fix is
basically to put in a setAccessible(true) call on the getter method, and to 
ensure
that the test class is not in the same package.

Original comment by Royst...@gmail.com on 18 Oct 2008 at 2:55

GoogleCodeExporter commented 8 years ago
If the getter is not accessible, then it's not a Bean property accessor, as 
defined
by Java Beans.

The matcher should not throw IllegalAccessException.  It should return false in 
this
situation.

Original comment by nat.pr...@gmail.com on 18 Oct 2008 at 3:43

GoogleCodeExporter commented 8 years ago
I hope it's not really about JavaBeans, and it still can fail even if the 
getter is
public.

The standard situation is that you have an interface (as in the original 
example)
exposing a getter, or maybe a getter and a setter.  Then you have a class which
implements that interface via a public getter and public setter method. But you 
make
that class package protected because you're exposing it through a factory method
which has a return type of the interface.

All completely standard stuff. Now you want to test it.  hasProperty is the 
obvious
candidate, but because the implementation class is not public, hasProperty 
doesn't work.

A public getter method exposed via a public interface really ought to be 
directly
testable via hasProperty: I've had several people come to me at work and 
complain
that they "don't like Hamcrest because hasProperty doesn't work properly". 
(That is,
it doesn't work as they expect.)

If you want to make this return false instead of throwing an exception on a 
getter
that isn't publicly visible on a public class, insisting on sticking with the
JavaBeans line, fair enough.  But it does surprise people.  And so then an
alternative matcher that does provide access in this very standard case (public
interface, either public or non-public implementation) is very definitely 
needed.  As
I said, we had to write one as people are always wanting to make assertions 
about
things accessed via interfaces, and it's basically exactly hasProperty but with 
a
setAccessible(true) in the middle. :-(

Why use hasProperty or a matcher at all?

Well, the error messages coming out of
assertThat(foo, hasProperty("bar", equalTo(5)));

are much clearer than:

assertThat(foo.getBar(), equalTo(5));

even though it's more typing and you don't get refactoring or compiler support.

Original comment by Royst...@gmail.com on 18 Oct 2008 at 4:13

GoogleCodeExporter commented 8 years ago
[deleted comment]
GoogleCodeExporter commented 8 years ago
If you write a method called "getXXX" that doesn't automatically make it a 
getter for
a property called "xxx".  You happen to have a name that follows a convention 
defined
by part of the Java Beans spec.  Unless you follow the rest of the spec, it's
not a property.  It's just a method with a name that starts with "get".

Original comment by nat.pr...@gmail.com on 19 Oct 2008 at 1:16