Open idkw opened 4 years ago
The issue seems to arise when using the avro dependency >= 1.9.x due to this change : https://issues.apache.org/jira/browse/AVRO-2369
The 1.9.x avro dependency in its Field constructor does this weird check instead of checking for NullNode directly:
public Field(String name, Schema schema, String doc, Object defaultValue) {
this(name, schema, doc,
defaultValue == NULL_DEFAULT_VALUE ? NullNode.getInstance() : JacksonUtils.toJsonNode(defaultValue), true,
Order.ASCENDING);
}
However the NULL_DEFAULT_VALUE field is just defined as Object NULL_DEFAULT_VALUE = new Object();
and didn't exist in the 1.8.x releases
To fix it I need to either use reflection or upgrade the avro dependency to 1.9.2 and fix the jsonNodeToObject
method.
public static Object jsonNodeToObject(JsonNode defaultJsonValue) {
if(defaultJsonValue != null && defaultJsonValue.isNull()) {
return Schema.Field.NULL_DEFAULT_VALUE;
}
return DEFAULT_VALUE_MAPPER.convertValue(defaultJsonValue, Object.class);
}
After reading some of the currently opened issues it appears there is a lot of friction and incompataibilities that arises from the fact of upgrading avro to 1.9.2 As I'm starting a new project, I don't have such friction, so I'll fork the 2.11 branch and will wait for a proper fix in the 3.x release
By the way, when is the 3.x release due to be released approximately ?
No good idea on 3.x, but I would not necessary wait for that. 2.12 should be finalized within 1-2 months, released by end of September, so some fixes (progress towards better avro-lib 1.9 or beyond compatibility) could go there.
Found a solution (not a perfect one, but doing the work):
It also handles other @NotNull
annotations.
It will put null
for all non required/@NotNull fields.
It will put []
for all required/@NotNull lists.
AvroMapper avroMapper = AvroMapper.builder()
.addModule(new SimpleModule(){
@Override
public void setupModule(SetupContext context) {
context.insertAnnotationIntrospector(new AnnotationIntrospector() {
@Override
public Boolean hasRequiredMarker(AnnotatedMember m) {
if (isRequired(m))
return true;
return null;
}
private boolean isRequired(Annotated ann) {
return ann.hasOneOf(new Class[]{NotNull.class, org.jetbrains.annotations.NotNull.class});
}
@Override
public String findPropertyDefaultValue(Annotated ann) {
if (!isRequired(ann)) {
return "null";
}
if (ann.getType().isCollectionLikeType()) {
return "[]";
}
return null;
}
@Override
public Version version() {
return Version.unknownVersion();
}
});
}
})
Thank you for sharing @Chuckame
@cowtowncoder try using @AvroDefault
@Skjolberg could you elaborate?
@cowtowncoder you need to set a default value in some fields, right? Well with the @AvroDefault annotation in Java you can do this when generating the schema.
@Skjolberg This is about generating schema via Avro module, from regular POJO that does not use Avro annotations. It looks like @AvroDefault
was mentioned in an earlier comment as also not working (not being recognized or applied).
So I was thinking you might have an idea of how processing needs to be changed or so, based on earlier discussions.
@cowtowncoder I'm using 2.15.3 on Jackson and 1.11.0 on avro, what I said above is working in my case.
@Skjolberg Interesting. Previous comments suggested it didn't, but perhaps they tried using something pre apache avro 1.11.0? We do have some issues wrt jackson-dataformat-avro and post-1.8.2 avro-lib, regarding tests but I guess runtime one can use overrides.
After upgrading from jackson
2.10.3
to2.11.0
and using avro1.9.2
, I noticed that the schema generation is broken regarding default "null" values for union types.Exemple POJO :
Code to generate the JSON schema :
With version 2.10.3 we had :
Now with version 2.11.0 we have :
The
default
field in the schema is missing when generating the schema with version2.11.0
After short analysis, I have noticed than in the
org.apache.avro
class, the methodhasDefaultValue
always returnsfalse
, so when generating the json schema output in thefieldsToJson
method, this code never write the default field :The
Field
instance is instanciated bycom.fasterxml.jackson.dataformat.avro.schema.RecordVisitor
and it seems to mess up with the default value :When debugging, with this
Book
class :JsonNode defaultValue
contains an instance ofNullNode
AvroSchemaHelper.jsonNodeToObject(defaultValue)
returns nullField
constructor there is a weird comparisondefaultValue == NULL_DEFAULT_VALUE
where NULL_DEFAULT_VALUE = new Object()NullNode
default value being completely forgotten and replaced by null which results in no default value at allDid something change to how I should specify a default value on a POJO field ? I tried with @JsonProperty and @AvroDefault but none work.