question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Change ValueSerDes before sending into output topic

See original GitHub issue

Description

I want to customize ValueSerDes before sending Kafka stream to another output topic. But I am receiving error and not able to do so.

public class KafkaConsumer
    {
        private static IDictionary<string, List<PropDto>> availableAssets = new Dictionary<string, List<PropDto>>();
        public async Task ConsumerAsync()
        {
            try
            {
                string json1 = File.ReadAllText("abc.json");
                var assets = JsonConvert.DeserializeObject<List<AsDto>>(json1);


                foreach (var item in assets)
                {
                    availableAssets.Add(item.AssetIdentifier, (List<PropDto>)item.AssetProperties);
                }

                // Stream configuration
                var config = new StreamConfig();
                config.ApplicationId = "testing-acc4";
                config.BootstrapServers = "localhost:9092";
                config.DefaultKeySerDes = new StringSerDes();
                config.DefaultValueSerDes = new AssetDataDto();
                //config.DefaultValueSerDes = new AlertsDataDto();

                StreamBuilder builder = new StreamBuilder();

                IKStream<string, AssetDataDto> str = builder.Stream<string, AssetDataDto>("test-acc4");
                IKStream<string, AssetDataDto> str1 = str.Filter((k, v) => CheckFilterCriteria(v));
                IKStream<string, AlertsDataDto> str2 = str1.MapValues((k, v) => CheckFilter(v));
                str2.To("test-acc4-output");

                Topology t = builder.Build();

                // Create a stream instance with topology and configuration
                KafkaStream stream = new KafkaStream(t, config);

                //Subscribe CTRL + C to quit stream application
                Console.CancelKeyPress += (o, e) =>
                {
                    stream.Dispose();
                };

                await stream.StartAsync();
            }
            catch(Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
            

        }

        static double? min;
        static double? max;
        private static AlertsDataDto CheckFilter(AssetDataDto asset)
        {
            
            AlertsDataDto alertsData = new()
            {
                MinValue = min,
                MaxValue = max,
            };
            return alertsData;
        }

        private static bool CheckFilterCriteria(AssetDataDto asset)
        {
            if (availableAssets.ContainsKey(asset.Identifier))
            {
                foreach (var item in availableAssets[asset.Identifier])
                {
                    if (item.AssetPropertyIdentifier == asset.AssetPropertyIdentifier)
                    {
                        min = item.MinBoundryValue;
                        max = item.MaxBoundryValue;
                        return true;
                        
                    }
                }
            }
            return false;
        }
    }

This is my AssetDataDto class:

public class AssetDataDto : AbstractSerDes<AssetDataDto>
    {
        public string AssetIdentifier { get; set; }
        public string AssetPropertyIdentifier { get; set; }
        public double Value { get; set; }
        public DateTime TimeStamp { get; set; }


        public override AssetDataDto Deserialize(byte[] data, SerializationContext context)
        {
            var bytesAsString = Encoding.UTF8.GetString(data);
            return JsonConvert.DeserializeObject<AssetDataDto>(bytesAsString);
        }
        public override byte[] Serialize(AssetDataDto data, SerializationContext context)
        {
            var a = JsonConvert.SerializeObject(data);
            return Encoding.UTF8.GetBytes(a);
        }
    }

This is my AlertsDataDto class:

public class AlertsDataDto : AbstractSerDes<AlertsDataDto>
    {
        public double? MinValue { get; set; }
        public double? MaxValue { get; set; }
        
        public override AlertsDataDto Deserialize(byte[] data, SerializationContext context)
        {
            var bytesAsString = Encoding.UTF8.GetString(data);
            return JsonConvert.DeserializeObject<AlertsDataDto>(bytesAsString);
        }
        public override byte[] Serialize(AlertsDataDto data, SerializationContext context)
        {
            var a = JsonConvert.SerializeObject(data);
            return Encoding.UTF8.GetBytes(a);
        }
    }

This is the error: topic1

How to reproduce

Checklist

Please provide the following information:

  • A complete (i.e. we can run it), minimal program demonstrating the problem. No need to supply a project file.
  • A code snippet with your topology builder (ex: builder.Stream<string, string>(“topic”).to(“an-another-topic”)😉
  • Streamiz.Kafka.Net nuget version.
  • Apache Kafka version.
  • Client configuration.
  • Operating system.
  • Provide logs (with in debug mode (log4net and StreamConfig.Debug) as necessary in configuration).
  • Critical issue.

Issue Analytics

  • State:closed
  • Created 10 months ago
  • Comments:6 (2 by maintainers)

github_iconTop GitHub Comments

2reactions
duke-bartholomewcommented, Nov 18, 2022

Hi @Shikha4599 , @duke-bartholomew say right ! Btw, it’s highly recommended to split in two different classed DTO and DTO’s Serdes. Best regards,

Hi @LGouellec

Where exactly split is required?

Hi @Shikha4599 I think what @LGouellec means is to split your data and the serde logic in different classes. The Serialization/Deserialization logic is not bound to an instance of your data. It’s just functionality that can be used to operate on your data objects.

KafkaStreams will just instanciate an instance of the Serde class to use for deserializing/serializing objects of that specific type. It does not care about the data embedded in that object. In your case, you will also initialize whatever resources needed by the base Serdes class whenever you create one of your data objects, which is not something you really want.

So, long story short:

public class AssetDataDto {
        public string AssetIdentifier { get; set; }
        public string AssetPropertyIdentifier { get; set; }
        public double Value { get; set; }
        public DateTime TimeStamp { get; set; }
    }

and

public class AssetDataDtoSerde : AbstractSerDes<AssetDataDto>  {
        public override AssetDataDto Deserialize(byte[] data, SerializationContext context) {
            var bytesAsString = Encoding.UTF8.GetString(data);
            return JsonConvert.DeserializeObject<AssetDataDto>(bytesAsString);
        }
        public override byte[] Serialize(AssetDataDto data, SerializationContext context) {
            var a = JsonConvert.SerializeObject(data);
            return Encoding.UTF8.GetBytes(a);
        }
    }

Also keep in mind that Kafka serdes should also be able to cope with ‘null’ values (in some cases). Deleting a message from a log-compacted topic for instance is done by publishing a ‘null’ value on a specific key, so the serializer used for that should be able to handle ‘null’ values. But that’s also a bit up to how the serdes are used in your business logic and topology …

2reactions
duke-bartholomewcommented, Nov 18, 2022

Hi @Shikha4599 You configured your topology with default value serde: new AssetDataDto() In your pipeline you change from AssetDataDto to AlertsDataDto (in stream: str2) So I guess you need to explicitily define your serde in the To method (because it’s not defined so KStreams will try to use the default one, which is AssetDataDto and not AlertsDataDto

Try using: str2.To("test-acc4-output", new StringSerDes(), new AlertsDataDto())

Read more comments on GitHub >

github_iconTop Results From Across the Web

to modify message structure before sending it to kafka topics
1 Answer 1 ... It seems you are using Kafka Connect. For this case, "Single Message Transform" (SMT) are your friend. Those allows...
Read more >
Output Values - Configuration Language | Terraform
Output values are the return values of a Terraform module.
Read more >
Writing Functions
The function edit dialog allows the number of outputs to be changed. If there is more than one output, an array of messages...
Read more >
Pass by reference (C++ only)
The called function can modify the value of the argument by using its reference passed in. The following example shows how arguments are...
Read more >
Set the AWS CLI output format
As explained in the configuration topic, you can specify the output format in three ways: Using the output option in a named profile...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found