diff --git a/avro/src/main/java/com/fasterxml/jackson/dataformat/avro/schema/AvroSchemaHelper.java b/avro/src/main/java/com/fasterxml/jackson/dataformat/avro/schema/AvroSchemaHelper.java index 99aa79937..2916e8671 100644 --- a/avro/src/main/java/com/fasterxml/jackson/dataformat/avro/schema/AvroSchemaHelper.java +++ b/avro/src/main/java/com/fasterxml/jackson/dataformat/avro/schema/AvroSchemaHelper.java @@ -10,6 +10,7 @@ import org.apache.avro.JsonProperties; import org.apache.avro.Schema; import org.apache.avro.Schema.Parser; +import org.apache.avro.SchemaParseException; import org.apache.avro.reflect.AvroAlias; import org.apache.avro.reflect.Stringable; import org.apache.avro.specific.SpecificData; @@ -269,13 +270,27 @@ public static Schema parseJsonSchema(String json) { * @param values List of enum names * @return An {@link org.apache.avro.Schema.Type#ENUM ENUM} schema. */ - public static Schema createEnumSchema(BeanDescription bean, List values) { + public static Schema createEnumSchema(BeanDescription bean, List values) + { final JavaType enumType = bean.getType(); - return addAlias(Schema.createEnum( - getName(enumType), - bean.findClassDescription(), - getNamespace(enumType, bean.getClassInfo()), values - ), bean); + final Schema avroSchema; + + try { + avroSchema = Schema.createEnum( + getName(enumType), + bean.findClassDescription(), + getNamespace(enumType, bean.getClassInfo()), + values); + } catch (SchemaParseException spe) { + final String msg = String.format("Problem generating Avro `Schema` for Enum type %s: %s", + ClassUtil.getTypeDescription(enumType), spe.getMessage()); + + // 05-Jan-2025, tatu: SHOULD be able to throw like so but + // `SchemaBuilder` does not expose checked exceptions so need to + // throw InvalidDefinitionException.from((JsonParser) null, msg); + throw new IllegalArgumentException(msg, spe); + } + return addAlias(avroSchema, bean); } /** diff --git a/avro/src/main/java/com/fasterxml/jackson/dataformat/avro/schema/EnumVisitor.java b/avro/src/main/java/com/fasterxml/jackson/dataformat/avro/schema/EnumVisitor.java index 20f61e163..438fab57d 100644 --- a/avro/src/main/java/com/fasterxml/jackson/dataformat/avro/schema/EnumVisitor.java +++ b/avro/src/main/java/com/fasterxml/jackson/dataformat/avro/schema/EnumVisitor.java @@ -1,5 +1,8 @@ package com.fasterxml.jackson.dataformat.avro.schema; +import java.util.ArrayList; +import java.util.Set; + import com.fasterxml.jackson.databind.BeanDescription; import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.SerializerProvider; @@ -7,9 +10,6 @@ import org.apache.avro.Schema; -import java.util.ArrayList; -import java.util.Set; - /** * Specific visitor for Java Enum types that are to be exposed as * Avro Enums. Used unless Java Enums are to be mapped to Avro Strings. diff --git a/avro/src/test/java/com/fasterxml/jackson/dataformat/avro/schema/EnumSchema422Test.java b/avro/src/test/java/com/fasterxml/jackson/dataformat/avro/schema/EnumSchema422Test.java new file mode 100644 index 000000000..31aad6d22 --- /dev/null +++ b/avro/src/test/java/com/fasterxml/jackson/dataformat/avro/schema/EnumSchema422Test.java @@ -0,0 +1,60 @@ +package com.fasterxml.jackson.dataformat.avro.schema; + +import org.junit.Test; + +import com.fasterxml.jackson.annotation.JsonValue; + +import com.fasterxml.jackson.dataformat.avro.AvroMapper; +import com.fasterxml.jackson.dataformat.avro.AvroTestBase; + +// For [dataformats-binary#422] +public class EnumSchema422Test extends AvroTestBase +{ + enum EnumType422 { + CARD_S("CARD-S"); + + private final String value; + + EnumType422(String value) { + this.value = value; + } + + @JsonValue + public String value() { + return this.value; + } + } + + static class Wrapper422 { + public EnumType422 contract; + } + + private final AvroMapper MAPPER = newMapper(); + + // For [dataformats-binary#422] + @Test + public void testEnumSchemaGeneration422() throws Exception + { + // First, failure due to invalid enum value (when generating as Enum) + AvroSchemaGenerator gen = new AvroSchemaGenerator() + .enableLogicalTypes(); + try { + MAPPER.acceptJsonFormatVisitor(Wrapper422.class, gen); + fail("Expected failure"); + } catch (IllegalArgumentException e) { // in 2.x + verifyException(e, "Problem generating Avro `Schema` for Enum type"); + verifyException(e, "Illegal character in"); + } + + // But then success when configuring to produce Strings for Enum types + + gen = new AvroSchemaGenerator() + .enableLogicalTypes() + .enableWriteEnumAsString(); + MAPPER.acceptJsonFormatVisitor(Wrapper422.class, gen); + + org.apache.avro.Schema avroSchema = gen.getGeneratedSchema().getAvroSchema(); + String avroSchemaInJSON = avroSchema.toString(true); + assertNotNull(avroSchemaInJSON); + } +} diff --git a/avro/src/test/java/com/fasterxml/jackson/dataformat/avro/schema/Enum_schemaCreationTest.java b/avro/src/test/java/com/fasterxml/jackson/dataformat/avro/schema/Enum_schemaCreationTest.java index 2a0dde6ba..7f23bf319 100644 --- a/avro/src/test/java/com/fasterxml/jackson/dataformat/avro/schema/Enum_schemaCreationTest.java +++ b/avro/src/test/java/com/fasterxml/jackson/dataformat/avro/schema/Enum_schemaCreationTest.java @@ -10,8 +10,8 @@ import org.apache.avro.specific.SpecificData; import org.junit.Test; -public class Enum_schemaCreationTest extends AvroTestBase { - +public class Enum_schemaCreationTest extends AvroTestBase +{ static enum NumbersEnum { ONE, TWO, THREE } diff --git a/release-notes/VERSION-2.x b/release-notes/VERSION-2.x index 8f770bcc2..8bdf46c01 100644 --- a/release-notes/VERSION-2.x +++ b/release-notes/VERSION-2.x @@ -19,6 +19,8 @@ Active maintainers: #308: (avro) Incorrect serialization for `LogicalType.Decimal` (Java `BigDecimal`) (reported by Idan S) (fix contributed by Michal F) +#422: Avro generation failed with enums containing values with special characters + (reported by @pfr-enedis) #535: (avro) AvroSchemaGenerator: logicalType(s) never set for non-date classes (reported by Cormac R) (fix contributed by Michal F)