-
-
Notifications
You must be signed in to change notification settings - Fork 137
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Avro] Add support for @union deserialization
- Loading branch information
1 parent
575e4e2
commit b31da0c
Showing
30 changed files
with
753 additions
and
224 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
6 changes: 3 additions & 3 deletions
6
avro/src/main/java/com/fasterxml/jackson/dataformat/avro/AvroMapper.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
74 changes: 74 additions & 0 deletions
74
avro/src/main/java/com/fasterxml/jackson/dataformat/avro/AvroTypeDeserializer.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
package com.fasterxml.jackson.dataformat.avro; | ||
|
||
import java.io.IOException; | ||
|
||
import com.fasterxml.jackson.annotation.JsonTypeInfo; | ||
import com.fasterxml.jackson.core.JsonParser; | ||
import com.fasterxml.jackson.databind.BeanProperty; | ||
import com.fasterxml.jackson.databind.DeserializationContext; | ||
import com.fasterxml.jackson.databind.JavaType; | ||
import com.fasterxml.jackson.databind.JsonDeserializer; | ||
import com.fasterxml.jackson.databind.jsontype.TypeDeserializer; | ||
import com.fasterxml.jackson.databind.jsontype.TypeIdResolver; | ||
import com.fasterxml.jackson.databind.jsontype.impl.TypeDeserializerBase; | ||
import com.fasterxml.jackson.dataformat.avro.schema.AvroSchemaHelper; | ||
|
||
public class AvroTypeDeserializer extends TypeDeserializerBase { | ||
|
||
protected AvroTypeDeserializer(JavaType baseType, TypeIdResolver idRes, String typePropertyName, boolean typeIdVisible, | ||
JavaType defaultImpl) { | ||
super(baseType, idRes, typePropertyName, typeIdVisible, defaultImpl); | ||
} | ||
|
||
protected AvroTypeDeserializer(TypeDeserializerBase src, BeanProperty property) { | ||
super(src, property); | ||
} | ||
|
||
@Override | ||
public TypeDeserializer forProperty(BeanProperty prop) { | ||
return new AvroTypeDeserializer(this, prop); | ||
} | ||
|
||
@Override | ||
public JsonTypeInfo.As getTypeInclusion() { | ||
// Don't do any restructuring of the incoming JSON tokens | ||
return JsonTypeInfo.As.EXISTING_PROPERTY; | ||
} | ||
|
||
@Override | ||
public Object deserializeTypedFromObject(JsonParser p, DeserializationContext ctxt) throws IOException { | ||
return deserializeTypedFromAny(p, ctxt); | ||
} | ||
|
||
@Override | ||
public Object deserializeTypedFromArray(JsonParser p, DeserializationContext ctxt) throws IOException { | ||
return deserializeTypedFromAny(p, ctxt); | ||
} | ||
|
||
@Override | ||
public Object deserializeTypedFromScalar(JsonParser p, DeserializationContext ctxt) throws IOException { | ||
return deserializeTypedFromAny(p, ctxt); | ||
} | ||
|
||
@Override | ||
public Object deserializeTypedFromAny(JsonParser p, DeserializationContext ctxt) throws IOException { | ||
if (p.getTypeId() == null && getDefaultImpl() == null) { | ||
JsonDeserializer<Object> deser = _findDeserializer(ctxt, AvroSchemaHelper.getTypeId(_baseType)); | ||
if (deser == null) { | ||
ctxt.reportInputMismatch(_baseType, "No (native) type id found when one was expected for polymorphic type handling"); | ||
return null; | ||
} | ||
return deser.deserialize(p, ctxt); | ||
} | ||
return _deserializeWithNativeTypeId(p, ctxt, p.getTypeId()); | ||
} | ||
|
||
@Override | ||
protected JavaType _handleUnknownTypeId(DeserializationContext ctxt, String typeId) | ||
throws IOException { | ||
if (ctxt.hasValueDeserializerFor(_baseType, null)) { | ||
return _baseType; | ||
} | ||
return super._handleUnknownTypeId(ctxt, typeId); | ||
} | ||
} |
63 changes: 63 additions & 0 deletions
63
avro/src/main/java/com/fasterxml/jackson/dataformat/avro/AvroTypeIdResolver.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
package com.fasterxml.jackson.dataformat.avro; | ||
|
||
import java.io.IOException; | ||
import java.util.Collection; | ||
import java.util.HashMap; | ||
import java.util.Map; | ||
|
||
import com.fasterxml.jackson.databind.DatabindContext; | ||
import com.fasterxml.jackson.databind.JavaType; | ||
import com.fasterxml.jackson.databind.exc.InvalidTypeIdException; | ||
import com.fasterxml.jackson.databind.jsontype.NamedType; | ||
import com.fasterxml.jackson.databind.jsontype.impl.ClassNameIdResolver; | ||
import com.fasterxml.jackson.databind.type.TypeFactory; | ||
|
||
/** | ||
* {@link com.fasterxml.jackson.databind.jsontype.TypeIdResolver} for Avro type IDs embedded in schemas. Avro generally uses class names, | ||
* but we want to also support named subtypes so that developers can easily remap the embedded type IDs to a different runtime class. | ||
*/ | ||
public class AvroTypeIdResolver extends ClassNameIdResolver { | ||
|
||
private final Map<String, Class<?>> _idTypes = new HashMap<>(); | ||
|
||
private final Map<Class<?>, String> _typeIds = new HashMap<>(); | ||
|
||
public AvroTypeIdResolver(JavaType baseType, TypeFactory typeFactory, Collection<NamedType> subTypes) { | ||
this(baseType, typeFactory); | ||
if (subTypes != null) { | ||
for (NamedType namedType : subTypes) { | ||
registerSubtype(namedType.getType(), namedType.getName()); | ||
} | ||
} | ||
} | ||
|
||
public AvroTypeIdResolver(JavaType baseType, TypeFactory typeFactory) { | ||
super(baseType, typeFactory); | ||
} | ||
|
||
@Override | ||
public void registerSubtype(Class<?> type, String name) { | ||
_idTypes.put(name, type); | ||
_typeIds.put(type, name); | ||
} | ||
|
||
@Override | ||
protected JavaType _typeFromId(String id, DatabindContext ctxt) throws IOException { | ||
// base types don't have subclasses | ||
if (_baseType.isPrimitive()) { | ||
return _baseType; | ||
} | ||
// check if there's a specific type we should be using for this ID | ||
Class<?> subType = _idTypes.get(id); | ||
if (subType != null) { | ||
id = _idFrom(null, subType, _typeFactory); | ||
} | ||
try { | ||
return super._typeFromId(id, ctxt); | ||
} catch (InvalidTypeIdException | IllegalArgumentException e) { | ||
// AvroTypeDeserializer expects null if we can't map the type ID to a class; It will throw an appropriate error if we can't | ||
// find a usable type. | ||
return null; | ||
} | ||
} | ||
} |
50 changes: 50 additions & 0 deletions
50
avro/src/main/java/com/fasterxml/jackson/dataformat/avro/AvroTypeResolverBuilder.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
package com.fasterxml.jackson.dataformat.avro; | ||
|
||
import java.util.Collection; | ||
|
||
import com.fasterxml.jackson.databind.DeserializationConfig; | ||
import com.fasterxml.jackson.databind.JavaType; | ||
import com.fasterxml.jackson.databind.SerializationConfig; | ||
import com.fasterxml.jackson.databind.cfg.MapperConfig; | ||
import com.fasterxml.jackson.databind.jsontype.NamedType; | ||
import com.fasterxml.jackson.databind.jsontype.TypeDeserializer; | ||
import com.fasterxml.jackson.databind.jsontype.TypeIdResolver; | ||
import com.fasterxml.jackson.databind.jsontype.TypeSerializer; | ||
import com.fasterxml.jackson.databind.jsontype.impl.StdTypeResolverBuilder; | ||
|
||
|
||
public class AvroTypeResolverBuilder extends StdTypeResolverBuilder { | ||
|
||
public AvroTypeResolverBuilder() { | ||
super(); | ||
typeIdVisibility(false).typeProperty("@class"); | ||
} | ||
|
||
@Override | ||
public TypeSerializer buildTypeSerializer(SerializationConfig config, JavaType baseType, Collection<NamedType> subtypes) { | ||
// All type information is encoded in the schema, never in the data. | ||
return null; | ||
} | ||
|
||
@Override | ||
public TypeDeserializer buildTypeDeserializer(DeserializationConfig config, JavaType baseType, Collection<NamedType> subtypes) { | ||
JavaType defaultImpl = null; | ||
if (getDefaultImpl() != null) { | ||
defaultImpl = config.constructType(getDefaultImpl()); | ||
} | ||
|
||
return new AvroTypeDeserializer(baseType, | ||
idResolver(config, baseType, subtypes, true, true), | ||
getTypeProperty(), | ||
isTypeIdVisible(), | ||
defaultImpl | ||
); | ||
|
||
} | ||
|
||
@Override | ||
protected TypeIdResolver idResolver(MapperConfig<?> config, JavaType baseType, Collection<NamedType> subtypes, boolean forSer, | ||
boolean forDeser) { | ||
return new AvroTypeIdResolver(baseType, config.getTypeFactory(), subtypes); | ||
} | ||
} |
Oops, something went wrong.