Query/Question
How can I serialize EventGridEvent to json, and then back? Please see the sample code that's failing as follows - I think I'm not intended to be doing what I'm doing?
Unrecognized field "topic" (class com.microsoft.azure.eventgrid.models.EventGridEvent), not marked as ignorable (0 known properties: ])
It seems like EventGridEvent has the right annotations, though?
Setup (please complete the following information if applicable):
I am trying to take the raw objects out of the event log, write them to an on premise kafka queue, then read them out of the on premise kafka queue with on premise workers. The reason these things are in an on premise setup is for security compliance demands.
Deserializer snippet:
private static final ObjectMapper objectMapper = new ObjectMapper();
@Override
public EventGridEvent deserialize(byte[] message) throws IOException {
return objectMapper.readValue(message, EventGridEvent.class);
}
Test snippet:
// SAMPLE EVENT: https://docs.microsoft.com/en-us/azure/event-grid/event-schema
byte[] sampleEvent = getClass().getClassLoader().getResourceAsStream("sampleEvent.json").readAllBytes();
System.out.println(new String(sampleEvent));
EventGridEvent event = deserializationSchema.deserialize(sampleEvent);
System.out.println(event.id());
Information Checklist
Kindly make sure that you have added all the following information above and checkoff the required fields otherwise we will treat the issuer as an incomplete report
Thanks for filing this issue @bytesandwich. @bsiegel could you please follow up on this track-1 inquiry?
Wow quick response! You guys are very on top of your project! I'm impressed @joshfree & @bsiegel :)
Hi @bytesandwich - one thing that stands out is that the sample event is actually a JSON list - because it's a list of events (containing a single event), it would need to be deserialized as an EventGridEvent[].
That said, the recommended way to achieve what you're asking about is to use the EventGridSubscriber class:
import com.microsoft.azure.eventgrid.customization.EventGridSubscriber;
import com.microsoft.azure.eventgrid.models.EventGridEvent;
// SAMPLE EVENT: https://docs.microsoft.com/en-us/azure/event-grid/event-schema
byte[] sampleEvent = getClass().getClassLoader().getResourceAsStream("sampleEvent.json").readAllBytes();
String eventJson = new String(sampleEvent);
System.out.println(eventJson);
EventGridSubscriber subscriber = new EventGridSubscriber();
EventGridEvent[] eventList = subscriber.deserializeEventGridEvents(eventJson);
System.out.println(eventList[0].id());
Tne EventGridSubscriber is preconfigured with mappings for all of the system events included in the library (those with models under com.microsoft.azure.eventgrid.models) so that for your sample event, you can also access the contained data as a strongly-typed model object:
System.out.println(eventList[0].data().getClass().toString());
// Prints "class com.microsoft.azure.eventgrid.models.StorageBlobCreatedEventData"
StorageBlobCreatedEventData eventData = (StorageBlobCreatedEventData) eventList[0].data();
System.out.println(eventData.blobType()); // Prints "BlockBlob"
If the event contains user-supplied data, you can register your own mapping between the value of the "eventType" field and your model class that you want to deserialize:
...
import com.mycompany.myapp.SomeCustomEvent;
...
EventGridSubscriber subscriber = new EventGridSubscriber();
subscriber.putCustomEventMapping("MyCompany.MyApp.SomeCustomEvent", SomeCustomEvent.class);
EventGridEvent[] eventList = subscriber.deserializeEventGridEvents(eventJson);
System.out.println(eventList[0].data().getClass().toString());
// Prints "class com.mycompany.myapp.SomeCustomEvent"
Perfect for deserialization, thank you! I appreciate the forward looking advice about mappings 馃憤
Is it possible to similarly serialize an event (or EventGridEvent[]) to json?
Yes, you could simply serialize the EventGridEvent object (or list of EventGridEvent objects) using the default ObjectMapper (assuming you're using Jackson):
import com.fasterxml.jackson.databind.ObjectMapper;
...
EventGridEvent event = eventList[0];
// Passing the whole eventList instead of a single event also works, it will be serialized as a JSON array
ObjectMapper mapper = new ObjectMapper();
String serialized = mapper.writeValueAsString(event);
System.out.println(serialized);
However the serialized value will not be exactly the same as the one the EventGridClient produces - the serializer used by the client has a variety of modules registered that change how certain data types (e.g. Joda DateTime) are serialized. If you want to ensure that the object will be serialized identically to how the EventGridClient would serialize it, use the JacksonAdapter included in the client runtime:
import com.microsoft.rest.serializer.JacksonAdapter;
...
EventGridEvent event = eventList[0];
JacksonAdapter adapter = new JacksonAdapter();
String serialized = adapter.serialize(event);
// or access `adapter.serializer() if you need to get an ObjectMapper instance e.g. for customization
System.out.println(serialized);
Or if you already have an EventGridClient instance, you can access its serializer as follows:
```java
import com.microsoft.azure.eventgrid.EventGridClient;
import com.microsoft.azure.eventgrid.TopicCredentials;
import com.microsoft.azure.eventgrid.implementation.EventGridClientImpl;
...
EventGridEvent event = eventList[0];
TopicCredentials credentials = ...; // Could also be DomainCredentials or any other ServiceClientCredentials
EventGridClient client = new EventGridClientImpl(credentials);
String serialized = client.restClient().serializerAdapter().serialize(event);
System.out.println(serialized);
Cool I can verify that the JacksonAdaptor works. I'm very happy with those answers to my query! Please feel free to close the ticket.