skip to Main Content

I need to generate an output json like below

{
   "account":{
      "Alpha":{
         "OLD":{
            "long":"zerozerooneO",
            "short":"001O"
         },
         "NEW":{
            "long":"zerozerooneN",
            "short":"001N"
         }
      },
      "Beta":{
         "OLD":{
            "long":"zerozerooneO",
            "short":"001O"
         },
         "NEW":{
            "long":"zerozerooneN",
            "short":"001N"
         }
      }
   }
}

From a List of object with sample below

[
   {
      "codetype":"Alpha",
      "shortOldCode":"001O",
      "longOldCode":"zerozerooneO",
      "shortNewCode":"001N",
      "longNewCode":"zerozerooneN"
   },
   {
      "codetype":"Beta",
      "shortOldCode":"001O",
      "longOldCode":"zerozerooneO",
      "shortNewCode":"001N",
      "longNewCode":"zerozerooneN"
   }
]

I have tried something like this

Map<String, Map<String, Map<String, List<Object>>>> newList = new HashMap<>();
            newList = dataMap.stream()
                    .filter(distinctByKey(code -> code.getCodeType())).collect(
                            groupingBy((GetCodeTypes a) -> "account",
                                    groupingBy((GetCodeTypes b) -> b.getCodeType(),
                                            groupingBy((GetCodeTypes c) -> "OLD",
                                                    mapping(
                                                            v -> {
                                                                GetCodeTypesResponse.Old
oldCode = new GetCodeTypesResponse.Old();
                                                                oldCode.setLongs(v.getLongOldCode());
                                                                oldCode.setShorts(v.getShortOldCode());
                                                                return oldCode;
                                                            }, toList())))));

Hoping anyone could point me in a right direction to get the desired output using hashmap in Java 8.I know grouping/mapping with record might work with new version of Java but the project I am working on is Java 1.8 and I would like to use Java Streams to solve this if possible.

2

