Список синтаксического анализа <String>как JSON - PullRequest
3 голосов
/ 28 мая 2020

Я слежу за книгой «Разработка программного обеспечения в реальном мире», и текущая глава была посвящена написанию 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 сам, если бы мог.

Я пробовал использовать 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;
}

Спасибо за любые идеи, как я могу сделать это менее уродливым, возможно, проблема в том, что я написал сам. json файл:

{
  "transactions": [
    {
      "date": "30-01-2017",
      "amount": -100,
      "description": "Deliveroo"
    },
    {
      "date": "01-02-2017",
      "amount": 6000,
      "description": "Salary"
    }
  ]
}

Ответы [ 2 ]

2 голосов
/ 28 мая 2020

Есть несколько различных решений вашей проблемы:

  1. Вы можете создать свой собственный TypeAdapter для анализа списка
  2. Вы можете использовать TypeToken s, чтобы сообщить Gson во время выполнения, что вы будете загружать (хотя это наверняка сломает поле date)
  3. Вы можете создать свой собственный JsonDeserializer

Я лично сделал бы второй и создал специальный TypeAdapter только для LocalDate, который автоматически применяется Gson после его регистрации.

0 голосов
/ 03 июня 2020

Я использовал метод, описанный в принятом ответе, но в Jackson вместо GSON, переопределив Jackson ObjectMapper и приняв DateTimeFormatter в конструкторе:

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

}

}

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...