package com.codepoetics.octarine.json.deserialisation; import com.codepoetics.octarine.records.Key; import com.codepoetics.octarine.records.Record; import com.codepoetics.octarine.records.Value; import com.codepoetics.octarine.records.Schema; import com.codepoetics.octarine.records.Valid; import com.codepoetics.octarine.records.Validation; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonToken; import org.pcollections.PMap; import org.pcollections.PVector; import java.io.IOException; import java.util.*; import java.util.function.BiFunction; import java.util.function.Function; import java.util.function.Supplier; public final class RecordDeserialiser implements SafeDeserialiser<Record> { public static Builder builder() { return new Builder(); } public static final class Builder implements Supplier<RecordDeserialiser> { private final Map<String, Function<JsonParser, Value>> valueReaders = new HashMap<>(); Builder() { } @Override public RecordDeserialiser get() { return new RecordDeserialiser((fieldName, parser) -> Optional.ofNullable(valueReaders.get(fieldName)).map(r -> r.apply(parser))); } public <V> Builder read(Key<? super V> key, Function<JsonParser, ? extends V> deserialiser) { return read(key, key.name(), deserialiser); } public <V> Builder read(Key<? super V> key, String fieldName, Function<JsonParser, ? extends V> deserialiser) { valueReaders.put(fieldName, p -> key.of(deserialiser.apply(p))); return this; } public <V> Builder read(Key<V> key, Supplier<Function<JsonParser, V>> deserialiserSupplier) { return read(key, deserialiserSupplier.get()); } public <V> Builder read(Key<V> key, String fieldName, Supplier<Function<JsonParser, V>> deserialiserSupplier) { return read(key, fieldName, deserialiserSupplier.get()); } public Builder readString(Key<String> key) { return read(key, Deserialisers.ofString); } public <V> Builder readFromString(Key<? super V> key, Function<String, V> converter) { return read(key, Deserialisers.ofString.andThen(converter)); } public Builder readInteger(Key<Integer> key) { return read(key, Deserialisers.ofInteger); } public Builder readDouble(Key<Double> key) { return read(key, Deserialisers.ofDouble); } public Builder readBoolean(Key<Boolean> key) { return read(key, Deserialisers.ofBoolean); } public Builder readLong(Key<Long> key) { return read(key, Deserialisers.ofLong); } public <V> Builder readList(Key<PVector<V>> key, Function<JsonParser, ? extends V> deserialiser) { return read(key, ListDeserialiser.readingItemsWith(deserialiser)); } public <V> Builder readMap(Key<PMap<String, V>> key, Function<JsonParser, ? extends V> deserialiser) { return read(key, MapDeserialiser.readingValuesWith(deserialiser)); } public <V> Builder readValidRecord(Key<Valid<V>> key, Function<JsonParser, Validation<V>> deserialiser) { return read(key, Deserialisers.ofValid(deserialiser)); } public Builder readString(Key<String> key, String fieldName) { return read(key, fieldName, Deserialisers.ofString); } public <V> Builder readFromString(Key<? super V> key, String fieldName, Function<String, V> converter) { return read(key, fieldName, Deserialisers.ofString.andThen(converter)); } public Builder readInteger(Key<Integer> key, String fieldName) { return read(key, fieldName, Deserialisers.ofInteger); } public Builder readDouble(Key<Double> key, String fieldName) { return read(key, fieldName, Deserialisers.ofDouble); } public Builder readBoolean(Key<Boolean> key, String fieldName) { return read(key, fieldName, Deserialisers.ofBoolean); } public Builder readLong(Key<Long> key, String fieldName) { return read(key, fieldName, Deserialisers.ofLong); } public <V> Builder readList(Key<PVector<V>> key, String fieldName, Function<JsonParser, ? extends V> deserialiser) { return read(key, fieldName, ListDeserialiser.readingItemsWith(deserialiser)); } public <V> Builder readMap(Key<PMap<String, V>> key, String fieldName, Function<JsonParser, ? extends V> deserialiser) { return read(key, fieldName, MapDeserialiser.readingValuesWith(deserialiser)); } public <V> Builder readValidRecord(Key<Valid<V>> key, String fieldName, Function<JsonParser, Validation<V>> deserialiser) { return read(key, fieldName, Deserialisers.ofValid(deserialiser)); } } private final BiFunction<String, JsonParser, Optional<Value>> parserMapper; private RecordDeserialiser(BiFunction<String, JsonParser, Optional<Value>> parserMapper) { this.parserMapper = parserMapper; } @Override public Record applyUnsafe(JsonParser parser) throws IOException { List<Value> values = new ArrayList<>(); if (parser.nextToken() == JsonToken.END_OBJECT) { return Record.empty(); } while (parser.nextValue() != JsonToken.END_OBJECT) { String fieldName = parser.getCurrentName(); Optional<Value> result = parserMapper.apply(fieldName, parser); if (result.isPresent()) { values.add(result.get()); } else { consumeUnwanted(parser); } } return Record.of(values); } private void consumeUnwanted(JsonParser parser) throws IOException { if (parser.getCurrentToken() == JsonToken.START_OBJECT) { while (parser.nextValue() != JsonToken.END_OBJECT) { if (parser.getCurrentToken() == JsonToken.START_OBJECT) { consumeUnwanted(parser); } } } } public <S> Deserialiser<Validation<S>> validAgainst(Schema<S> schema) { return new ValidRecordDeserialiser<>(schema, this); } }