/** * Create a new BinaryMessageDecoder instance for this class that uses the specified {@link SchemaStore}. * @param resolver a {@link SchemaStore} used to find schemas by fingerprint */ public static BinaryMessageDecoder<ComplexPayloadAvro> createDecoder(SchemaStore resolver) { return new BinaryMessageDecoder<ComplexPayloadAvro>(MODEL$, SCHEMA$, resolver); }
/** Deserializes a User from a ByteBuffer. */ public static User fromByteBuffer( java.nio.ByteBuffer b) throws java.io.IOException { return DECODER.decode(b); }
/** * Creates a new {@link BinaryMessageEncoder} that uses the given * {@link GenericData data model} to construct datum instances described by * the {@link Schema schema}. * <p> * The {@code readSchema} is used as the expected schema (read schema). Datum * instances created by this class will are described by the expected schema. * <p> * The schema used to decode incoming buffers is determined by the schema * fingerprint encoded in the message header. This class can decode messages * that were encoded using the {@code readSchema}, other schemas that are * added using {@link #addSchema(Schema)}, or schemas returned by the * {@code resolver}. * * @param model the {@link GenericData data model} for datum instances * @param readSchema the {@link Schema} used to construct datum instances * @param resolver a {@link SchemaStore} used to find schemas by fingerprint */ public BinaryMessageDecoder(GenericData model, Schema readSchema, SchemaStore resolver) { this.model = model; this.readSchema = readSchema; this.resolver = resolver; addSchema(readSchema); }
@Test public void testCompatibleReadWithSchema() throws Exception { MessageEncoder<Record> v1Encoder = new BinaryMessageEncoder<>(GenericData.get(), SCHEMA_V1); BinaryMessageDecoder<Record> v2Decoder = new BinaryMessageDecoder<>(GenericData.get(), SCHEMA_V2); v2Decoder.addSchema(SCHEMA_V1); ByteBuffer v1Buffer = v1Encoder.encode(V1_RECORDS.get(3)); Record record = v2Decoder.decode(v1Buffer); Assert.assertEquals( V2_BUILDER.set("id", 6L).set("message", "m-6").clear("data").build(), record); }
@Test(expected = MissingSchemaException.class) public void testCompatibleReadFailsWithoutSchema() throws Exception { MessageEncoder<Record> v1Encoder = new BinaryMessageEncoder<>(GenericData.get(), SCHEMA_V1); BinaryMessageDecoder<Record> v2Decoder = new BinaryMessageDecoder<>(GenericData.get(), SCHEMA_V2); ByteBuffer v1Buffer = v1Encoder.encode(V1_RECORDS.get(3)); v2Decoder.decode(v1Buffer); }
@Override public D decode(InputStream stream, D reuse) throws IOException { byte[] header = HEADER_BUFFER.get(); try { if (!readFully(stream, header)) { throw new BadHeaderException("Not enough header bytes"); } } catch (IOException e) { throw new IOException("Failed to read header and fingerprint bytes", e); } if (BinaryMessageEncoder.V1_HEADER[0] != header[0] || BinaryMessageEncoder.V1_HEADER[1] != header[1]) { throw new BadHeaderException(String.format( "Unrecognized header bytes: 0x%02X 0x%02X", header[0], header[1])); } RawMessageDecoder<D> decoder = getDecoder(FP_BUFFER.get().getLong(2)); return decoder.decode(stream, reuse); }
@Test public void testSchemaEvolution() throws Exception { List<ByteBuffer> buffers = new ArrayList<>(); List<Record> records = new ArrayList<>(); records.addAll(V1_RECORDS); records.addAll(V2_RECORDS); MessageEncoder<Record> v1Encoder = new BinaryMessageEncoder<>(GenericData.get(), SCHEMA_V1); MessageEncoder<Record> v2Encoder = new BinaryMessageEncoder<>(GenericData.get(), SCHEMA_V2); for (Record record : records) { if (record.getSchema() == SCHEMA_V1) { buffers.add(v1Encoder.encode(record)); } else { buffers.add(v2Encoder.encode(record)); } } Set<Record> allAsV2 = new HashSet<>(V2_RECORDS); allAsV2.add(V2_BUILDER.set("id", 1L).set("message", "m-1").clear("data").build()); allAsV2.add(V2_BUILDER.set("id", 2L).set("message", "m-2").clear("data").build()); allAsV2.add(V2_BUILDER.set("id", 4L).set("message", "m-4").clear("data").build()); allAsV2.add(V2_BUILDER.set("id", 6L).set("message", "m-6").clear("data").build()); BinaryMessageDecoder<Record> v2Decoder = new BinaryMessageDecoder<>(GenericData.get(), SCHEMA_V2); v2Decoder.addSchema(SCHEMA_V1); Set<Record> decodedUsingV2 = new HashSet<>(); for (ByteBuffer buffer : buffers) { decodedUsingV2.add(v2Decoder.decode(buffer)); } Assert.assertEquals(allAsV2, decodedUsingV2); }
@Test public void testCompatibleReadWithSchemaFromLookup() throws Exception { MessageEncoder<Record> v1Encoder = new BinaryMessageEncoder<>(GenericData.get(), SCHEMA_V1); SchemaStore.Cache schemaCache = new SchemaStore.Cache(); schemaCache.addSchema(SCHEMA_V1); BinaryMessageDecoder<Record> v2Decoder = new BinaryMessageDecoder<>(GenericData.get(), SCHEMA_V2, schemaCache); ByteBuffer v1Buffer = v1Encoder.encode(V1_RECORDS.get(2)); Record record = v2Decoder.decode(v1Buffer); Assert.assertEquals( V2_BUILDER.set("id", 4L).set("message", "m-4").clear("data").build(), record); }
@Override public D decode(InputStream stream, D reuse) throws IOException { byte[] header = HEADER_BUFFER.get(); try { if (!readFully(stream, header)) { throw new BadHeaderException("Not enough header bytes"); } } catch (IOException e) { throw new IOException("Failed to read header and fingerprint bytes", e); } if (BinaryMessageEncoder.V1_HEADER[0] != header[0] || BinaryMessageEncoder.V1_HEADER[1] != header[1]) { throw new BadHeaderException(String.format( "Unrecognized header bytes: 0x%02X 0x%02X", header[0], header[1])); } RawMessageDecoder<D> decoder = getDecoder(FP_BUFFER.get().getLong(2)); return decoder.decode(stream, reuse); }
/** * Create a new BinaryMessageDecoder instance for this class that uses the specified {@link SchemaStore}. * @param resolver a {@link SchemaStore} used to find schemas by fingerprint */ public static BinaryMessageDecoder<User> createDecoder(SchemaStore resolver) { return new BinaryMessageDecoder<User>(MODEL$, SCHEMA$, resolver); }
/** Deserializes a ComplexPayloadAvro from a ByteBuffer. */ public static ComplexPayloadAvro fromByteBuffer( java.nio.ByteBuffer b) throws java.io.IOException { return DECODER.decode(b); }
/** * Creates a new {@link BinaryMessageEncoder} that uses the given * {@link GenericData data model} to construct datum instances described by * the {@link Schema schema}. * <p> * The {@code readSchema} is used as the expected schema (read schema). Datum * instances created by this class will are described by the expected schema. * <p> * The schema used to decode incoming buffers is determined by the schema * fingerprint encoded in the message header. This class can decode messages * that were encoded using the {@code readSchema}, other schemas that are * added using {@link #addSchema(Schema)}, or schemas returned by the * {@code resolver}. * * @param model the {@link GenericData data model} for datum instances * @param readSchema the {@link Schema} used to construct datum instances * @param resolver a {@link SchemaStore} used to find schemas by fingerprint */ public BinaryMessageDecoder(GenericData model, Schema readSchema, SchemaStore resolver) { this.model = model; this.readSchema = readSchema; this.resolver = resolver; addSchema(readSchema); }
/** * Create a new BinaryMessageDecoder instance for this class that uses the specified {@link SchemaStore}. * @param resolver a {@link SchemaStore} used to find schemas by fingerprint */ public static BinaryMessageDecoder<Address> createDecoder(SchemaStore resolver) { return new BinaryMessageDecoder<Address>(MODEL$, SCHEMA$, resolver); }
/** Deserializes a Address from a ByteBuffer. */ public static Address fromByteBuffer( java.nio.ByteBuffer b) throws java.io.IOException { return DECODER.decode(b); }
private RawMessageDecoder<D> getDecoder(long fp) { RawMessageDecoder<D> decoder = codecByFingerprint.get(fp); if (decoder != null) { return decoder; } if (resolver != null) { Schema writeSchema = resolver.findByFingerprint(fp); if (writeSchema != null) { addSchema(writeSchema); return codecByFingerprint.get(fp); } } throw new MissingSchemaException( "Cannot resolve schema for fingerprint: " + fp); }
/** * Create a new BinaryMessageDecoder instance for this class that uses the specified {@link SchemaStore}. * @param resolver a {@link SchemaStore} used to find schemas by fingerprint */ public static BinaryMessageDecoder<InnerPayLoadAvro> createDecoder(SchemaStore resolver) { return new BinaryMessageDecoder<InnerPayLoadAvro>(MODEL$, SCHEMA$, resolver); }
/** Deserializes a InnerPayLoadAvro from a ByteBuffer. */ public static InnerPayLoadAvro fromByteBuffer( java.nio.ByteBuffer b) throws java.io.IOException { return DECODER.decode(b); }
private RawMessageDecoder<D> getDecoder(long fp) { RawMessageDecoder<D> decoder = codecByFingerprint.get(fp); if (decoder != null) { return decoder; } if (resolver != null) { Schema writeSchema = resolver.findByFingerprint(fp); if (writeSchema != null) { addSchema(writeSchema); return codecByFingerprint.get(fp); } } throw new MissingSchemaException( "Cannot resolve schema for fingerprint: " + fp); }
/** * Create a new BinaryMessageDecoder instance for this class that uses the specified {@link SchemaStore}. * @param resolver a {@link SchemaStore} used to find schemas by fingerprint */ public static BinaryMessageDecoder<Address> createDecoder(SchemaStore resolver) { return new BinaryMessageDecoder<Address>(MODEL$, SCHEMA$, resolver); }
/** Deserializes a DifferentSchemaRecord from a ByteBuffer. */ public static DifferentSchemaRecord fromByteBuffer( java.nio.ByteBuffer b) throws java.io.IOException { return DECODER.decode(b); }