Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Runtime error wen using Hamcrest Matchers in Android production code with proguard

I am writing an app that has a form with text fields that take numbers. To check whether the input is valid I decided to use Hamcrest Matchers. I defined:

public static <T> boolean checkThat(T actual, Matcher<? super T> matcher) {
    return matcher.matches(actual);
}

such that I can use stuff like:

if(checkThat(doubleFromText,greaterThan(0.0)) doSomething();

Now this works perfectly fine in debug mode, but when I enable proguard for production release the application crashes immediately with the following message (obtained with retrace):

java.lang.Error: Cannot determine correct type for matchesSafely() method.
        at org.hamcrest.internal.ReflectiveTypeFinder.findExpectedType(Unknown Source)
                                                      canObtainExpectedTypeFrom
        at org.hamcrest.TypeSafeMatcher.<init>(Unknown Source)
        at org.hamcrest.TypeSafeMatcher.<init>(Unknown Source)
        at org.hamcrest.number.OrderingComparison.<init>(Unknown Source)
        at org.hamcrest.number.OrderingComparison.greaterThan(Unknown Source)
                                                  matchesSafely
        at org.hamcrest.Matchers.greaterThan(Unknown Source)

How can I fix this?

I made a minimal example demonstrating the problem: https://github.com/burgerga/HamcrestMatchersWithProguard


Notes:

  • I added -dontwarn java.beans.** to my proguard rules to get it to compile.
  • Before you start telling me I should just use if(doubleFromText > 0), the example I gave was simplified. In my code I use something like

    checkThat(textIn(myEditText),parsesToDouble(greaterThan(0.0)));
    

    where parsesToDouble is a simple matcher I wrote. I think this is a very flexible and clear way to state my intent, and I'm simply interested in how to get it working with proguard.

like image 747
Gerhard Burger Avatar asked Jan 16 '15 10:01

Gerhard Burger


People also ask

What is a Hamcrest matcher?

Hamcrest is a framework that assists writing software tests in the Java programming language. It supports creating customized assertion matchers ('Hamcrest' is an anagram of 'matchers'), allowing match rules to be defined declaratively. These matchers have uses in unit testing frameworks such as JUnit and jMock.

What is matchers in JUnit?

Matchers is an external addition to the JUnit framework. Matchers were added by the framework called Hamcrest. JUnit 4.8. 2 ships with Hamcrest internally, so you don't have to download it, and add it yourself. Matchers are used with the org.

What is Hamcrest API?

Hamcrest is a framework for writing matcher objects allowing 'match' rules to be defined declaratively. There are a number of situations where matchers are invaluable, such as UI validation or data filtering, but it is in the area of writing flexible tests that matchers are most commonly used.


1 Answers

Because Hamcrest uses reflection, some methods get deleted in the shrinking phase that shouldn't be deleted. I was able to get it working again by adding

-keepclasseswithmembers class org.hamcrest.number.** { *** matchesSafely(...); }

to the proguard rules. If you don't care about a slightly larger apk you can add

-keep class org.hamcrest.** { *; }

to make sure nothing from hamcrest gets deleted.

like image 64
Gerhard Burger Avatar answered Sep 19 '22 21:09

Gerhard Burger