public ResourceSpec merge(final ResourceSpec other) {
        checkNotNull(other, "Cannot merge with null resources");

        if (this.equals(UNKNOWN) || other.equals(UNKNOWN)) {
            return UNKNOWN;
        }

        Map<String, ExternalResource> resultExtendedResource = new HashMap<>(extendedResources);

        other.extendedResources.forEach(
                (String name, ExternalResource resource) -> {
                    resultExtendedResource.compute(
                            name,
                            (ignored, oldResource) ->
                                    oldResource == null ? resource : oldResource.merge(resource));
                });

        return new ResourceSpec(
                this.cpuCores.merge(other.cpuCores),
                this.taskHeapMemory.add(other.taskHeapMemory),
                this.taskOffHeapMemory.add(other.taskOffHeapMemory),
                this.managedMemory.add(other.managedMemory),
                resultExtendedResource);
    }
@Test
    void testMerge() {
        ResourceSpec rs1 =
                ResourceSpec.newBuilder(1.0, 100)
                        .setExtendedResource(new ExternalResource(EXTERNAL_RESOURCE_NAME, 1.1))
                        .build();
        ResourceSpec rs2 = ResourceSpec.newBuilder(1.0, 100).build();

        ResourceSpec rs3 = rs1.merge(rs2);
        assertThat(rs3.getCpuCores()).isEqualTo(new CPUResource(2.0));
        assertThat(rs3.getTaskHeapMemory().getMebiBytes()).isEqualTo(200);
        assertThat(rs3.getExtendedResource(EXTERNAL_RESOURCE_NAME))
                .hasValue(new ExternalResource(EXTERNAL_RESOURCE_NAME, 1.1));

        ResourceSpec rs4 = rs1.merge(rs3);
        assertThat(rs4.getExtendedResource(EXTERNAL_RESOURCE_NAME))
                .hasValue(new ExternalResource(EXTERNAL_RESOURCE_NAME, 2.2));
    }