Answers


  1. Here is a reasonable, but non-stream based solution to your problem:

    package com.learn.grouping;
    
    import com.fasterxml.jackson.annotation.JsonProperty;
    
    import lombok.Getter;
    import lombok.Setter;
    import lombok.ToString;
    
    /**
     * This is the format of your input JSON
     */
    @Getter
    @Setter
    @ToString(doNotUseGetters = true)
    public class BlamItemInput
    {
        @JsonProperty("codetype")
        private String codeType;
    
        private String longNewCode;
        private String longOldCode;
        private String shortNewCode;
        private String shortOldCode;
    }
    
    package com.learn.grouping;
    
    import java.util.List;
    
    import org.apache.commons.collections4.CollectionUtils;
    import org.springframework.stereotype.Component;
    
    /**
     * This converts from input format to desired output (layered map) format.
     */
    @Component
    public class BlamConverter
    {
        public CodeTypeMap convert(final List<BlamItemInput> blamItemInputList)
        {
            final CodeTypeMap returnValue;
    
            if (CollectionUtils.isNotEmpty(blamItemInputList))
            {
                returnValue = new CodeTypeMap();
    
                for (final BlamItemInput current : blamItemInputList)
                {
                    final KapowItem kapowItem = new KapowItem();
    
                    kapowItem.setNewItem(current.getLongNewCode(), current.getShortNewCode());
                    kapowItem.setOldItem(current.getLongOldCode(), current.getShortOldCode());
    
                    returnValue.addKapowItem(current.getCodeType(), kapowItem);
                }
            }
            else
            {
                returnValue = null;
            }
    
            return returnValue;
        }
    }
    
    package com.learn.grouping;
    
    import java.util.HashMap;
    import java.util.Map;
    
    import com.fasterxml.jackson.annotation.JsonProperty;
    
    import lombok.Getter;
    import lombok.ToString;
    
    /**
     * Top level of the output format
     */
    @Getter
    @ToString(doNotUseGetters = true)
    public class CodeTypeMap
    {
        @JsonProperty("account")
        private final Map<String, KapowItem> kapowMap = new HashMap<>();
    
        public void addKapowItem(
            final String keyValue,
            final KapowItem newCodeTypeItem)
        {
            kapowMap.put(keyValue, newCodeTypeItem);
        }
    }
    
    package com.learn.grouping;
    
    import com.fasterxml.jackson.annotation.JsonProperty;
    import com.fasterxml.jackson.annotation.JsonPropertyOrder;
    
    import lombok.Getter;
    import lombok.ToString;
    
    /**
     * Second level of the output JSON
     */
    @Getter
    @ToString(doNotUseGetters = true)
    @JsonPropertyOrder({"OLD", "NEW"})
    public class KapowItem
    {
        @JsonProperty("NEW")
        private KapowNestedItem newItem;
    
        @JsonProperty("OLD")
        private KapowNestedItem oldItem;
    
        public void setNewItem(
            final String longValue,
            final String shortValue)
        {
            newItem = new KapowNestedItem(longValue, shortValue);
        }
    
        public void setOldItem(
            final String longValue,
            final String shortValue)
        {
            oldItem = new KapowNestedItem(longValue, shortValue);
        }
    }
    
    package com.learn.grouping;
    
    import com.fasterxml.jackson.annotation.JsonProperty;
    
    import lombok.Getter;
    import lombok.RequiredArgsConstructor;
    import lombok.ToString;
    
    /**
     * Bottom (third) level of the output JSON
     */
    @Getter
    @RequiredArgsConstructor
    @ToString(doNotUseGetters = true)
    public class KapowNestedItem
    {
        @JsonProperty("long")
        private final String longValue;
    
        @JsonProperty("short")
        private final String shortValue;
    }
    
    package com.learn.grouping;
    
    import java.util.List;
    
    import org.junit.jupiter.api.BeforeEach;
    import org.junit.jupiter.api.Test;
    import org.junit.jupiter.api.extension.ExtendWith;
    import org.mockito.junit.jupiter.MockitoExtension;
    import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
    
    import com.fasterxml.jackson.annotation.JsonInclude.Include;
    import com.fasterxml.jackson.core.JsonProcessingException;
    import com.fasterxml.jackson.databind.DeserializationFeature;
    import com.fasterxml.jackson.databind.JsonMappingException;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.fasterxml.jackson.databind.SerializationFeature;
    import com.fasterxml.jackson.databind.type.TypeFactory;
    
    /**
     * Converter unit test because, you aren't done until after you unit test.
     */
    @ExtendWith(MockitoExtension.class)
    public class TestBlamConverter
    {
        private static final String INPUT_JSON = "[{"codetype":"Alpha","shortOldCode":"001O","longOldCode":"zerozerooneO","shortNewCode":"001N","longNewCode":"zerozerooneN"},{"codetype":"Beta","shortOldCode":"001O","longOldCode":"zerozerooneO","shortNewCode":"001N","longNewCode":"zerozerooneN"}]";
    
        private BlamConverter classToTest;
    
        private ObjectMapper objectMapper;
    
        @BeforeEach
        void beforeEach()
        {
            final Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
    
            builder.featuresToDisable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,
                SerializationFeature.WRITE_DATES_AS_TIMESTAMPS,
                SerializationFeature.FAIL_ON_EMPTY_BEANS);
    
            builder.serializationInclusion(Include.NON_NULL);
    
            objectMapper = builder.build();
    
            classToTest = new BlamConverter();
        }
    
        @Test
        void convert_allGood_succes() throws JsonMappingException, JsonProcessingException
        {
            final CodeTypeMap actualResult;
            final List<BlamItemInput> inputList;
            final String outputJson;
            final TypeFactory typeFactory = objectMapper.getTypeFactory();
    
            inputList = objectMapper.readValue(INPUT_JSON, typeFactory.constructCollectionType(List.class, BlamItemInput.class));
    
    
            actualResult = classToTest.convert(inputList);
    
    
            outputJson = objectMapper.writeValueAsString(actualResult);
    
            System.out.println("outputJson: " + outputJson);
        }
    }
    
    Login or Signup to reply.
  2. This is a simple non-stream solution that use JSON library to do the transformation.

    https://github.com/octomix/josson

    Josson josson = Josson.fromJsonString("[{"codetype":"Alpha","shortOldCode":"001O","longOldCode":"zerozerooneO","shortNewCode":"001N","longNewCode":"zerozerooneN"},{"codetype":"Beta","shortOldCode":"001O","longOldCode":"zerozerooneO","shortNewCode":"001N","longNewCode":"zerozerooneN"}]");
    JsonNode node = josson.getNode(
        "map(codetype::" +
        "    map(OLD:" +
        "        map(long: longOldCode," +
        "            short: shortOldCode)," +
        "        NEW:" +
        "        map(long: longNewCode," +
        "            short: shortNewCode)" +
        "    )" +
        ")" +
        ".mergeObjects()" +
        ".toObject('account')");
    System.out.println(node.toPrettyString());
    

    Output

    {
      "account" : {
        "Alpha" : {
          "OLD" : {
            "long" : "zerozerooneO",
            "short" : "001O"
          },
          "NEW" : {
            "long" : "zerozerooneN",
            "short" : "001N"
          }
        },
        "Beta" : {
          "OLD" : {
            "long" : "zerozerooneO",
            "short" : "001O"
          },
          "NEW" : {
            "long" : "zerozerooneN",
            "short" : "001N"
          }
        }
      }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search