skip to Main Content

I know that this question has been already posted. But after many days searching a solution, i can’t find one..

I have two objects, which are converted to HashMap.
Once these HashMap I need to merge object 1 into object 2.
Namely: These objects can contain null keys.

I want the attribute of object 1 to replace the attribute of object 2 only if the attribute of object 1 is not null.


private <T> Map<String, T> mergeObjects(T first, T second) {
        ObjectMapper oMapper = new ObjectMapper();

        // On transforme l'objet en une MAP afin de faciliter le merge
        Map<String, T> objet1Map = oMapper.convertValue(first, Map.class);
        Map<String, T> objet2Map = oMapper.convertValue(second, Map.class);


        // Merge object 1 into object 2 (but it merges null values, i don't want that..)
        objet2Map.putAll(objet1Map);

        return objet2Map;
    }


My object is something like that :

{
        "environment": "d",
        "type": "deploymentconfig",
        "component": {
            "template": "redis-template.yaml",
            "routes": null,
            "parameters": {
                "REQUESTS_CPU": "25m",
                "LIMITS_MEMORY": null,
                "PROBE_PATH": null,
                "IMAGE_STREAM": "my-image",
                "IMAGE_STREAM_TAG": "6.9.6"
}
...
...
}

Edit 1 :

objet1 : {component={template=redis-pvc-component-template.yaml, parameters={REQUESTS_CPU=25m, IMAGE_STREAM=redis-5-rhel7-gtec, IMAGE_STREAM_TAG=5.16_19.12, MEMORY_LIMIT=298Mi}}, type=deploymentconfig}

objet2: {component={parameters={STORAGECLASS=prod}}, environment=p, type=deploymentconfig}

Result ->

{
        "environment": "p",
        "type": "deploymentconfig",
        "component": {
            "template": null,
            "routes": null,
            "parameters": {
                "REQUESTS_CPU": null, // disappeared
                "LIMITS_MEMORY": null,
                "PROBE_PATH": null,
                "IMAGE_STREAM": null, // disappeared
                "IMAGE_STREAM_TAG": null, // disappeared
                "MEMORY_LIMIT": null, // disappeared
                "STORAGECLASS": "prod",
                "VOLUME": null,
                "ROUTE_HOSTNAME": null,
                "IMAGE_STREAM_PROJECT": null,
                "LIVENESS_PROBE_PATH": null,
                "LIVENESS_PROBE_DELAY": null,
                "READINESS_PROBE_PATH": null,
                "READINESS_PROBE_DELAY": null,
                "JAVA_OPTIONS": null,
                "ENVIRONMENT": null
            }
        },
        "autoscaler": null
    }



As you can see many properties have disappeared after the putAll..

3

Answers


  1. Chosen as BEST ANSWER

    Answer that works for me : -> https://stackoverflow.com/a/29698326/13761574

    // This is fancier than Map.putAll(Map)
    private static Map deepMerge(Map original, Map newMap) {
        for (Object key : newMap.keySet()) {
            if (newMap.get(key) instanceof Map && original.get(key) instanceof Map) {
                Map originalChild = (Map) original.get(key);
                Map newChild = (Map) newMap.get(key);
                original.put(key, deepMerge(originalChild, newChild));
            } else if (newMap.get(key) instanceof List && original.get(key) instanceof List) {
                List originalChild = (List) original.get(key);
                List newChild = (List) newMap.get(key);
                for (Object each : newChild) {
                    if (!originalChild.contains(each)) {
                        originalChild.add(each);
                    }
                }
            } else {
                original.put(key, newMap.get(key));
            }
        }
        return original;
    }
    

  2. Edit 1:

        @Test
        public void test() throws JsonProcessingException {
            ObjectMapper objectMapper = new ObjectMapper();
            objectMapper.setSerializationInclusion(Include.NON_NULL);
    
            HashMap<String,String> map = new HashMap<>();
    
            map.put("some","some");
            map.put("other",null);
    
            HashMap<String,Object> othermap = new HashMap<>();
            othermap.put("keey","value");
            othermap.put("nested",map);
    
            final String asString = objectMapper.writeValueAsString(othermap);
            System.out.println(asString);
        }
    }
    

    without serialization config.

    {"keey":"value","nested":{"some":"some","other":null}}.

    with serialization config.

    {"keey":"value","nested":{"some":"some"}} //non null inclusion.


    Can you try setting objectmapper to exclude null properties?

    mapper.setSerializationInclusion(Include.NON_NULL);

    https://www.baeldung.com/jackson-ignore-null-fields#globally

    Login or Signup to reply.
  3. You’ll need to merge the individual entries of the maps.

    If you just want to keep the value of the first map, you can just use putIfAbsent().

    Map<String, T> map1 = ...
    Map<String, T> map2 = ...
    Map<String, T> result = new HashMap<>(map1);
    
    map2.forEach((key, value) -> result.putIfAbsent(key, value);
    

    If you have the value in both maps, you can use merge to define behavior to calculate what value you want.

    map2.forEach((key, value) -> result.merge(key, value, // put if absent
       (v1, v2) -> v1); // calculate new value if present in both
    }
    

    The latter example I give behaves equivalent to the first, ie it keeps the existing value in the map.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search