Skip to content

Commit 2553f41

Browse files
connieysrnagar
andauthored
Adds common exception for serialization related failures (Azure#28093)
* Add SchemaRegistryAvroException. * Update serialization to throw AvroSerializationException. * Update CHANGELOG. * Updating exceptions to be thrown during serialization. Add documentation. * Updating documentation for exceptions. * Adding code snippets. * Adding code snippets. * Rename exception. * Rename helper method to deserialize. * Update sdk/schemaregistry/azure-data-schemaregistry-apacheavro/CHANGELOG.md Co-authored-by: Srikanta <[email protected]>
1 parent f08c7b8 commit 2553f41

File tree

10 files changed

+463
-81
lines changed

10 files changed

+463
-81
lines changed

sdk/schemaregistry/azure-data-schemaregistry-apacheavro/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,10 @@
77
### Breaking Changes
88

99
### Bugs Fixed
10+
1011
- Fixed a bug that caused deserialize operation to throw `SchemaParseException` when multiple messages with same schema
1112
were deserialized (https://github.com/Azure/azure-sdk-for-java/issues/27602).
13+
- Wrap Apache Avro exceptions with new exception type, `SchemaRegistryApacheAvroException`.
1214

1315
### Other Changes
1416

sdk/schemaregistry/azure-data-schemaregistry-apacheavro/README.md

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -28,17 +28,16 @@ and deserialization.
2828
```
2929
[//]: # ({x-version-update-end})
3030

31-
### Create `SchemaRegistryAvroSerializer` instance
31+
### Create `SchemaRegistryApacheAvroSerializer` instance
3232

33-
The `SchemaRegistryAvroSerializer` instance is the main class that provides APIs for serializing and
33+
The `SchemaRegistryApacheAvroSerializer` instance is the main class that provides APIs for serializing and
3434
deserializing avro data format. The avro schema is stored and retrieved from the Schema Registry service
3535
through the `SchemaRegistryAsyncClient`. So, before we create the serializer, we should create the client.
3636

3737
#### Create `SchemaRegistryAsyncClient` with Azure Active Directory Credential
3838

3939
In order to interact with the Azure Schema Registry service, you'll need to create an instance of the
40-
`SchemaRegistryAsyncClient` class through the `SchemaRegistryClientBuilder`. You will need an **endpoint** and an
41-
**API key** to instantiate a client object.
40+
`SchemaRegistryAsyncClient` class through the `SchemaRegistryClientBuilder`. You will need the Schema Registry **endpoint**.
4241

4342
You can authenticate with Azure Active Directory using the [Azure Identity library][azure_identity]. Note that regional
4443
endpoints do not support AAD authentication. Create a [custom subdomain][custom_subdomain] for your resource in order to
@@ -81,22 +80,13 @@ SchemaRegistryApacheAvroSerializer serializer = new SchemaRegistryApacheAvroSeri
8180

8281
## Key concepts
8382

84-
### ObjectSerializer
85-
This library provides a serializer, `SchemaRegistryAvroSerializer`, that implements the `ObjectSerializer` interface.
86-
This allows a developer to use this serializer in any Java Azure SDKs that utilize `ObjectSerializer`. The
83+
This library provides a serializer, `SchemaRegistryApacheAvroSerializer`. The
8784
`SchemaRegistryAvroSerializer` utilizes a `SchemaRegistryAsyncClient` to construct messages using a wire format
8885
containing schema information such as a schema ID.
8986

9087
This serializer requires the Apache Avro library. The payload types accepted by this serializer include
9188
[GenericRecord][generic_record] and [SpecificRecord][specific_record].
9289

93-
### Wire Format
94-
The serializer in this library creates messages in a wire format. The format is the following:
95-
96-
- Bytes [0-3] – record format indicator – currently is \x00\x00\x00\x00
97-
- Bytes [4-35] – UTF-8 GUID, identifying the schema in a Schema Registry instance
98-
- Bytes [36-end] – serialized payload bytes
99-
10090
## Examples
10191

10292
* [Serialize](#serialize)

sdk/schemaregistry/azure-data-schemaregistry-apacheavro/src/main/java/com/azure/data/schemaregistry/apacheavro/AvroSerializer.java

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323

2424
import java.io.ByteArrayOutputStream;
2525
import java.io.IOException;
26-
import java.io.UncheckedIOException;
2726
import java.lang.reflect.Constructor;
2827
import java.lang.reflect.InvocationTargetException;
2928
import java.nio.ByteBuffer;
@@ -134,14 +133,15 @@ Schema parseSchemaString(String schemaString) {
134133
* Returns A byte[] containing Avro encoding of object parameter.
135134
*
136135
* @param object Object to be encoded into byte stream
136+
* @param schemaId Identifier of the schema trying to be encoded.
137137
*
138138
* @return A set of bytes that represent the object.
139139
*
140140
* @throws IllegalArgumentException If the object is not a serializable type.
141141
* @throws IllegalStateException if the object could not be serialized to an object stream or there was a
142142
* runtime exception during serialization.
143143
*/
144-
<T> byte[] encode(T object) {
144+
<T> byte[] serialize(T object, String schemaId) {
145145
final Schema schema = getSchema(object);
146146

147147
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
@@ -162,7 +162,8 @@ <T> byte[] encode(T object) {
162162
return outputStream.toByteArray();
163163
} catch (IOException | RuntimeException e) {
164164
// Avro serialization can throw AvroRuntimeException, NullPointerException, ClassCastException, etc
165-
throw logger.logExceptionAsError(new IllegalStateException("Error serializing Avro message", e));
165+
throw logger.logExceptionAsError(new SchemaRegistryApacheAvroException(
166+
"An error occurred while attempting to serialize to Avro.", e, schemaId));
166167
}
167168
}
168169

@@ -172,7 +173,7 @@ <T> byte[] encode(T object) {
172173
*
173174
* @return deserialized object
174175
*/
175-
<T> T decode(ByteBuffer contents, byte[] schemaBytes, TypeReference<T> typeReference) {
176+
<T> T deserialize(ByteBuffer contents, byte[] schemaBytes, TypeReference<T> typeReference) {
176177
Objects.requireNonNull(contents, "'bytes' must not be null.");
177178
Objects.requireNonNull(schemaBytes, "'schemaBytes' must not be null.");
178179

@@ -185,7 +186,7 @@ <T> T decode(ByteBuffer contents, byte[] schemaBytes, TypeReference<T> typeRefer
185186
try {
186187
return messageDecoder.decode(contents);
187188
} catch (IOException e) {
188-
throw logger.logExceptionAsError(new UncheckedIOException(
189+
throw logger.logExceptionAsError(new SchemaRegistryApacheAvroException(
189190
"Unable to deserialize Avro schema object using binary message decoder.", e));
190191
}
191192
} else {
@@ -196,7 +197,8 @@ <T> T decode(ByteBuffer contents, byte[] schemaBytes, TypeReference<T> typeRefer
196197
return reader.read(null, decoderFactory.binaryDecoder(input, null));
197198
}
198199
} catch (IOException | RuntimeException e) {
199-
throw logger.logExceptionAsError(new IllegalStateException("Error deserializing raw Avro message.", e));
200+
throw logger.logExceptionAsError(new SchemaRegistryApacheAvroException(
201+
"Error deserializing raw Avro message.", e));
200202
}
201203
}
202204
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
package com.azure.data.schemaregistry.apacheavro;
5+
6+
import com.azure.core.exception.AzureException;
7+
8+
/**
9+
* Represents an exception that is thrown when Avro serialization or deserialization fails.
10+
*/
11+
public class SchemaRegistryApacheAvroException extends AzureException {
12+
private final String schemaId;
13+
14+
/**
15+
* Initializes a new instance.
16+
*
17+
* @param message The exception message.
18+
*/
19+
public SchemaRegistryApacheAvroException(String message) {
20+
super(message);
21+
22+
this.schemaId = null;
23+
}
24+
25+
/**
26+
* Initializes a new instance.
27+
*
28+
* @param message The exception message.
29+
* @param cause The {@link Throwable} which caused the creation of this exception.
30+
*/
31+
public SchemaRegistryApacheAvroException(String message, Throwable cause) {
32+
super(message, cause);
33+
34+
this.schemaId = null;
35+
}
36+
37+
/**
38+
* Initializes a new instance.
39+
*
40+
* @param message The exception message.
41+
* @param cause The {@link Throwable} which caused the creation of this exception.
42+
* @param enableSuppression Whether suppression is enabled or disabled.
43+
* @param writableStackTrace Whether the exception stack trace will be filled in.
44+
*/
45+
public SchemaRegistryApacheAvroException(String message, Throwable cause, boolean enableSuppression,
46+
boolean writableStackTrace) {
47+
super(message, cause, enableSuppression, writableStackTrace);
48+
49+
this.schemaId = null;
50+
}
51+
52+
/**
53+
* Initializes a new instance.
54+
*
55+
* @param message The exception message.
56+
* @param cause The {@link Throwable} which caused the creation of this exception.
57+
* @param schemaId The id of the schema being processed when this exception occurred. {@code null} if there was
58+
* none.
59+
*/
60+
public SchemaRegistryApacheAvroException(String message, Throwable cause, String schemaId) {
61+
super(message, cause);
62+
this.schemaId = schemaId;
63+
}
64+
65+
/**
66+
* Gets the schema id that was associated with this exception.
67+
*
68+
* @return The schema id associated with teh exception. {@code null} if there was no schema id.
69+
*/
70+
public String getSchemaId() {
71+
return schemaId;
72+
}
73+
}

0 commit comments

Comments
 (0)