Java 解析列表<;字符串>;作为JSON

Java 解析列表<;字符串>;作为JSON,java,json,jackson,gson,Java,Json,Jackson,Gson,我正在阅读《真实世界软件开发》一书,本章是关于编写一个BankStatementCSVParser,它读取的文件如下: 30-01-2017,-100, Deliveroo 30-01-2017,-50, Tesco 01-02-2017,6000, Salary 02-02-2017,2000, Royalties 02-02-2017,-4000, Rent 03-02-2017,3000, Tesco 05-02-2017,-30, Cinema 并解析每行并输出此类的对象: publi

我正在阅读《真实世界软件开发》一书,本章是关于编写一个
BankStatementCSVParser
,它读取的文件如下:

30-01-2017,-100, Deliveroo
30-01-2017,-50, Tesco
01-02-2017,6000, Salary
02-02-2017,2000, Royalties
02-02-2017,-4000, Rent
03-02-2017,3000, Tesco
05-02-2017,-30, Cinema
并解析每行并输出此类的对象:

public class BankTransaction {
    private final LocalDate date;
    private final double amount;
    private final String description;

    public BankTransaction(final LocalDate date, final double amount, 
           final String description) {
        this.date = date;
        this.amount = amount;
        this.description = description;
    }

    public LocalDate getDate() {
        return date;
    }

    public double getAmount() {
        return amount;
    }

    public String getDescription() {
        return description;
    }
}
这很好,CSV很容易(特别是因为我在复制这本书…),问题出现在本章末尾,当时我被要求在可能的情况下自己实现
BankStatementJSONParser

我尝试过woth GSON和Jackson,但我无法真正获得任何示例,因为我的
BankTransaction
类是不可变的,不允许设置器

我设法找到了一个可行的解决方案,但看起来很可怕:

public List<BankTransaction> parseLinesFrom(List<String> lines) {
    Map<String, ?> map = new Gson().fromJson(String.join(" ", lines), Map.class);
    List<?> listOfTransactions = (List<?>) map.get("transactions");

    List<BankTransaction> bankTransactions = new ArrayList<>();
    listOfTransactions.forEach(rawJson -> {
        LinkedTreeMap<String, ?> javaJson = (LinkedTreeMap<String, ?>) rawJson;

        final LocalDate localDate = LocalDate.parse(javaJson.get("date").toString(), DATE_PATTERN);
        final double amount = Double.parseDouble(javaJson.get("amount").toString());
        final String description = javaJson.get("description").toString();
        BankTransaction newTransaction = new BankTransaction(localDate, amount, description);
        bankTransactions.add(newTransaction);
    });
    return bankTransactions;
}

您的问题有几种不同的解决方案:

  • 您可以创建自己的来解析列表
  • 您可以使用s在运行时告诉Gson您将加载什么(这肯定会打破
    日期
    字段)
  • 你可以自己创造

  • 我个人会做第二个,只为LocalDate创建一个自定义,它在注册后由Gson自动应用。

    我使用了被接受的答案描述的方法,但在Jackson中,通过覆盖Jackson ObjectMapper并在构造函数中接受DateTimeFormatter,而不是在Gson中:

    public class CustomObjectMapper extends ObjectMapper {
    public CustomObjectMapper(DateTimeFormatter pattern){
        SimpleModule customModule = new SimpleModule("LocalDateMapper");
        customModule.addSerializer(LocalDate.class, new JsonSerializer<LocalDate>() {
            @Override
            public void serialize(LocalDate value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
                ToStringSerializer.instance.serialize(value, gen, serializers);
            }
        });
        customModule.addDeserializer(LocalDate.class, new JsonDeserializer<LocalDate>() {
            @Override
            public LocalDate deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
                return LocalDate.parse(p.getText(), pattern);
            }
        });
    
        registerModule(customModule);
    
    }
    
    公共类CustomObjectMapper扩展了ObjectMapper{
    公共CustomObjectMapper(DateTimeFormatter模式){
    SimpleModule customModule=新的SimpleModule(“LocalDateMapper”);
    addSerializer(LocalDate.class,新的JsonSerializer()){
    @凌驾
    public void serialize(LocalDate值、JsonGenerator gen、SerializerProvider序列化程序)引发IOException{
    序列化(值、根、序列化器);
    }
    });
    addDeserializer(LocalDate.class,新的JsonDeserializer(){
    @凌驾
    公共LocalDate反序列化(JsonParser p,DeserializationContext ctxt)抛出IOException,JsonProcessingException{
    返回LocalDate.parse(p.getText(),pattern);
    }
    });
    注册模块(customModule);
    }
    

    }

    @JsonCreator
    注释构造函数和用
    @JsonProperty
    注释其参数是否解决了您的问题?您可以直接使用jackson反序列化:
    objectMapper.readValue(input,List.class)
    这可能是您问题的解决方案:感谢您的建议,它几乎成功了,但它看起来不喜欢日期字段,尝试添加了一些@JsonFormat,但它不断抱怨非法反射。谢谢,我照你说的做了,但是用了杰克逊。这对我来说相当复杂,但现在我觉得它不再那么神奇了:)
    public class CustomObjectMapper extends ObjectMapper {
    public CustomObjectMapper(DateTimeFormatter pattern){
        SimpleModule customModule = new SimpleModule("LocalDateMapper");
        customModule.addSerializer(LocalDate.class, new JsonSerializer<LocalDate>() {
            @Override
            public void serialize(LocalDate value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
                ToStringSerializer.instance.serialize(value, gen, serializers);
            }
        });
        customModule.addDeserializer(LocalDate.class, new JsonDeserializer<LocalDate>() {
            @Override
            public LocalDate deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
                return LocalDate.parse(p.getText(), pattern);
            }
        });
    
        registerModule(customModule);
    
    }