class ClientCachePartitionAwarenessGroup {
    /** Partition mapping. If {@code null} then cache must be excluded in partition awareness usage (e.g. REPLICATED cache).  */
    private final @Nullable ClientCachePartitionMapping mapping;

    /** {@code true} if the RendezvousAffinityFunction is used with the default affinity key mapper. */
    private final boolean dfltAffinity;

    /** Descriptor of the associated caches. */
    private final Map<Integer, CacheConfiguration<?, ?>> cacheCfgs = new HashMap<>();

    /**
     * @param mapping Partition mapping.
     * @param dfltAffinity {@code true} if the default affinity or a custom affinity mapper was used.
     */
    public ClientCachePartitionAwarenessGroup(@Nullable ClientCachePartitionMapping mapping, boolean dfltAffinity) {
        this.mapping = mapping;
        this.dfltAffinity = dfltAffinity;
    }

    /**
     * Write mapping using binary writer.
     *
     * @param proc Binary processor.
     * @param writer Binary Writer.
     * @param cpctx Protocol context.
     */
    public void write(CacheObjectBinaryProcessorImpl proc, BinaryRawWriter writer, ClientProtocolContext cpctx) {
        boolean isPartitionAwarenessApplicable = mapping != null;

        writer.writeBoolean(isPartitionAwarenessApplicable);

        writer.writeInt(cacheCfgs.size());

        if (isPartitionAwarenessApplicable) {
            for (Map.Entry<Integer, CacheConfiguration<?, ?>> entry: cacheCfgs.entrySet()) {
                writer.writeInt(entry.getKey());

                writeCacheKeyConfiguration(writer, proc, entry.getValue().getKeyConfiguration());
            }

            mapping.write(writer);

            if (cpctx.isFeatureSupported(ClientBitmaskFeature.ALL_AFFINITY_MAPPINGS))
                writer.writeBoolean(dfltAffinity);
        }
        else {
            for (int cacheId : cacheCfgs.keySet())
                writer.writeInt(cacheId);
        }
    }

    /**
     * Add caches to the same affinity group.
     * @param descs Cache descriptors.
     */
    public void addAll(List<DynamicCacheDescriptor> descs) {
        for (DynamicCacheDescriptor desc : descs)
            cacheCfgs.putIfAbsent(desc.cacheId(), desc.cacheConfiguration());
    }

    /** */
    private static void writeCacheKeyConfiguration(
        BinaryRawWriter writer,
        CacheObjectBinaryProcessorImpl binProc,
        CacheKeyConfiguration[] keyCfgs
    ) {
        if (keyCfgs == null) {
            writer.writeInt(0);

            return;
        }

        writer.writeInt(keyCfgs.length);

        for (CacheKeyConfiguration keyCfg : keyCfgs) {
            int keyTypeId = binProc.typeId(keyCfg.getTypeName());
            int affKeyFieldId = binProc.binaryContext().fieldId(keyTypeId, keyCfg.getAffinityKeyFieldName());

            writer.writeInt(keyTypeId);
            writer.writeInt(affKeyFieldId);
        }
    }

    /** {@inheritDoc} */
    @Override public boolean equals(Object o) {<FILL_FUNCTION_BODY>}

    /** {@inheritDoc} */
    @Override public int hashCode() {
        return Objects.hash(mapping, dfltAffinity);
    }
}

        if (this == o)
            return true;

        if (o == null || getClass() != o.getClass())
            return false;

        ClientCachePartitionAwarenessGroup grp = (ClientCachePartitionAwarenessGroup)o;

        return dfltAffinity == grp.dfltAffinity && Objects.equals(mapping, grp.mapping);
    
<no_super_class>