class AffinityKey<K> implements Externalizable {
    /** */
    private static final long serialVersionUID = 0L;

    /** Key. */
    @GridToStringInclude(sensitive = true)
    private K key;

    /** Affinity key. */
    @AffinityKeyMapped
    @GridToStringInclude(sensitive = true)
    private Object affKey;

    /**
     * Empty constructor.
     */
    public AffinityKey() {
        // No-op.
    }

    /**
     * Initializes key wrapper for a given key. If affinity key
     * is not initialized, then this key will be used for affinity.
     *
     * @param key Key.
     */
    public AffinityKey(K key) {
        A.notNull(key, "key");

        this.key = key;
    }

    /**
     * Initializes key together with its affinity key counter-part.
     *
     * @param key Key.
     * @param affKey Affinity key.
     */
    public AffinityKey(K key, Object affKey) {
        A.notNull(key, "key");

        this.key = key;
        this.affKey = affKey;
    }

    /**
     * Gets wrapped key.
     *
     * @return Wrapped key.
     */
    public K key() {
        return key;
    }

    /**
     * Sets wrapped key.
     *
     * @param key Wrapped key.
     */
    public void key(K key) {
        this.key = key;
    }

    /**
     * Gets affinity key to use for affinity mapping. If affinity key is not provided,
     * then {@code key} value will be returned.
     * <p>
     * This method is annotated with {@link AffinityKeyMapped} and will be picked up
     * by {@link GridCacheDefaultAffinityKeyMapper} automatically.
     *
     * @param <T> Type of affinity key.
     *
     * @return Affinity key to use for affinity mapping.
     */
    public <T> T affinityKey() {<FILL_FUNCTION_BODY>}

    /**
     * Sets affinity key to use for affinity mapping. If affinity key is not provided,
     * then {@code key} value will be returned.
     *
     * @param affKey Affinity key to use for affinity mapping.
     */
    public void affinityKey(Object affKey) {
        this.affKey = affKey;
    }

    /** {@inheritDoc} */
    @Override public void writeExternal(ObjectOutput out) throws IOException {
        out.writeObject(key);
        out.writeObject(affKey);
    }

    /** {@inheritDoc} */
    @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
        key = (K)in.readObject();
        affKey = in.readObject();
    }

    /**
     * Hash code implementation which delegates to the underlying {@link #key()}. Note, however,
     * that different subclasses of {@link AffinityKey} will produce different hash codes.
     * <p>
     * Users should override this method if different behavior is desired.
     *
     * @return Hash code.
     */
    @Override public int hashCode() {
        A.notNull(key, "key");

        return 31 * key.hashCode() + getClass().getName().hashCode();
    }

    /**
     * Equality check which delegates to the underlying key equality. Note, however, that
     * different subclasses of {@link AffinityKey} will never be equal.
     * <p>
     * Users should override this method if different behavior is desired.
     *
     * @param obj Object to check for equality.
     * @return {@code True} if objects are equal.
     */
    @Override public boolean equals(Object obj) {
        A.notNull(key, "key");

        return obj != null && getClass() == obj.getClass() && key.equals(((AffinityKey)obj).key);
    }

    /** {@inheritDoc} */
    @Override public String toString() {
        return S.toString(AffinityKey.class, this);
    }
}

        A.notNull(key, "key");

        return (T)(affKey == null ? key : affKey);
    
<no_super_class>