All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.adgear.anoa.read.AvroReader Maven / Gradle / Ivy

Go to download

Core classes for Anoa library, which aims to be a safe, convenient and fast record de/serialization wrapper for the Avro, Thrift and Jackson libraries, using the functional idioms of Java 8. The anoa-core module tries to keep upstream dependencies to a minimum.

There is a newer version: 3.1.2
Show newest version
package com.adgear.anoa.read;

import com.adgear.anoa.AnoaJacksonTypeException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;

import org.apache.avro.Schema;
import org.apache.avro.generic.GenericData;
import org.apache.avro.generic.GenericRecord;
import org.apache.avro.generic.IndexedRecord;
import org.apache.avro.specific.SpecificData;
import org.apache.avro.specific.SpecificRecord;

import java.io.IOException;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

abstract class AvroReader extends AbstractReader {

  final protected List fieldWrappers;
  final private Map> fieldLookUp;

  abstract protected R newInstance() throws Exception;

  @SuppressWarnings("unchecked")
  private AvroReader(Schema schema) {
    this.fieldLookUp = new HashMap<>();
    this.fieldWrappers = new ArrayList<>();
    int index = 0;
    for (Schema.Field field : schema.getFields()) {
      AvroFieldWrapper fieldWrapper = new AvroFieldWrapper(index++, field);
      fieldWrappers.add(fieldWrapper);
      fieldLookUp.put(field.name(), Optional.of(fieldWrapper));
      field.aliases().stream().forEach(alias -> fieldLookUp.put(alias, Optional.of(fieldWrapper)));
    }
  }

  @Override
  protected R validateTopLevel(R record) {
    if (record instanceof SpecificRecord) {
      SpecificData.get().validate(record.getSchema(), record);
    } else {
      GenericData.get().validate(record.getSchema(), record);
    }
    return record;
  }

  @Override
  public R read(JsonParser jacksonParser) throws IOException {
    if (jacksonParser.getCurrentToken() == JsonToken.START_OBJECT) {
      final AvroRecordWrapper recordWrapper;
      try {
        recordWrapper = new AvroRecordWrapper<>(newInstance(), fieldWrappers);
      } catch (Exception e) {
        return null;
      }
      doMap(jacksonParser, (fieldName, p) -> {
        Optional cacheValue = fieldLookUp.get(fieldName);
        if (cacheValue == null) {
          final Optional>> found = fieldLookUp.entrySet().stream()
              .filter(e -> (0 == fieldName.compareToIgnoreCase(e.getKey())))
              .findAny();
          cacheValue = found.flatMap(Map.Entry::getValue);
          fieldLookUp.put(fieldName, cacheValue);
        }
        if (cacheValue.isPresent()) {
          recordWrapper.put(cacheValue.get(), cacheValue.get().reader.read(p));
        } else {
          gobbleValue(p);
        }
      });
      return recordWrapper.get();
    } else {
      gobbleValue(jacksonParser);
      return null;
    }
  }

  @Override
  public R readStrict(JsonParser jacksonParser) throws AnoaJacksonTypeException, IOException {
    switch (jacksonParser.getCurrentToken()) {
      case VALUE_NULL:
        return null;
      case START_OBJECT:
        final AvroRecordWrapper recordWrapper;
        try {
          recordWrapper = new AvroRecordWrapper<>(newInstance(), fieldWrappers);
        } catch (Exception e) {
          throw new AnoaJacksonTypeException(e);
        }
        doMap(jacksonParser, (fieldName, p) -> {
          final Optional cacheValue =
              fieldLookUp.computeIfAbsent(fieldName, __ -> Optional.empty());
          if (cacheValue.isPresent()) {
            recordWrapper.put(cacheValue.get(), cacheValue.get().reader.readStrict(p));
          } else {
            gobbleValue(p);
          }
        });
        return recordWrapper.get();
      default:
        throw new AnoaJacksonTypeException("Token is not '{': " + jacksonParser.getCurrentToken());
    }
  }

  static class GenericReader extends AvroReader {

    final Schema schema;

    GenericReader(Schema schema) {
      super(schema);
      this.schema = schema;
    }

    @Override
    protected GenericRecord newInstance() throws Exception {
      return new GenericData.Record(schema);
    }
  }

  static class SpecificReader extends AvroReader {

    final Constructor constructor;

    SpecificReader(Class recordClass) {
      super(SpecificData.get().getSchema(recordClass));
      try {
        this.constructor = recordClass.getDeclaredConstructor();
      } catch (NoSuchMethodException e) {
        throw new RuntimeException(e);
      }
    }

    @Override
    protected R newInstance() throws Exception {
      return constructor.newInstance();
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy