org.mutabilitydetector.unittesting.matchers.reasons
Class ProvidedOtherClass

java.lang.Object
  extended by org.mutabilitydetector.unittesting.matchers.reasons.ProvidedOtherClass

public final class ProvidedOtherClass
extends Object


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

provided

public static ProvidedOtherClass provided(Dotted className)

provided

public static ProvidedOtherClass provided(Dotted... classNames)

provided

public static ProvidedOtherClass provided(Iterable<Dotted> classNames)

isAlsoImmutable

public org.hamcrest.Matcher<MutableReasonDetail> isAlsoImmutable()
Assumes that the selected type is immutable, preventing warnings related to transitive mutability.

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.


areAlsoImmutable

public org.hamcrest.Matcher<MutableReasonDetail> areAlsoImmutable()
Assumes that the selected type is immutable, preventing warnings related to transitive mutability.

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.



Copyright © 2013. All Rights Reserved.