diff --git a/lang/c/src/value-json.c b/lang/c/src/value-json.c index 53c2b3d3e42..1d274d9cdf7 100644 --- a/lang/c/src/value-json.c +++ b/lang/c/src/value-json.c @@ -337,10 +337,12 @@ avro_value_to_json_t(const avro_value_t *value) case AVRO_UNION: { int disc; - avro_value_t branch; + avro_value_t branch; avro_schema_t union_schema; avro_schema_t branch_schema; - const char *branch_name; + const char *branch_name; + const char *namespace; + json_t *full_name_buf = NULL; check_return(NULL, avro_value_get_current_branch(value, &branch)); @@ -352,26 +354,40 @@ avro_value_to_json_t(const avro_value_t *value) union_schema = avro_value_get_schema(value); branch_schema = avro_schema_union_branch(union_schema, disc); + + namespace = avro_schema_namespace(branch_schema); branch_name = avro_schema_type_name(branch_schema); + if (namespace != NULL) { + full_name_buf = json_sprintf("%s.%s", namespace, branch_name); + if (full_name_buf == NULL) { + avro_set_error("Cannot allocate full name union"); + return NULL; + } + branch_name = json_string_value(full_name_buf); + } json_t *result = json_object(); if (result == NULL) { avro_set_error("Cannot allocate JSON union"); + json_decref(full_name_buf); return NULL; } json_t *branch_json = avro_value_to_json_t(&branch); if (branch_json == NULL) { json_decref(result); + json_decref(full_name_buf); return NULL; } if (json_object_set_new(result, branch_name, branch_json)) { avro_set_error("Cannot append branch to union"); json_decref(result); + json_decref(full_name_buf); return NULL; } + json_decref(full_name_buf); return result; } diff --git a/lang/c/tests/CMakeLists.txt b/lang/c/tests/CMakeLists.txt index 3200164770d..6420b335680 100644 --- a/lang/c/tests/CMakeLists.txt +++ b/lang/c/tests/CMakeLists.txt @@ -87,3 +87,4 @@ add_avro_test_checkmem(test_avro_1379) add_avro_test_checkmem(test_avro_1691) add_avro_test_checkmem(test_avro_1906) add_avro_test_checkmem(test_avro_1904) +add_avro_test_checkmem(test_avro_4135) diff --git a/lang/c/tests/test_avro_4135.c b/lang/c/tests/test_avro_4135.c new file mode 100755 index 00000000000..75d1cf15c39 --- /dev/null +++ b/lang/c/tests/test_avro_4135.c @@ -0,0 +1,111 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +#include +#include +#include + +#define check_exit(call) \ + do { \ + int __rc = call; \ + if (__rc != 0) { \ + fprintf(stderr, "Unexpected error:\n %s\n %s\n", \ + avro_strerror(), #call); \ + exit(EXIT_FAILURE); \ + } \ + } while (0) + +void check_json_encoding(const avro_value_t * val, const char * expected) { + char * actual; + + check_exit(avro_value_to_json(val, 1, &actual)); + if (strcmp(expected, actual) != 0) { + fprintf(stderr, "json encoding mismatch\n expected: %s\n actual: %s\n", expected, actual); + exit(EXIT_FAILURE); + } + free(actual); +} + +int main(int argc, char **argv) +{ + const char *json = + "{" + " \"type\": \"record\"," + " \"name\": \"r\"," + " \"fields\": [" + " { \"name\": \"field\", \"type\": [" + " \"null\"," + " \"int\"," + " {" + " \"type\": \"record\"," + " \"name\": \"r1\"," + " \"fields\": []" + " }," + " {" + " \"type\": \"record\"," + " \"name\": \"r2\"," + " \"namespace\": \"space\"," + " \"fields\": []" + " }" + " ]}" + " ]" + "}"; + + avro_schema_t schema = NULL; + avro_schema_error_t error; + + (void) argc; + (void) argv; + + check_exit(avro_schema_from_json(json, strlen(json), &schema, &error)); + + avro_value_iface_t *iface = avro_generic_class_from_schema(schema); + avro_value_t val; + check_exit(avro_generic_value_new(iface, &val)); + +#define TEST_AVRO_4135 (1) + #if TEST_AVRO_4135 + { + avro_value_t field; + avro_value_t branch; + char *json_encoding; + + avro_value_get_by_index(&val, 0, &field, NULL); + check_exit(avro_value_set_branch(&field, 0, &branch)); + avro_value_set_null(&branch); + check_json_encoding(&val, "{\"field\": null}"); + + check_exit(avro_value_set_branch(&field, 1, &branch)); + avro_value_set_int(&branch, 42); + check_exit(avro_value_to_json(&val, 1, &json_encoding)); + check_json_encoding(&val, "{\"field\": {\"int\": 42}}"); + + check_exit(avro_value_set_branch(&field, 2, &branch)); + check_exit(avro_value_to_json(&val, 1, &json_encoding)); + check_json_encoding(&val, "{\"field\": {\"r1\": {}}}"); + + check_exit(avro_value_set_branch(&field, 3, &branch)); + check_exit(avro_value_to_json(&val, 3, &json_encoding)); + free(json_encoding); + check_json_encoding(&val, "{\"field\": {\"space.r2\": {}}}"); + } + #endif + + avro_value_decref(&val); + avro_schema_decref(schema); + return 0; +}