Sunday, 27 January 2013

In the past hour I just released a new version of Mutability Detector, v0.9. This release is quite significant. If you currently use Mutability Detector, I'd highly recommend upgrading. If you've never used it before, there's never been a better time to try*.

* I reserve the right to make this statement on all future releases ;-)

The String Problem

Finding java.lang.String to be mutable has long been a problem for Mutability Detector, recently rearing it's ugly head during a case study of ThreeTen, the new Date&Time API for Java 8. Although the general case of benign data races has still not been solved, I have taken the pragmatic choice to hard code it as immutable. Similarly for other JDK types, such as the primitive wrappers (Integer, Double, Character, etc), BigDecimal, BigInteger, and Class.

The way String et al have been hardcoded has been exposed to users, so that if you have false positives "tainting" your codebase, you too can tell Mutability Detector to regard certain types as immutable. For further information on this configuration, refer to the JavaDoc.

... are now considered immutable. Provided you use the methods from the standard JDK to copy (the new ArrayList call) and wrap in an unmodifiable collection (the unmodifiableList call) an error won't be raised. That condition is rather strict, for example, I personally use Guava's Lists.newArrayList method to copy, and that is still flagged as an issue. Let me know how useful it is for you.

Those two additions should hopefully make a major difference in the usability of Mutability Detector. Feedback, as always, is welcome.

What's Next?

That kinda depends on the feedback I get, bug fixes that are getting in your way will likely be top priority. More ambitious plans include: allowing mutable fields, provided they are not mutated and don't escape; studying popular projects like Guava to do more case studies, and/or bundle more useful configuration.

Once the release hits Maven Central, I'll also push out a new version of the FindBugs plugin.

I've added a wiki page with download links, since GitHub has deprecated the downloads page. The links are to the artifacts hosted on Maven Central, which you can just download from your browser. Hopefully that's not too close to Maven to put you off :)

thank you very much for your amazing tool. But my first tests failed because I still get the message "Expected: java.lang.String to be IMMUTABLE, but: java.lang.String is actually NOT_IMMUTABLE". Well I added a maven dependency to "org.mutabilitydetector / MutabilityDetector / 0.9.5" and run "MutabilityAssert.assertImmutable(myClass)".

With java.lang.String, you're not doing it wrong. The behaviour you see is by design. String is hardcoded to be immutable because the analysis is not powerful enough to detect its internal mutation is safe. This lead to lots of false positives of other classes, because the mutability is transitive, and kind of "infects" other classes. Hardcoding it allows classes that have String fields to still be considered immutable, but if you test the class directly, it gives the "real" result. I expected this behaviour would suit most users, as they don't make changes directly to String, instead, they use String in their own classes.

thanks for you reply! Now I understand the behaviour, though I think it's more desirable to make it consistent by design. I find it a bit confusing that String members are considered immutable, but the String class itself not. *At least* you should point that out in the documentation.

Here's the background; I'm sure you'll find this is a perfect valid use case: I have an Event class that contains a couple of members which must be immutable and members that are not immutable. The must-be-immutable members have an annotation @EventVariable. So I wrote a Unit-Test that determines all @EventVariable members and requires these to be immutable. That works fine, until I saw that String members are not immutable. Then my research brought me to this page where I read String is considered immutable being a contradition to my unit tests.

same with "assertInstancesOf(myClass, Matchers.anyOf(MutabilityMatchers.areImmutable(), MutabilityMatchers.areEffectivelyImmutable()));". And I get messages like "Expected: java.time.Instant to be EFFECTIVELY_IMMUTABLE, but: java.time.Instant is actually IMMUTABLE". Doesn't being immutable imply being effectively immutable?

I certainly could let the areEffectivelyImmutable() matcher accept classes that are immutable, but I'm not sure what the use case would be. Is this behaviour, albeit slightly confusing, preventing you from doing something?