All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.mutabilitydetector.MutabilityReason Maven / Gradle / Ivy

There is a newer version: 0.10.6
Show newest version
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);
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy