简体   繁体   English

如何使用 jackson Z93F725A07423FE1C8146F448B33ZD 将 csv 读取到嵌套的 json

[英]how to read a csv to a nested json with jackson java

i have this type of csv:我有这种类型的 csv:

metric,value,date
temp_a,622.0,1477895624866
temp_a,-3.0,1477916224866
temp_a,365.0,1477917224866
temp_b,861.0,1477895624866
temp_b,767.0,1477917224866

and i want to use java jackson to convert it to json but not any json;我想使用 java jackson 将其转换为 json 但不是任何 Z466DEEC76ECDF5FCA6D38571F6 it needs to be like this:它需要是这样的:

[
  {
    "metric":"temp_a",
    "datapoints":[
      [622, 1477895624866],
      [-3, 1477916224866],
      [365, 1477917224866]
    ]
  },
  {
    "metric":"temp_b",
    "datapoints":[
      [861, 1477895624866],
      [767, 1477917224866]
    ]
  }
]

where dataponits is an array containing the value and the date in the csv.其中 dataponits 是一个数组,其中包含 csv 中的值和日期。

i have managed to use the jackson to get this result:我已经设法使用 jackson 来得到这个结果:

{metric=temp_a, value=622.0, date=1477895624866}
{metric=temp_a, value=-3.0, date=1477916224866}
{metric=temp_a, value=365.0, date=1477917224866}
{metric=temp_b, value=861.0, date=1477895624866}
{metric=temp_b, value=767.0, date=1477917224866}

but it is not what i want and the jackson doc is a bit hard for me to understand and play with, may be this is possible with Pojos or annotations but i can't understand them, i couldn't find how to do a nested json.但这不是我想要的,jackson 文档对我来说有点难以理解和使用,可能这可以通过 Pojos 或注释来实现,但我无法理解它们,我找不到如何进行嵌套json。

if i can do this better this something else then jackson please tell me.如果我能在这方面做得更好,那么 jackson 请告诉我。 thank you for helping.感谢您的帮助。

You do not have to always deserialise CSV to a POJO structure and implement custom serialisers.您不必总是将CSV反序列化为POJO结构并实现自定义序列化器。 In this case, you can also:在这种情况下,您还可以:

  • Deserialise CSV to a Map将 CSV 反序列CSV Map
  • Group by elements in a Map to a form metric -> [[...], [...]]Map中的元素分组为表单metric -> [[...], [...]]
  • Convert above Map to another form of Map将上面的Map转换为Map的另一种形式
  • Serialise Map to a JSONMap JSON

Example code could look like below:示例代码如下所示:

import com.fasterxml.jackson.core.util.DefaultIndenter;
import com.fasterxml.jackson.core.util.DefaultPrettyPrinter;
import com.fasterxml.jackson.databind.MappingIterator;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.json.JsonMapper;
import com.fasterxml.jackson.dataformat.csv.CsvMapper;
import com.fasterxml.jackson.dataformat.csv.CsvSchema;

import java.io.File;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

public class CsvApp {

    public static void main(String[] args) throws Exception {
        File csvFile = new File("./resource/test.csv").getAbsoluteFile();

        CsvMapper csvMapper = CsvMapper.builder().build();
        MappingIterator<Map> rows = csvMapper
                .readerWithSchemaFor(Map.class)
                .with(CsvSchema.emptySchema().withHeader())
                .readValues(csvFile);

        DataConverter converter = new DataConverter();
        List<Map<String, Object>> result = converter.toMetricDataPoints(rows);

        ObjectMapper jsonMapper = JsonMapper.builder()
                .enable(SerializationFeature.INDENT_OUTPUT)
                .build();

        jsonMapper.writeValue(System.out, result);
    }

}

class DataConverter {

    public List<Map<String, Object>> toMetricDataPoints(MappingIterator<Map> rows) {
        return toStream(rows)
            //group by metric -> [value, date]
            .collect(Collectors.groupingBy(map -> map.get("metric"),
                Collectors.mapping(map -> Arrays.asList(toNumber(map.get("value")), toNumber(map.get("date"))),
                    Collectors.toList())))
            .entrySet().stream()
            // convert to Map: metric + datapoints
            .map(entry -> {
                Map<String, Object> res = new LinkedHashMap<>(4);
                res.put("metric", entry.getKey());
                res.put("datapoints", entry.getValue());

                return res;
            }).collect(Collectors.toList());
    }

    private Stream<Map> toStream(MappingIterator<Map> rowIterator) {
        return StreamSupport.stream(Spliterators.spliteratorUnknownSize(rowIterator, Spliterator.ORDERED), false);
    }

    private long toNumber(Object value) {
        return new BigDecimal(Objects.toString(value, "0")).longValue();
    }
}

Above code prints:上面的代码打印:

[ {
  "metric" : "temp_a",
  "datapoints" : [ [ 622, 1477895624866 ], [ -3, 1477916224866 ], [ 365, 1477917224866 ] ]
}, {
  "metric" : "temp_b",
  "datapoints" : [ [ 861, 1477895624866 ], [ 767, 1477917224866 ] ]
} ]

As you can see, we used only basic Jackson functionality, rest of manipulation on data we implemented using Java 8 API . As you can see, we used only basic Jackson functionality, rest of manipulation on data we implemented using Java 8 API .

See also:也可以看看:

  1. Directly convert CSV file to JSON file using the Jackson library 使用 Jackson 库直接将 CSV 文件转换为 JSON 文件
  2. How to convert an iterator to a stream? 如何将迭代器转换为 stream?
  3. Jackson JSON Deserialization: array elements in each line Jackson JSON 反序列化:每行数组元素

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM