Created
October 18, 2024 06:40
-
-
Save amard33p/a6d170d6fd24e97965502d6b1a93c4ed to your computer and use it in GitHub Desktop.
Avro to Json Serialization and Deserialization Utility which shows field name in exception message
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.example.jsontoavro; | |
import org.apache.avro.AvroTypeException; | |
import org.apache.avro.Schema; | |
import org.apache.avro.generic.GenericRecord; | |
import org.apache.avro.io.DatumReader; | |
import org.apache.avro.io.DatumWriter; | |
import org.apache.avro.io.DecoderFactory; | |
import org.apache.avro.io.EncoderFactory; | |
import org.apache.avro.io.JsonDecoder; | |
import org.apache.avro.io.JsonEncoder; | |
import org.apache.avro.io.ResolvingDecoder; | |
import org.apache.avro.specific.SpecificDatumReader; | |
import org.apache.avro.specific.SpecificDatumWriter; | |
import org.apache.avro.specific.SpecificRecordBase; | |
import java.io.ByteArrayOutputStream; | |
import java.io.IOException; | |
public final class AvroUtil { | |
private AvroUtil() { | |
} | |
/*** | |
* Converts an Avro specific record to a JSON string. | |
* | |
* @param specificRecord The Avro specific record. | |
* @param <T> The type of the Avro specific record. It must be a subclass of SpecificRecordBase. | |
* @return A string with a JSON representation of the input. | |
*/ | |
public static <T extends SpecificRecordBase> String toJsonString(T specificRecord) { | |
try (ByteArrayOutputStream out = new ByteArrayOutputStream()) { | |
DatumWriter<T> writer = new SpecificDatumWriter<>(specificRecord.getSchema()); | |
JsonEncoder encoder = EncoderFactory.get().jsonEncoder(specificRecord.getSchema(), out, true); | |
writer.write(specificRecord, encoder); | |
encoder.flush(); | |
return out.toString(); | |
} catch (Exception e) { | |
throw new IllegalStateException("Failed to read SpecificRecordBase", e); | |
} | |
} | |
/*** | |
* Parses a JSON string and returns an Avro specific record, provided a schema. | |
* | |
* @param schema The Avro schema. | |
* @param json A JSON representation of the object. | |
* @return The Avro specific record. | |
*/ | |
public static GenericRecord parseFromJsonString(Schema schema, String json) throws IllegalStateException { | |
{ | |
try { | |
DatumReader<GenericRecord> reader = new CustomSpecificDatumReader<>(schema); | |
JsonDecoder decoder = DecoderFactory.get().jsonDecoder(schema, json); | |
return reader.read(null, decoder); | |
} catch (Exception e) { | |
throw new IllegalStateException("Failed to parse json.", e); | |
} | |
} | |
} | |
} | |
class CustomSpecificDatumReader<T> extends SpecificDatumReader<T> { | |
public CustomSpecificDatumReader(Schema schema) { | |
super(schema); | |
} | |
/* | |
* Shows the field name and the expected type in the exception message. | |
*/ | |
@Override | |
protected void readField(Object record, Schema.Field field, Object oldDatum, ResolvingDecoder in, Object state) throws IOException { | |
try { | |
super.readField(record, field, oldDatum, in, state); | |
} catch (AvroTypeException ex) { | |
throw new AvroTypeException("Error reading field '" + field.name() + "' of type " + field.schema().getType() + ": " + ex.getMessage()); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment