org.mutabilitydetector.MutabilityReason Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of MutabilityDetector Show documentation
Show all versions of MutabilityDetector Show documentation
Lightweight analysis tool for detecting mutability in Java
classes.
package org.mutabilitydetector;
/*
* #%L
* MutabilityDetector
* %%
* Copyright (C) 2008 - 2014 Graham Allan
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import static java.util.Arrays.asList;
/**
* The various reasons that instances of a class can be considered mutable.
*
*
* @author Graham Allan / Grundlefleck at gmail dot com
*
*/
public enum MutabilityReason implements Reason {
/**
* Class could not be analysed. Possible reasons include not being able to
* load the class correctly.
*/
CANNOT_ANALYSE("Class could not be analysed. Possible reasons include not being able to load the class correctly.",
IsImmutable.COULD_NOT_ANALYSE),
/**
* For an object to be immutable, its fields must also be immutable. By
* assigning an abstract type to a field, it is not known if the concrete
* fields supplied will be immutable or not.
*/
ABSTRACT_TYPE_TO_FIELD("For an object to be immutable, its fields must also be immutable. "
+ "By assigning an abstract type to a field, "
+ "it is not known if the concrete fields supplied will be immutable or not.", IsImmutable.NOT_IMMUTABLE),
/**
*
*/
ABSTRACT_COLLECTION_TYPE_TO_FIELD(
"JDK collection types are defined to be mutable (their interfaces declare mutation methods). Assigning a collection type to "
+ "a field is similar to assigning abstract type, except that there is a common idiom which can be used to guarantee the collection is not mutated. "
+ "That is to copy the collection and wrap in an unmodifiable collection, using one of wrapping methods on java.util.Collections, e.g. unmodifiableList. Unless that idiom is "
+ "used, the field is considered mutable. ", IsImmutable.NOT_IMMUTABLE),
COLLECTION_FIELD_WITH_MUTABLE_ELEMENT_TYPE(
"JDK collection types are defined to be mutable. While there is a very common idiom which "
+ "makes these collections immutable, if the type of the collection elements is mutable, the collection itself also becomes mutable. "
+ "For example, List dates = Collections.unmodifiableList(new ArrayList(srcList)), is a mutable list, because its elements "
+ "can be mutated.", IsImmutable.NOT_IMMUTABLE),
/**
* The given class can be subclassed. While this specific class may still be
* immutable, subclasses may not. It is recommended that the class be
* declared final, or all of its constructors declared private. This will
* allow clients to be confident that parameters declared to be this type
* will indeed be of this type at runtime, not an instance of a mutable
* subclass. Note that applying the final keyword to a class does not have
* any effect on the Java Memory Model.
*/
CAN_BE_SUBCLASSED(
"Class can be subclassed. While this specific class may still be immutable, it is recommended that the class "
+ "be declared final, or all of its constructors declared private. This will allow clients to "
+ "be confident that parameters declared to be this type will indeed be of this type at runtime, "
+ "not an instance of a mutable subclass. Note that applying the final keyword to a class does not have any effect on the Java Memory Model.",
IsImmutable.NOT_IMMUTABLE),
/**
* Abstract types (interfaces or abstract classes) are considered to be
* \"Inherently Mutable\" in particular cases. Because the concrete
* implementation cannot be known until compile-time, run-time instances of
* abstract types could be either mutable or immutable.
*/
ABSTRACT_TYPE_INHERENTLY_MUTABLE("Abstract types (interfaces or abstract classes) are considered to be "
+ "\"Inherently Mutable\" in particular cases. Because the concrete implementation cannot be known"
+ "until compile-time, instances of abstract types could be either mutable or immutable.",
IsImmutable.NOT_IMMUTABLE),
/**
* Since an array can be mutated after construction (by modifying what it
* contains) they are inherently mutable. However, since it is possible that
* a field which is an array type is never mutated after construction, it is
* still possible for the containing type to be immutable
*/
ARRAY_TYPE_INHERENTLY_MUTABLE("Since an array can be mutated after construction "
+ "(by modifying what it contains) they are inherently mutable. However, since it is possible "
+ "that a field which is an array type is never mutated after construction, it is still possible "
+ "for the containing type to be immutable.", IsImmutable.NOT_IMMUTABLE),
/**
* A mutable type can be assigned to a field. Since references to the
* mutable field may be kept, the containing type can be mutated after
* construction.
*
* This reason can also indicate a circular reference in the fields of
* several types. E.g. type A has a field of type B, and type B has a field
* of type A. Therefore one of these types has to not be completely
* constructed when passed to the other type.
*/
MUTABLE_TYPE_TO_FIELD("A mutable type can be assigned to a field. Since references to the mutable field "
+ "may be kept, the containing type can be mutated after construction.", IsImmutable.NOT_IMMUTABLE),
/**
* [Experimental] The 'this' reference escaped during construction. Whoever
* receives the reference may observe values of the object mutating.
*/
ESCAPED_THIS_REFERENCE(
"[Experimental] The 'this' reference escaped during construction. Whoever receives the reference may observe values of the object mutating.",
IsImmutable.NOT_IMMUTABLE),
/**
* Field is not declared final. If the object is published across threads
* the Java Memory Model does not guarantee that it will be fully
* initialised before it is read. However, if the object is only used in a
* single thread, reads are guaranteed to see the fully initialised fields.
*/
NON_FINAL_FIELD(
"Field is not declared final. If the object is published across threads the Java Memory Model "
+ "does not guarantee that it will be fully initialised before it is read. "
+ "However, if the object is only used in a single thread, reads are guaranteed to see the fully initialised fields.",
IsImmutable.EFFECTIVELY_IMMUTABLE),
/**
* Class has a published, non-final field. Fields of an immutable class may
* not be reassigned after an instance is constructed. If an accessible
* field is not made final, it can be reassigned.
*/
PUBLISHED_NON_FINAL_FIELD("Class has a published, non-final field. Fields of an immutable class may not be "
+ "reassigned after an instance is constructed. "
+ "If an accessible field is not made final, it can be reassigned.", IsImmutable.NOT_IMMUTABLE),
/**
* For a class to be immutable, fields cannot be reassigned once an instance
* is constructed. The most common example of this is JavaBean convention
* "setter" methods.
*/
FIELD_CAN_BE_REASSIGNED(
"For a class to be immutable, fields cannot be reassigned once an instance is constructed.",
IsImmutable.NOT_IMMUTABLE),
/**
* This is a placeholder reason.
*/
NULL_REASON("Placeholder reason for a null checker.", IsImmutable.COULD_NOT_ANALYSE);
private final String description;
private final String code;
private final IsImmutable createsResult;
MutabilityReason(String description, IsImmutable createsResult) {
this.description = description;
this.code = this.name();
this.createsResult = createsResult;
}
@Override
public String description() {
return description;
}
@Override
public String code() {
return code;
}
@Override
public IsImmutable createsResult() {
return createsResult;
}
@Override
public boolean isOneOf(Reason... reasons) {
return asList(reasons).contains(this);
}
}