package java.lang.annotation;

import ej.annotation.Nullable;

/**
 * The common interface extended by all annotation types. Note that an interface that manually
 * extends this one does <i>not</i> define an annotation type. Also note that this interface does
 * not itself define an annotation type.
 *
 * More information about annotation types can be found in section 9.6 of <cite>The Java&trade;
 * Language Specification</cite>.
 */
public interface Annotation {

    /**
     * Returns the annotation type of this annotation.
     * @return the annotation type of this annotation.
     */
    Class<? extends Annotation> annotationType();

    /**
     * Returns true if the specified object represents an annotation that is logically equivalent to
     * this one. In other words, returns true if the specified object is an instance of the same
     * annotation type as this instance, all of whose members are equal to the corresponding member of
     * this annotation, as defined below:
     * <ul>
     * <li>Two corresponding primitive typed members whose values are <code>x</code> and <code>y</code> are
     * considered equal if <code>x == y</code>, unless their type is <code>float</code> or <code>double</code>.
     *
     * <li>Two corresponding <code>float</code> members whose values are <code>x</code> and <code>y</code> are
     * considered equal if <code>Float.valueOf(x).equals(Float.valueOf(y))</code>. (Unlike the <code>==</code>
     * operator, NaN is considered equal to itself, and <code>0.0f</code> unequal to <code>-0.0f</code>.)
     *
     * <li>Two corresponding <code>double</code> members whose values are <code>x</code> and <code>y</code> are
     * considered equal if <code>Double.valueOf(x).equals(Double.valueOf(y))</code>. (Unlike the <code>==</code>
     * operator, NaN is considered equal to itself, and <code>0.0</code> unequal to <code>-0.0</code>.)
     *
     * <li>Two corresponding <code>String</code>, <code>Class</code>, enum, or annotation typed members whose
     * values are <code>x</code> and <code>y</code> are considered equal if <code>x.equals(y)</code>. (Note that
     * this definition is recursive for annotation typed members.)
     * </ul>
     * @return true if the specified object represents an annotation that is logically equivalent to
     *         this one, otherwise false
     */
    @Override
    boolean equals(@Nullable Object obj);

    /**
     * Returns the hash code of this annotation, as defined below:
     *
     * <p>
     * The hash code of an annotation is the sum of the hash codes of its members (including those with
     * default values), as defined below:
     *
     * The hash code of an annotation member is (127 times the hash code of the member-name as computed
     * by {@link String#hashCode()}) XOR the hash code of the member-value, as defined below:
     *
     * <p>
     * The hash code of a member-value depends on its type:
     * <ul>
     * <li>The hash code of a primitive value <code><i>v</i></code> is equal to
     * <code><i>WrapperType</i>.valueOf(<i>v</i>).hashCode()</code>, where <code><i>WrapperType</i></code> is
     * the wrapper type corresponding to the primitive type of <code><i>v</i></code> ({@link Byte},
     * {@link Character}, {@link Double}, {@link Float}, {@link Integer}, {@link Long}, {@link Short},
     * or {@link Boolean}).
     *
     * <li>The hash code of a string, enum, class, or annotation member-value I <code><i>v</i></code> is
     * computed as by calling <code><i>v</i>.hashCode()</code>. (In the case of annotation member values,
     * this is a recursive definition.)
     * </ul>
     *
     * @return the hash code of this annotation
     */
    @Override
    int hashCode();

    /**
     * Returns a string representation of this annotation. The details of the representation are
     * implementation-dependent, but the following may be regarded as typical:
     *
     * <pre>
     *   &#064;com.acme.util.Name(first=Alfred, middle=E., last=Neuman)
     * </pre>
     *
     * @return a string representation of this annotation
     */
    @Override
    String toString();
}
