Skip to content

Commit 8e86df1

Browse files
authored
Fix fingerprint method for null default values (#733)
* Fix default toString for JsonProperties.NULL_VALUE The normalization of the Schema is inconsistent across restarts due to object's JsonProperties.NULL_VALUE lack of override toString. This fixes that and allows deterministic creation for fingerprints. * Assert that fingerprint hash remains the same across executions Added test case to assess that generated fingerprint is always the same between multiple executions, to prevent using an invalid stringified version of Object. Same Schema string must return same fingerprint, at least as long as normalize function is not changed. Forced MD5, just in case in future releases, the default hashing algorithm changes.
1 parent 15d9cd9 commit 8e86df1

File tree

2 files changed

+50
-1
lines changed

2 files changed

+50
-1
lines changed

schema-registry/common/src/main/java/com/hortonworks/registries/schemaregistry/avro/AvroSchemaProvider.java

+6-1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import com.hortonworks.registries.schemaregistry.SchemaFieldInfo;
2323
import com.hortonworks.registries.schemaregistry.errors.InvalidSchemaException;
2424
import com.hortonworks.registries.schemaregistry.errors.SchemaNotFoundException;
25+
import org.apache.avro.JsonProperties;
2526
import org.apache.avro.Schema;
2627

2728
import java.io.IOException;
@@ -180,7 +181,11 @@ private static Appendable build(Map<String, String> env,
180181
// handle default value
181182
Object defaultValue = field.defaultVal();
182183
if (defaultValue != null) {
183-
appendable.append(defaultValue.toString());
184+
if (defaultValue == JsonProperties.NULL_VALUE) {
185+
appendable.append("null");
186+
} else {
187+
appendable.append(defaultValue.toString());
188+
}
184189
}
185190

186191
build(env, field.schema(), appendable).append("}");
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package com.hortonworks.registries.schemaregistry.avro;
2+
3+
import com.hortonworks.registries.schemaregistry.SchemaProvider;
4+
import org.junit.Assert;
5+
import org.junit.Test;
6+
7+
import java.util.Collections;
8+
9+
import static org.hamcrest.core.IsEqual.equalTo;
10+
11+
public class AvroSchemaProviderTest {
12+
13+
private String schemaWithNullDefaults = "{\n" +
14+
" \"type\" : \"record\",\n" +
15+
" \"namespace\" : \"com.hortonworks.registries\",\n" +
16+
" \"name\" : \"trucks\",\n" +
17+
" \"fields\" : [\n" +
18+
" { \"name\" : \"driverId\" , \"type\" : [\"null\", \"int\"], \"default\": null }" +
19+
" ]\n" +
20+
"}\n";
21+
22+
@Test
23+
public void testGetFingerprintNullTypeDeterminism() throws Exception {
24+
AvroSchemaProvider avroSchemaProvider = new AvroSchemaProvider();
25+
avroSchemaProvider.init(Collections.singletonMap(SchemaProvider.HASH_FUNCTION_CONFIG, "MD5"));
26+
27+
String withNullDefaultsFingerprintHex = bytesToHex(avroSchemaProvider.getFingerprint(schemaWithNullDefaults));
28+
29+
Assert.assertThat(withNullDefaultsFingerprintHex, equalTo("e1e17a3aef8c728c131204bbf49046b2"));
30+
}
31+
32+
private static String bytesToHex(byte[] hash) {
33+
StringBuilder hexString = new StringBuilder();
34+
for (byte b : hash) {
35+
String hex = Integer.toHexString(0xff & b);
36+
if (hex.length() == 1) {
37+
hexString.append('0');
38+
}
39+
hexString.append(hex);
40+
}
41+
return hexString.toString();
42+
}
43+
44+
}

0 commit comments

Comments
 (0)