@@ -85,25 +85,56 @@ public RecordVisitor(SerializerProvider p, JavaType type, VisitorFormatWrapperIm
8585
8686 List <NamedType > subTypes = getProvider ().getAnnotationIntrospector ().findSubtypes (bean .getClassInfo ());
8787 if (subTypes != null && !subTypes .isEmpty ()) {
88- List <Schema > unionSchemas = new ArrayList <>();
89- // Initialize with this schema
90- if (_type .isConcrete ()) {
91- unionSchemas .add (_typeSchema );
92- }
88+
89+ // At this point calculating hashCode for _typeSchema fails with NPE because RecordSchema.fields is NULL
90+ // (see org.apache.avro.Schema.RecordSchema#computeHash).
91+ // Therefore, _typeSchema must be added into union at very end, or unionSchemas must not be HashSet (or any
92+ // other type calling hashCode() for equality check).
93+ Set <Schema > unionSchemas = new HashSet <>();
94+ // ArrayList<Schema> unionSchemas = new ArrayList<>();
95+
96+ // IdentityHashMap is used because it is using reference-equality.
97+ // Set<Schema> unionSchemas = Collections.newSetFromMap(new IdentityHashMap<>());
98+
99+ // Initialize with this schema is
100+ // if (_type.isConcrete()) {
101+ // unionSchemas.add(_typeSchema);
102+ // }
103+
93104 try {
94105 for (NamedType subType : subTypes ) {
95106 JsonSerializer <?> ser = getProvider ().findValueSerializer (subType .getType ());
96107 VisitorFormatWrapperImpl visitor = _visitorWrapper .createChildWrapper ();
97108 ser .acceptJsonFormatVisitor (visitor , getProvider ().getTypeFactory ().constructType (subType .getType ()));
98109 Schema subTypeSchema = visitor .getAvroSchema ();
99- // If subType schema is also UNION, include all its types into this union
110+ // Add subType schema into this union, unless it is already there.
111+ // When subType schema is itself a union, include all its types into this union
100112 if (subTypeSchema .getType () == Type .UNION ) {
113+ // subTypeSchema.getTypes().stream()
114+ // .filter(unionElement -> !unionSchemas.contains(unionElement))
115+ // .forEach(unionSchemas::add);
116+ // or
117+ // for( Schema unionElement: subTypeSchema.getTypes()) {
118+ // if (unionSchemas.contains(unionElement)) {
119+ // continue;
120+ // }
121+ // unionSchemas.add(unionElement);
122+ // }
101123 unionSchemas .addAll (subTypeSchema .getTypes ());
102124 } else {
125+ // if (!unionSchemas.contains(subTypeSchema)) {
126+ // unionSchemas.add(subTypeSchema);
127+ // }
103128 unionSchemas .add (subTypeSchema );
104129 }
105130 }
106- _avroSchema = Schema .createUnion (unionSchemas );
131+
132+ ArrayList <Schema > unionList = new ArrayList <>(unionSchemas );
133+ // add _type schema into union
134+ if (_type .isConcrete ()) {
135+ unionList .add (_typeSchema );
136+ }
137+ _avroSchema = Schema .createUnion (unionList );
107138 } catch (JsonMappingException jme ) {
108139 throw new RuntimeException ("Failed to build schema" , jme );
109140 }
0 commit comments