|
||||||||||
PREV CLASS NEXT CLASS | FRAMES NO FRAMES | |||||||||
SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |
java.lang.Object org.mutabilitydetector.unittesting.matchers.reasons.ProvidedOtherClass
public final class ProvidedOtherClass
Method Summary | |
---|---|
org.hamcrest.Matcher<MutableReasonDetail> |
areAlsoImmutable()
Assumes that the selected type is immutable, preventing warnings related to transitive mutability. |
org.hamcrest.Matcher<MutableReasonDetail> |
isAlsoImmutable()
Assumes that the selected type is immutable, preventing warnings related to transitive mutability. |
static ProvidedOtherClass |
provided(Dotted... classNames)
|
static ProvidedOtherClass |
provided(Dotted className)
|
static ProvidedOtherClass |
provided(Iterable<Dotted> classNames)
|
Methods inherited from class java.lang.Object |
---|
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait |
Method Detail |
---|
public static ProvidedOtherClass provided(Dotted className)
public static ProvidedOtherClass provided(Dotted... classNames)
public static ProvidedOtherClass provided(Iterable<Dotted> classNames)
public org.hamcrest.Matcher<MutableReasonDetail> isAlsoImmutable()
One common way for classes to be rendered mutable is to contain a mutable field. Another way is that the class is extensible (non-final). The interaction of these rules can occasionally conflict with the notion of abstraction. For example, consider the following classes:
// implementations MUST be immutable public interface Named { String getName(); } public final class HasSomethingNamed { private final Named named; public HasSomethingNamed(Named named) { this.named = named; } public String getNameOfYourThing() { return this.named.getName(); } }In this contrived example, the interface Named is abstracting something. It would be preferable to be able to depend on that abstraction, rather than a concrete implementation. Unfortunately, any implementation of Named could violate the condition that it must be immutable. If the Named implementation given to the constructor of HasSomethingNamed is actually mutable, it causes HasSomething named to be mutable as well. Consider this code:
SneakyMutableNamed n = new SneakyMutableNamed("Jimmy"); HasSomethingNamed h = new HasSomethingNamed(n); String nameOnFirstCall = h.getNameOfYourThing(); n.myReassignableName = "Bobby"; String nameOnSecondCall = h.getNameOfYourThing();Here, because a sneaky subclass of Named is mutated, the instance of HasSomethingNamed has been observed to change (getNameOfYourThing() first returns "Jimmy" then "Bobby").
Despite this limitation, it can still be preferable that the abstract class is given as a parameter. Perhaps you are able to trust that all implementations are immutable. In that case, Mutability Detector raising a warning on HasSomethingNamed would be considered a false positive. This reason allows the test to pass.
Example usage:
assertInstancesOf(HasSomethingNamed.class,
areImmutable(),
AllowedReason.provided(Named.class).isAlsoImmutable());
Not that this also allows a field which is a collection type, with Named as a generic element type.
public org.hamcrest.Matcher<MutableReasonDetail> areAlsoImmutable()
One common way for classes to be rendered mutable is to contain a mutable field. Another way is that the class is extensible (non-final). The interaction of these rules can occasionally conflict with the notion of abstraction. For example, consider the following classes:
// implementations MUST be immutable public interface Named { String getName(); } public final class HasSomethingNamed { private final Named named; public HasSomethingNamed(Named named) { this.named = named; } public String getNameOfYourThing() { return this.named.getName(); } }In this contrived example, the interface Named is abstracting something. It would be preferable to be able to depend on that abstraction, rather than a concrete implementation. Unfortunately, any implementation of Named could violate the condition that it must be immutable. If the Named implementation given to the constructor of HasSomethingNamed is actually mutable, it causes HasSomething named to be mutable as well. Consider this code:
SneakyMutableNamed n = new SneakyMutableNamed("Jimmy"); HasSomethingNamed h = new HasSomethingNamed(n); String nameOnFirstCall = h.getNameOfYourThing(); n.myReassignableName = "Bobby"; String nameOnSecondCall = h.getNameOfYourThing();Here, because a sneaky subclass of Named is mutated, the instance of HasSomethingNamed has been observed to change (getNameOfYourThing() first returns "Jimmy" then "Bobby)".
Despite this limitation, it can still be preferable that the abstract class is given as a parameter. Perhaps you are able to trust that all implementations are immutable. In that case, Mutability Detector raising a warning on HasSomethingNamed would be considered a false positive. This reason allows the test to pass.
Example usage:
assertInstancesOf(HasSomethingNamed.class,
areImmutable(),
AllowedReason.provided(Named.class).areAlsoImmutable());
Not that this also allows a field which is a collection type, with Named as a generic element type.
|
||||||||||
PREV CLASS NEXT CLASS | FRAMES NO FRAMES | |||||||||
SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |