github.com/confluentinc/confluent-kafka-go@v1.9.2/schemaregistry/serde/avro/avro_specific.go (about)

     1  /**
     2   * Copyright 2022 Confluent Inc.
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   * http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package avro
    18  
    19  import (
    20  	"bytes"
    21  	"fmt"
    22  	"io"
    23  
    24  	"github.com/actgardner/gogen-avro/v10/compiler"
    25  	"github.com/actgardner/gogen-avro/v10/parser"
    26  	"github.com/actgardner/gogen-avro/v10/schema"
    27  	"github.com/actgardner/gogen-avro/v10/vm"
    28  	"github.com/actgardner/gogen-avro/v10/vm/types"
    29  	"github.com/confluentinc/confluent-kafka-go/schemaregistry"
    30  	"github.com/confluentinc/confluent-kafka-go/schemaregistry/serde"
    31  )
    32  
    33  // SpecificSerializer represents a specific Avro serializer
    34  type SpecificSerializer struct {
    35  	serde.BaseSerializer
    36  }
    37  
    38  // SpecificDeserializer represents a specific Avro deserializer
    39  type SpecificDeserializer struct {
    40  	serde.BaseDeserializer
    41  }
    42  
    43  var _ serde.Serializer = new(SpecificSerializer)
    44  var _ serde.Deserializer = new(SpecificDeserializer)
    45  
    46  // SpecificAvroMessage represents a generated Avro class from gogen-avro
    47  type SpecificAvroMessage interface {
    48  	types.Field
    49  	Serialize(w io.Writer) error
    50  	Schema() string
    51  }
    52  
    53  // NewSpecificSerializer creates an Avro serializer for Avro-generated objects
    54  func NewSpecificSerializer(client schemaregistry.Client, serdeType serde.Type, conf *SerializerConfig) (*SpecificSerializer, error) {
    55  	s := &SpecificSerializer{}
    56  	err := s.ConfigureSerializer(client, serdeType, &conf.SerializerConfig)
    57  	if err != nil {
    58  		return nil, err
    59  	}
    60  	return s, nil
    61  }
    62  
    63  // Serialize implements serialization of specific Avro data
    64  func (s *SpecificSerializer) Serialize(topic string, msg interface{}) ([]byte, error) {
    65  	if msg == nil {
    66  		return nil, nil
    67  	}
    68  	var avroMsg SpecificAvroMessage
    69  	switch t := msg.(type) {
    70  	case SpecificAvroMessage:
    71  		avroMsg = t
    72  	default:
    73  		return nil, fmt.Errorf("serialization target must be an avro message. Got '%v'", t)
    74  	}
    75  	var id = 0
    76  	info := schemaregistry.SchemaInfo{
    77  		Schema: avroMsg.Schema(),
    78  	}
    79  	id, err := s.GetID(topic, avroMsg, info)
    80  	if err != nil {
    81  		return nil, err
    82  	}
    83  	var buf bytes.Buffer
    84  	err = avroMsg.Serialize(&buf)
    85  	if err != nil {
    86  		return nil, err
    87  	}
    88  	payload, err := s.WriteBytes(id, buf.Bytes())
    89  	if err != nil {
    90  		return nil, err
    91  	}
    92  	return payload, nil
    93  }
    94  
    95  // NewSpecificDeserializer creates an Avro deserializer for Avro-generated objects
    96  func NewSpecificDeserializer(client schemaregistry.Client, serdeType serde.Type, conf *DeserializerConfig) (*SpecificDeserializer, error) {
    97  	s := &SpecificDeserializer{}
    98  	err := s.ConfigureDeserializer(client, serdeType, &conf.DeserializerConfig)
    99  	if err != nil {
   100  		return nil, err
   101  	}
   102  	return s, nil
   103  }
   104  
   105  // Deserialize implements deserialization of specific Avro data
   106  func (s *SpecificDeserializer) Deserialize(topic string, payload []byte) (interface{}, error) {
   107  	if payload == nil {
   108  		return nil, nil
   109  	}
   110  	info, err := s.GetSchema(topic, payload)
   111  	if err != nil {
   112  		return nil, err
   113  	}
   114  	writer, err := s.toAvroType(info)
   115  	if err != nil {
   116  		return nil, err
   117  	}
   118  	subject, err := s.SubjectNameStrategy(topic, s.SerdeType, info)
   119  	if err != nil {
   120  		return nil, err
   121  	}
   122  	msg, err := s.MessageFactory(subject, writer.Name())
   123  	if err != nil {
   124  		return nil, err
   125  	}
   126  	var avroMsg SpecificAvroMessage
   127  	switch t := msg.(type) {
   128  	case SpecificAvroMessage:
   129  		avroMsg = t
   130  	default:
   131  		return nil, fmt.Errorf("deserialization target must be an avro message. Got '%v'", t)
   132  	}
   133  	reader, err := s.toAvroType(schemaregistry.SchemaInfo{Schema: avroMsg.Schema()})
   134  	if err != nil {
   135  		return nil, err
   136  	}
   137  	deser, err := compiler.Compile(writer, reader)
   138  	if err != nil {
   139  		return nil, err
   140  	}
   141  	r := bytes.NewReader(payload[5:])
   142  	return vm.Eval(r, deser, avroMsg), nil
   143  }
   144  
   145  // DeserializeInto implements deserialization of specific Avro data to the given object
   146  func (s *SpecificDeserializer) DeserializeInto(topic string, payload []byte, msg interface{}) error {
   147  	if payload == nil {
   148  		return nil
   149  	}
   150  	var avroMsg SpecificAvroMessage
   151  	switch t := msg.(type) {
   152  	case SpecificAvroMessage:
   153  		avroMsg = t
   154  	default:
   155  		return fmt.Errorf("serialization target must be an avro message. Got '%v'", t)
   156  	}
   157  	info, err := s.GetSchema(topic, payload)
   158  	if err != nil {
   159  		return err
   160  	}
   161  	writer, err := s.toAvroType(info)
   162  	if err != nil {
   163  		return err
   164  	}
   165  	reader, err := s.toAvroType(schemaregistry.SchemaInfo{Schema: avroMsg.Schema()})
   166  	if err != nil {
   167  		return err
   168  	}
   169  	deser, err := compiler.Compile(writer, reader)
   170  	if err != nil {
   171  		return err
   172  	}
   173  	r := bytes.NewReader(payload[5:])
   174  	return vm.Eval(r, deser, avroMsg)
   175  }
   176  
   177  func (s *SpecificDeserializer) toAvroType(schema schemaregistry.SchemaInfo) (schema.AvroType, error) {
   178  	ns := parser.NewNamespace(false)
   179  	return resolveAvroReferences(s.Client, schema, ns)
   180  }