Java 8 Streams 中的 GroupingBy 具有超过 3 级分组

问题描述 投票:0回答:1

我需要生成这样的输出json

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

来自以下示例的对象列表

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

我尝试过这样的事情

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())))));

希望任何人都可以为我指明正确的方向,以使用 hashmap 获得所需的输出

java json hashmap java-stream
1个回答
0
投票

这是一个合理的,但非基于流的解决方案来解决您的问题:

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);
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.