From cb1a58d1566d433de49a41b9dcc732e40c056910 Mon Sep 17 00:00:00 2001 From: Bryan Harclerode Date: Tue, 28 Mar 2017 15:50:41 -0500 Subject: [PATCH 1/2] [Avro] Add support for @AvroEncode annotation --- .../avro/AvroAnnotationIntrospector.java | 16 ++ .../dataformat/avro/AvroGenerator.java | 20 +- .../jackson/dataformat/avro/AvroParser.java | 16 ++ .../avro/CustomEncodingWrapper.java | 62 ++++++ .../dataformat/avro/deser/ArrayReader.java | 6 +- .../dataformat/avro/deser/AvroParserImpl.java | 45 +++- .../avro/deser/AvroParserImplDecoder.java | 209 ++++++++++++++++++ .../deser/CustomEncodingDeserializer.java | 38 ++++ .../dataformat/avro/deser/MapReader.java | 10 + .../dataformat/avro/deser/StructDefaults.java | 5 + .../dataformat/avro/schema/RecordVisitor.java | 5 + .../avro/schema/VisitorFormatWrapperImpl.java | 5 + .../avro/ser/CustomEncodingDatum.java | 28 +++ .../avro/ser/CustomEncodingSerializer.java | 46 ++++ .../dataformat/avro/ser/EncodedDatum.java | 22 ++ .../avro/ser/NonBSGenericDatumWriter.java | 5 + .../avro/ser/ObjectWriteContext.java | 2 +- .../interop/annotations/AvroEncodeTest.java | 144 ++++++++++++ 18 files changed, 671 insertions(+), 13 deletions(-) create mode 100644 avro/src/main/java/com/fasterxml/jackson/dataformat/avro/CustomEncodingWrapper.java create mode 100644 avro/src/main/java/com/fasterxml/jackson/dataformat/avro/deser/AvroParserImplDecoder.java create mode 100644 avro/src/main/java/com/fasterxml/jackson/dataformat/avro/deser/CustomEncodingDeserializer.java create mode 100644 avro/src/main/java/com/fasterxml/jackson/dataformat/avro/ser/CustomEncodingDatum.java create mode 100644 avro/src/main/java/com/fasterxml/jackson/dataformat/avro/ser/CustomEncodingSerializer.java create mode 100644 avro/src/main/java/com/fasterxml/jackson/dataformat/avro/ser/EncodedDatum.java create mode 100644 avro/src/test/java/com/fasterxml/jackson/dataformat/avro/interop/annotations/AvroEncodeTest.java diff --git a/avro/src/main/java/com/fasterxml/jackson/dataformat/avro/AvroAnnotationIntrospector.java b/avro/src/main/java/com/fasterxml/jackson/dataformat/avro/AvroAnnotationIntrospector.java index d52551ea2..27329f9ed 100644 --- a/avro/src/main/java/com/fasterxml/jackson/dataformat/avro/AvroAnnotationIntrospector.java +++ b/avro/src/main/java/com/fasterxml/jackson/dataformat/avro/AvroAnnotationIntrospector.java @@ -20,7 +20,10 @@ import com.fasterxml.jackson.databind.jsontype.NamedType; import com.fasterxml.jackson.databind.jsontype.TypeResolverBuilder; import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; +import com.fasterxml.jackson.databind.util.ClassUtil; +import com.fasterxml.jackson.dataformat.avro.deser.CustomEncodingDeserializer; import com.fasterxml.jackson.dataformat.avro.schema.AvroSchemaHelper; +import com.fasterxml.jackson.dataformat.avro.ser.CustomEncodingSerializer; /** * Adds support for the following annotations from the Apache Avro implementation: @@ -62,6 +65,15 @@ public PropertyName findNameForDeserialization(Annotated a) { return _findName(a); } + @Override + public Object findDeserializer(Annotated am) { + AvroEncode ann = _findAnnotation(am, AvroEncode.class); + if (ann != null) { + return new CustomEncodingDeserializer<>((CustomEncoding)ClassUtil.createInstance(ann.using(), true)); + } + return null; + } + @Override public String findPropertyDefaultValue(Annotated m) { AvroDefault ann = _findAnnotation(m, AvroDefault.class); @@ -113,6 +125,10 @@ public Object findSerializer(Annotated a) { if (a.hasAnnotation(Stringable.class)) { return ToStringSerializer.class; } + AvroEncode ann = _findAnnotation(a, AvroEncode.class); + if (ann != null) { + return new CustomEncodingSerializer<>((CustomEncoding)ClassUtil.createInstance(ann.using(), true)); + } return null; } diff --git a/avro/src/main/java/com/fasterxml/jackson/dataformat/avro/AvroGenerator.java b/avro/src/main/java/com/fasterxml/jackson/dataformat/avro/AvroGenerator.java index 381de6a7d..9923dcf01 100644 --- a/avro/src/main/java/com/fasterxml/jackson/dataformat/avro/AvroGenerator.java +++ b/avro/src/main/java/com/fasterxml/jackson/dataformat/avro/AvroGenerator.java @@ -8,18 +8,11 @@ import org.apache.avro.io.BinaryEncoder; -import com.fasterxml.jackson.core.Base64Variant; -import com.fasterxml.jackson.core.FormatFeature; -import com.fasterxml.jackson.core.FormatSchema; -import com.fasterxml.jackson.core.JsonGenerationException; -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.core.ObjectCodec; -import com.fasterxml.jackson.core.PrettyPrinter; -import com.fasterxml.jackson.core.SerializableString; -import com.fasterxml.jackson.core.Version; +import com.fasterxml.jackson.core.*; import com.fasterxml.jackson.core.base.GeneratorBase; import com.fasterxml.jackson.core.io.IOContext; import com.fasterxml.jackson.dataformat.avro.ser.AvroWriteContext; +import com.fasterxml.jackson.dataformat.avro.ser.EncodedDatum; public class AvroGenerator extends GeneratorBase { @@ -458,6 +451,15 @@ public final void writeUTF8String(byte[] text, int offset, int len) throws IOExc /********************************************************** */ + @Override + public void writeEmbeddedObject(Object object) throws IOException { + if (object instanceof EncodedDatum) { + _avroContext.writeValue(object); + return; + } + super.writeEmbeddedObject(object); + } + @Override public void writeRaw(String text) throws IOException { _reportUnsupportedOperation(); diff --git a/avro/src/main/java/com/fasterxml/jackson/dataformat/avro/AvroParser.java b/avro/src/main/java/com/fasterxml/jackson/dataformat/avro/AvroParser.java index 10a5a1ae3..1f0e83042 100644 --- a/avro/src/main/java/com/fasterxml/jackson/dataformat/avro/AvroParser.java +++ b/avro/src/main/java/com/fasterxml/jackson/dataformat/avro/AvroParser.java @@ -9,7 +9,9 @@ import com.fasterxml.jackson.core.io.IOContext; import com.fasterxml.jackson.core.json.JsonReadContext; import com.fasterxml.jackson.core.util.ByteArrayBuilder; +import com.fasterxml.jackson.dataformat.avro.deser.ArrayReader; import com.fasterxml.jackson.dataformat.avro.deser.AvroReadContext; +import com.fasterxml.jackson.dataformat.avro.deser.MapReader; import com.fasterxml.jackson.dataformat.avro.deser.MissingReader; /** @@ -257,6 +259,20 @@ public JsonLocation getCurrentLocation() // !!! TODO return null; } + + /** + * Returns the remaining number of elements in the current block of a map or array + */ + public long getRemainingElements() { + + if ( _avroContext instanceof ArrayReader) { + return ((ArrayReader) _avroContext).getRemainingElements(); + } + if (_avroContext instanceof MapReader) { + return ((MapReader) _avroContext).getRemainingElements(); + } + return -1; + } /* /********************************************************** diff --git a/avro/src/main/java/com/fasterxml/jackson/dataformat/avro/CustomEncodingWrapper.java b/avro/src/main/java/com/fasterxml/jackson/dataformat/avro/CustomEncodingWrapper.java new file mode 100644 index 000000000..f7380ff38 --- /dev/null +++ b/avro/src/main/java/com/fasterxml/jackson/dataformat/avro/CustomEncodingWrapper.java @@ -0,0 +1,62 @@ +package com.fasterxml.jackson.dataformat.avro; + +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +import org.apache.avro.Schema; +import org.apache.avro.io.Decoder; +import org.apache.avro.io.Encoder; +import org.apache.avro.reflect.CustomEncoding; + +/** + * Wrapper that makes the methods on a {@link CustomEncoding} accessible since they are otherwise package-private. + */ +public class CustomEncodingWrapper { + private static final Method GET_SCHEMA; + private static final Method READ; + private static final Method WRITE; + + static { + try { + GET_SCHEMA = CustomEncoding.class.getDeclaredMethod("getSchema"); + READ = CustomEncoding.class.getDeclaredMethod("read", Object.class, Decoder.class); + WRITE = CustomEncoding.class.getDeclaredMethod("write", Object.class, Encoder.class); + GET_SCHEMA.setAccessible(true); + READ.setAccessible(true); + WRITE.setAccessible(true); + } catch (NoSuchMethodException e) { + throw new RuntimeException("Failed to initialize CustomEncoderWrapper, Avro version mismatch?", e); + } + } + + private final CustomEncoding encoding; + + public CustomEncodingWrapper(CustomEncoding encoding) { + this.encoding = encoding; + } + + public void write(Object datum, Encoder out) throws IOException { + try { + WRITE.invoke(encoding, datum, out); + } catch (IllegalAccessException | InvocationTargetException e) { + throw new RuntimeException("Failed to encode object", e); + } + } + + public Schema getSchema() { + try { + return (Schema) GET_SCHEMA.invoke(encoding); + } catch (IllegalAccessException | InvocationTargetException e) { + throw new RuntimeException("Failed to access schema", e); + } + } + + public T read(Object reuse, Decoder in) throws IOException { + try { + return (T) READ.invoke(encoding, reuse, in); + } catch (IllegalAccessException | InvocationTargetException e) { + throw new RuntimeException("Failed to decode object", e); + } + } +} diff --git a/avro/src/main/java/com/fasterxml/jackson/dataformat/avro/deser/ArrayReader.java b/avro/src/main/java/com/fasterxml/jackson/dataformat/avro/deser/ArrayReader.java index 9269f9fa6..409051827 100644 --- a/avro/src/main/java/com/fasterxml/jackson/dataformat/avro/deser/ArrayReader.java +++ b/avro/src/main/java/com/fasterxml/jackson/dataformat/avro/deser/ArrayReader.java @@ -4,7 +4,7 @@ import com.fasterxml.jackson.core.JsonToken; -abstract class ArrayReader extends AvroStructureReader +public abstract class ArrayReader extends AvroStructureReader { protected final static int STATE_START = 0; protected final static int STATE_ELEMENTS = 1; @@ -55,6 +55,10 @@ protected void appendDesc(StringBuilder sb) { sb.append(']'); } + public long getRemainingElements() { + return _count - _index; + } + @Override public String getTypeId() { return _currToken != JsonToken.START_ARRAY && _currToken != JsonToken.END_ARRAY ? _elementTypeId : super.getTypeId(); diff --git a/avro/src/main/java/com/fasterxml/jackson/dataformat/avro/deser/AvroParserImpl.java b/avro/src/main/java/com/fasterxml/jackson/dataformat/avro/deser/AvroParserImpl.java index 2518e451c..ccb3fad63 100644 --- a/avro/src/main/java/com/fasterxml/jackson/dataformat/avro/deser/AvroParserImpl.java +++ b/avro/src/main/java/com/fasterxml/jackson/dataformat/avro/deser/AvroParserImpl.java @@ -55,6 +55,16 @@ public class AvroParserImpl extends AvroParser */ protected BinaryDecoder _decoder; + /** + * Index of the union branch that was followed to reach the current token. This is cleared when the next token is read. + */ + protected int _branchIndex; + + /** + * Index of the enum that was read as the current token. This is cleared when the next token is read. + */ + protected int _enumIndex; + /* /********************************************************** /* Life-cycle @@ -101,6 +111,23 @@ protected void _releaseBuffers() throws IOException { } } + /** + * Skip to the end of the current structure (array/map/object); This is different from {@link #skipMap()} and {@link #skipArray()} + * because it operates at the parser level instead of at the decoder level and advances the parsing context in addition to consuming + * the data from the input. + * + * @throws IOException If there was an issue advancing through the underlying data stream + */ + protected void skipValue() throws IOException { + if (_avroContext instanceof ArrayReader) { + ((ArrayReader) _avroContext).skipValue(this); + } else if (_avroContext instanceof MapReader) { + ((MapReader) _avroContext).skipValue(this); + } else if (_avroContext instanceof RecordReader) { + ((RecordReader) _avroContext).skipValue(this); + } + } + @Override public JsonParser overrideFormatFeatures(int values, int mask) { int oldF = _formatFeatures; @@ -141,6 +168,8 @@ protected void _closeInput() throws IOException { @Override public JsonToken nextToken() throws IOException { + _branchIndex = -1; + _enumIndex = -1; _binaryValue = null; if (_closed) { return null; @@ -331,11 +360,11 @@ public long skipMap() throws IOException { // // // Misc other decoding public int decodeIndex() throws IOException { - return _decoder.readIndex(); + return (_branchIndex = _decoder.readIndex()); } public int decodeEnum() throws IOException { - return _decoder.readEnum(); + return (_enumIndex = _decoder.readEnum()); } public boolean checkInputEnd() throws IOException { @@ -347,6 +376,18 @@ public boolean checkInputEnd() throws IOException { /* Methods for AvroReadContext impls, other /********************************************************** */ + + protected int branchIndex() { + return _branchIndex; + } + + protected int enumIndex() { + return _enumIndex; + } + + protected boolean isRecord() { + return _avroContext instanceof RecordReader; + } protected void setAvroContext(AvroReadContext ctxt) { if (ctxt == null) { // sanity check diff --git a/avro/src/main/java/com/fasterxml/jackson/dataformat/avro/deser/AvroParserImplDecoder.java b/avro/src/main/java/com/fasterxml/jackson/dataformat/avro/deser/AvroParserImplDecoder.java new file mode 100644 index 000000000..ea46fd4b7 --- /dev/null +++ b/avro/src/main/java/com/fasterxml/jackson/dataformat/avro/deser/AvroParserImplDecoder.java @@ -0,0 +1,209 @@ +package com.fasterxml.jackson.dataformat.avro.deser; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.Arrays; + +import org.apache.avro.io.Decoder; +import org.apache.avro.util.Utf8; + +import com.fasterxml.jackson.core.JsonToken; + +/** + * Wraps an AvroParser instance and allows it to be advanced by reading from it like an avro {@link Decoder} + */ +public class AvroParserImplDecoder extends Decoder { + + protected final AvroParserImpl _parser; + + public AvroParserImplDecoder(AvroParserImpl parser) { + _parser = parser; + } + + /** + * Reads in the next value token from the parser and validates that it's one of the expected tokens + * + * @param expectedTokens List of token types that is expected + * @return The token that was consumed from the parser + * @throws IOException If there is an error while reading the next token + * @throws IllegalArgumentException If the next token is not one of the expectedTokens + */ + protected JsonToken consumeToken(JsonToken... expectedTokens) throws IOException { + JsonToken token = nextValue(); + for (JsonToken expectedToken : expectedTokens) { + if (token.equals(expectedToken)) { + _parser.clearCurrentToken(); + return token; + } + } + throw new IllegalArgumentException("Expected " + Arrays.toString(expectedTokens) + ", got: " + token); + } + + /** + * Advance to the next actual value token; This effectively discards the virtual JSON tokens inserted by the parser for + * START_OBJECT, END_OBJECT, START_ARRAY, etc. that are not actually present in the underlying + * data stream and stops after reading the first token that represents actual data + * + * @return The next data token + * @throws IOException If there is an error while reading the next token + */ + protected JsonToken nextValue() throws IOException { + // Decoders don't care about start and end of records, or field names in records; swallow them + while (((_parser.currentToken() == JsonToken.START_OBJECT || _parser.currentToken() == JsonToken.END_OBJECT + || _parser.currentToken() == JsonToken.FIELD_NAME) && _parser.isRecord()) || _parser.currentToken() == null + || _parser.currentToken() == JsonToken.END_ARRAY) { + _parser.nextToken(); + if (_parser.currentToken() == null) { + break; + } + } + return _parser.currentToken(); + } + + /** + * Advance to the next token that might contain union branching information; This effectively discards the virtual JSON tokens inserted + * by the parser for END_OBJECT, START_ARRAY, etc. that are not actually present in the underlying data + * stream and stops after reading the first token that represents actual data. START_OBJECT is not skipped because union + * information is only available at the start of an object, and has been discarded by the parser by the time we reach the next actual + * value. + * + * @return The next union branch token + * @throws IOException If there is an error while reading the next token + */ + protected JsonToken nextUnionValue() throws IOException { + // Decoders don't care about end of records, or field names in records; swallow them + while (((_parser.currentToken() == JsonToken.END_OBJECT || _parser.currentToken() == JsonToken.FIELD_NAME) && _parser.isRecord()) + || _parser.currentToken() == null || _parser.currentToken() == JsonToken.END_ARRAY) { + _parser.nextToken(); + if (_parser.currentToken() == null) { + break; + } + } + return _parser.currentToken(); + } + + @Override + public void readNull() throws IOException { + consumeToken(JsonToken.VALUE_NULL); + } + + @Override + public boolean readBoolean() throws IOException { + return consumeToken(JsonToken.VALUE_FALSE, JsonToken.VALUE_TRUE) == JsonToken.VALUE_TRUE; + } + + @Override + public int readInt() throws IOException { + consumeToken(JsonToken.VALUE_NUMBER_INT); + return _parser.getIntValue(); + } + + @Override + public long readLong() throws IOException { + consumeToken(JsonToken.VALUE_NUMBER_INT); + return _parser.getLongValue(); + } + + @Override + public float readFloat() throws IOException { + consumeToken(JsonToken.VALUE_NUMBER_FLOAT); + return _parser.getFloatValue(); + } + + @Override + public double readDouble() throws IOException { + consumeToken(JsonToken.VALUE_NUMBER_FLOAT); + return _parser.getDoubleValue(); + } + + @Override + public Utf8 readString(Utf8 old) throws IOException { + return new Utf8(readString()); + } + + @Override + public String readString() throws IOException { + nextValue(); + String value = _parser.getText(); + _parser.clearCurrentToken(); + return value; + } + + @Override + public void skipString() throws IOException { + consumeToken(JsonToken.VALUE_STRING); + readString(); + } + + @Override + public ByteBuffer readBytes(ByteBuffer old) throws IOException { + consumeToken(JsonToken.VALUE_EMBEDDED_OBJECT); + return ByteBuffer.wrap(_parser.getBinaryValue()); + } + + @Override + public void skipBytes() throws IOException { + readBytes(null); + } + + @Override + public void readFixed(byte[] bytes, int start, int length) throws IOException { + consumeToken(JsonToken.VALUE_EMBEDDED_OBJECT); + System.arraycopy(_parser.getBinaryValue(), 0, bytes, start, length); + } + + @Override + public void skipFixed(int length) throws IOException { + readFixed(new byte[length], 0, length); + } + + @Override + public int readEnum() throws IOException { + nextValue(); + return _parser.enumIndex(); + } + + @Override + public long readArrayStart() throws IOException { + consumeToken(JsonToken.START_ARRAY); + return _parser.getRemainingElements(); + } + + @Override + public long arrayNext() throws IOException { + return _parser.getRemainingElements(); + } + + @Override + public long skipArray() throws IOException { + consumeToken(JsonToken.START_ARRAY); + _parser.skipValue(); + consumeToken(JsonToken.END_ARRAY); + return 0; + } + + @Override + public long readMapStart() throws IOException { + consumeToken(JsonToken.START_OBJECT); + return _parser.getRemainingElements(); + } + + @Override + public long mapNext() throws IOException { + return _parser.getRemainingElements(); + } + + @Override + public long skipMap() throws IOException { + consumeToken(JsonToken.START_OBJECT); + _parser.skipValue(); + consumeToken(JsonToken.END_OBJECT); + return 0; + } + + @Override + public int readIndex() throws IOException { + nextUnionValue(); + return _parser.branchIndex(); + } +} diff --git a/avro/src/main/java/com/fasterxml/jackson/dataformat/avro/deser/CustomEncodingDeserializer.java b/avro/src/main/java/com/fasterxml/jackson/dataformat/avro/deser/CustomEncodingDeserializer.java new file mode 100644 index 000000000..6479bacd3 --- /dev/null +++ b/avro/src/main/java/com/fasterxml/jackson/dataformat/avro/deser/CustomEncodingDeserializer.java @@ -0,0 +1,38 @@ +package com.fasterxml.jackson.dataformat.avro.deser; + +import java.io.IOException; + +import org.apache.avro.reflect.CustomEncoding; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; +import com.fasterxml.jackson.dataformat.avro.CustomEncodingWrapper; + +/** + * Deserializes an object using a avro {@link CustomEncoding} + * + * @see com.fasterxml.jackson.dataformat.avro.AvroAnnotationIntrospector + */ +public class CustomEncodingDeserializer extends JsonDeserializer { + + private final CustomEncodingWrapper encoding; + + public CustomEncodingDeserializer(CustomEncoding encoding) { + this.encoding = new CustomEncodingWrapper<>(encoding); + } + + @Override + public T deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { + AvroParserImpl avroParser = (AvroParserImpl) p; + AvroParserImplDecoder decoder = new AvroParserImplDecoder(avroParser); + return encoding.read(null, decoder); + } + + @Override + public T deserialize(JsonParser p, DeserializationContext ctxt, T intoValue) throws IOException { + AvroParserImpl avroParser = (AvroParserImpl) p; + AvroParserImplDecoder decoder = new AvroParserImplDecoder(avroParser); + return encoding.read(intoValue, decoder); + } +} diff --git a/avro/src/main/java/com/fasterxml/jackson/dataformat/avro/deser/MapReader.java b/avro/src/main/java/com/fasterxml/jackson/dataformat/avro/deser/MapReader.java index 9a3d4d954..cfcd2f910 100644 --- a/avro/src/main/java/com/fasterxml/jackson/dataformat/avro/deser/MapReader.java +++ b/avro/src/main/java/com/fasterxml/jackson/dataformat/avro/deser/MapReader.java @@ -51,6 +51,8 @@ public static MapReader construct(AvroStructureReader reader, String typeId, Str @Override public abstract void skipValue(AvroParserImpl parser) throws IOException; + public abstract long getRemainingElements(); + @Override public String nextFieldName() throws IOException { JsonToken t = nextToken(); @@ -106,6 +108,10 @@ protected Scalar(AvroReadContext parent, super(parent, parser, typeId, keyTypeId, valueTypeId != null ? valueTypeId : sd.getTypeId()); _scalarDecoder = sd; } + + public long getRemainingElements() { + return _count - _index; + } @Override public MapReader newReader(AvroReadContext parent, AvroParserImpl parser) { @@ -178,6 +184,10 @@ public NonScalar(AvroReadContext parent, super(parent, parser, typeId, keyTypeId, null); _structureReader = reader; } + + public long getRemainingElements() { + return _count - _index; + } @Override public MapReader newReader(AvroReadContext parent, AvroParserImpl parser) { diff --git a/avro/src/main/java/com/fasterxml/jackson/dataformat/avro/deser/StructDefaults.java b/avro/src/main/java/com/fasterxml/jackson/dataformat/avro/deser/StructDefaults.java index 23c9d6e84..b7a27e349 100644 --- a/avro/src/main/java/com/fasterxml/jackson/dataformat/avro/deser/StructDefaults.java +++ b/avro/src/main/java/com/fasterxml/jackson/dataformat/avro/deser/StructDefaults.java @@ -40,6 +40,11 @@ public ObjectDefaults(AvroReadContext parent, _fieldReaders = fieldReaders; } + @Override + public long getRemainingElements() { + return _fieldReaders.length - _index; + } + @Override public MapReader newReader(AvroReadContext parent, AvroParserImpl parser) { diff --git a/avro/src/main/java/com/fasterxml/jackson/dataformat/avro/schema/RecordVisitor.java b/avro/src/main/java/com/fasterxml/jackson/dataformat/avro/schema/RecordVisitor.java index 52bdfdda8..f1d6867bb 100644 --- a/avro/src/main/java/com/fasterxml/jackson/dataformat/avro/schema/RecordVisitor.java +++ b/avro/src/main/java/com/fasterxml/jackson/dataformat/avro/schema/RecordVisitor.java @@ -19,6 +19,7 @@ import com.fasterxml.jackson.databind.jsontype.NamedType; import com.fasterxml.jackson.databind.ser.BeanPropertyWriter; import com.fasterxml.jackson.dataformat.avro.AvroFixedSize; +import com.fasterxml.jackson.dataformat.avro.ser.CustomEncodingSerializer; public class RecordVisitor extends JsonObjectFormatVisitor.Base @@ -161,6 +162,10 @@ protected Schema.Field schemaFieldForWriter(BeanProperty prop, boolean optional) if (prop instanceof BeanPropertyWriter) { BeanPropertyWriter bpw = (BeanPropertyWriter) prop; ser = bpw.getSerializer(); + /* + * 2-Mar-2017, bryan: AvroEncode annotation expects to have the schema used directly + */ + optional = optional && !(ser instanceof CustomEncodingSerializer); // Don't modify schema } final SerializerProvider prov = getProvider(); if (ser == null) { diff --git a/avro/src/main/java/com/fasterxml/jackson/dataformat/avro/schema/VisitorFormatWrapperImpl.java b/avro/src/main/java/com/fasterxml/jackson/dataformat/avro/schema/VisitorFormatWrapperImpl.java index 4c8aac1e1..99bf9e63d 100644 --- a/avro/src/main/java/com/fasterxml/jackson/dataformat/avro/schema/VisitorFormatWrapperImpl.java +++ b/avro/src/main/java/com/fasterxml/jackson/dataformat/avro/schema/VisitorFormatWrapperImpl.java @@ -5,6 +5,7 @@ import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.SerializerProvider; import com.fasterxml.jackson.databind.jsonFormatVisitors.*; +import com.fasterxml.jackson.dataformat.avro.AvroSchema; public class VisitorFormatWrapperImpl implements JsonFormatVisitorWrapper @@ -69,6 +70,10 @@ public Schema getAvroSchema() { /********************************************************************** */ + public void expectAvroFormat(AvroSchema schema) { + _valueSchema = schema.getAvroSchema(); + } + @Override public JsonObjectFormatVisitor expectObjectFormat(JavaType type) { diff --git a/avro/src/main/java/com/fasterxml/jackson/dataformat/avro/ser/CustomEncodingDatum.java b/avro/src/main/java/com/fasterxml/jackson/dataformat/avro/ser/CustomEncodingDatum.java new file mode 100644 index 000000000..88d1c17f5 --- /dev/null +++ b/avro/src/main/java/com/fasterxml/jackson/dataformat/avro/ser/CustomEncodingDatum.java @@ -0,0 +1,28 @@ +package com.fasterxml.jackson.dataformat.avro.ser; + +import java.io.IOException; + +import org.apache.avro.io.Encoder; + +import com.fasterxml.jackson.dataformat.avro.CustomEncodingWrapper; + +/** + * Writes out an object using a {@link org.apache.avro.reflect.CustomEncoding} + * + * @param Type of data supported by this EncodedDatum + */ +public class CustomEncodingDatum implements EncodedDatum { + + private final CustomEncodingWrapper _encoding; + + private final T _datum; + + public CustomEncodingDatum(CustomEncodingWrapper encoding, T datum) { + this._encoding = encoding; + this._datum = datum; + } + + public void write(Encoder encoder) throws IOException { + _encoding.write(_datum, encoder); + } +} diff --git a/avro/src/main/java/com/fasterxml/jackson/dataformat/avro/ser/CustomEncodingSerializer.java b/avro/src/main/java/com/fasterxml/jackson/dataformat/avro/ser/CustomEncodingSerializer.java new file mode 100644 index 000000000..1c405db28 --- /dev/null +++ b/avro/src/main/java/com/fasterxml/jackson/dataformat/avro/ser/CustomEncodingSerializer.java @@ -0,0 +1,46 @@ +package com.fasterxml.jackson.dataformat.avro.ser; + +import java.io.IOException; + +import org.apache.avro.reflect.CustomEncoding; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonFormatVisitorWrapper; +import com.fasterxml.jackson.dataformat.avro.AvroSchema; +import com.fasterxml.jackson.dataformat.avro.CustomEncodingWrapper; +import com.fasterxml.jackson.dataformat.avro.schema.VisitorFormatWrapperImpl; + +/** + * Serializes an object using a avro {@link CustomEncoding} + * + * @see com.fasterxml.jackson.dataformat.avro.AvroAnnotationIntrospector + */ +public class CustomEncodingSerializer extends JsonSerializer { + + private final CustomEncodingWrapper encoding; + + public CustomEncodingSerializer(CustomEncoding encoding) { + this.encoding = new CustomEncodingWrapper<>(encoding); + } + + @Override + public void serialize(T t, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) + throws IOException, JsonProcessingException { + jsonGenerator.writeEmbeddedObject(new CustomEncodingDatum<>(encoding, t)); + + } + + @Override + public void acceptJsonFormatVisitor(JsonFormatVisitorWrapper visitor, JavaType type) throws JsonMappingException { + if (visitor instanceof VisitorFormatWrapperImpl) { + ((VisitorFormatWrapperImpl) visitor).expectAvroFormat(new AvroSchema(encoding.getSchema())); + } else { + super.acceptJsonFormatVisitor(visitor, type); + } + } +} diff --git a/avro/src/main/java/com/fasterxml/jackson/dataformat/avro/ser/EncodedDatum.java b/avro/src/main/java/com/fasterxml/jackson/dataformat/avro/ser/EncodedDatum.java new file mode 100644 index 000000000..eec3ffb74 --- /dev/null +++ b/avro/src/main/java/com/fasterxml/jackson/dataformat/avro/ser/EncodedDatum.java @@ -0,0 +1,22 @@ +package com.fasterxml.jackson.dataformat.avro.ser; + +import java.io.IOException; + +import org.apache.avro.io.Encoder; + +import com.fasterxml.jackson.dataformat.avro.AvroGenerator; + +/** + * Interface for handling opaque avro-encoded objects. These can be written with {@link AvroGenerator#writeEmbeddedObject(Object)} and will + * be written directly to the encoder. + */ +public interface EncodedDatum { + + /** + * Callback invoked when it is time to write this datum to the output + * + * @param encoder Encoder to which the datum should be written + * @throws IOException if there was an error writing out the datum + */ + void write(Encoder encoder) throws IOException; +} diff --git a/avro/src/main/java/com/fasterxml/jackson/dataformat/avro/ser/NonBSGenericDatumWriter.java b/avro/src/main/java/com/fasterxml/jackson/dataformat/avro/ser/NonBSGenericDatumWriter.java index a06b005d2..707ad840c 100644 --- a/avro/src/main/java/com/fasterxml/jackson/dataformat/avro/ser/NonBSGenericDatumWriter.java +++ b/avro/src/main/java/com/fasterxml/jackson/dataformat/avro/ser/NonBSGenericDatumWriter.java @@ -33,6 +33,11 @@ public int resolveUnion(Schema union, Object datum) { @Override protected void write(Schema schema, Object datum, Encoder out) throws IOException { + // EncodedDatum are already in an avro-encoded format and can be written out directly to the underlying encoder + if (datum instanceof EncodedDatum) { + ((EncodedDatum) datum).write(out); + return; + } Type t = schema.getType(); if (t == Type.ENUM) { super.writeWithoutConversion(schema, GENERIC_DATA.createEnum(datum.toString(), schema), out); diff --git a/avro/src/main/java/com/fasterxml/jackson/dataformat/avro/ser/ObjectWriteContext.java b/avro/src/main/java/com/fasterxml/jackson/dataformat/avro/ser/ObjectWriteContext.java index 45cf8d8c1..fdd700c85 100644 --- a/avro/src/main/java/com/fasterxml/jackson/dataformat/avro/ser/ObjectWriteContext.java +++ b/avro/src/main/java/com/fasterxml/jackson/dataformat/avro/ser/ObjectWriteContext.java @@ -90,7 +90,7 @@ public void writeValue(Object value) throws JsonMappingException { _verifyValueWrite(); if (_nextField != null) { Schema schema = _nextField.schema(); - if (schema.getType() == Schema.Type.FIXED) { + if (schema.getType() == Schema.Type.FIXED && value instanceof ByteBuffer) { // 13-Nov-2014 josh: AvroGenerator wraps all binary values in ByteBuffers, // but avro wants FIXED, so rewrap the array, copying if necessary ByteBuffer bb = (ByteBuffer) value; diff --git a/avro/src/test/java/com/fasterxml/jackson/dataformat/avro/interop/annotations/AvroEncodeTest.java b/avro/src/test/java/com/fasterxml/jackson/dataformat/avro/interop/annotations/AvroEncodeTest.java new file mode 100644 index 000000000..aeee84a8c --- /dev/null +++ b/avro/src/test/java/com/fasterxml/jackson/dataformat/avro/interop/annotations/AvroEncodeTest.java @@ -0,0 +1,144 @@ +package com.fasterxml.jackson.dataformat.avro.interop.annotations; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.apache.avro.io.Decoder; +import org.apache.avro.io.Encoder; +import org.apache.avro.reflect.AvroEncode; +import org.apache.avro.reflect.CustomEncoding; +import org.apache.avro.reflect.Nullable; +import org.apache.avro.reflect.ReflectData; +import org.junit.Before; +import org.junit.Test; + +import com.fasterxml.jackson.dataformat.avro.interop.ApacheAvroInteropUtil; +import com.fasterxml.jackson.dataformat.avro.interop.InteropTestBase; + +import static org.assertj.core.api.Assertions.assertThat; + +public class AvroEncodeTest extends InteropTestBase { + + @Data + static class Wrapper { + + private double precedingValue = 0.18273465; + + @AvroEncode(using = ApacheImplEncoding.class) + private CustomComponent component; + + private int followingValue = 3456; + + } + + @Data + @AllArgsConstructor + @NoArgsConstructor + static class CustomComponent { + + private int intValue; + + private byte byteValue; + + private short shortValue; + + private String stringValue; + + @Nullable + private Map> mapValue; + + @Nullable + private CustomComponent nestedRecordValue; + + @Nullable + private Double doubleValue; + + @Nullable + private Long longValue; + + } + + public static class ApacheImplEncoding extends CustomEncoding { + + public ApacheImplEncoding() { + schema = ApacheAvroInteropUtil.getJacksonSchema(CustomComponent.class); + } + + @Override + protected void write(Object datum, Encoder out) throws IOException { + ReflectData.get().createDatumWriter(schema).write(datum, out); + } + + @Override + protected CustomComponent read(Object reuse, Decoder in) throws IOException { + return (CustomComponent) ReflectData.get().createDatumReader(schema).read(null, in); + } + + } + + protected Wrapper wrapper; + + protected Wrapper result; + + @Before + public void setup() throws IOException { + wrapper = new Wrapper(); + // + wrapper.setComponent(new CustomComponent()); + wrapper.getComponent().setByteValue((byte) 126); + wrapper.getComponent().setIntValue(897125364); + wrapper.getComponent().setShortValue((short) -7614); + wrapper.getComponent().setMapValue(new HashMap>()); + wrapper.getComponent().getMapValue().put("birds", new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5, 6))); + wrapper.getComponent().getMapValue().put("cats", new ArrayList()); + wrapper.getComponent().getMapValue().put("dogs", new ArrayList<>(Arrays.asList(-1234, 56, 6767, 54134, 57, 86))); + wrapper.getComponent().setStringValue("Hello World!"); + // + wrapper.getComponent().setNestedRecordValue(new CustomComponent()); + wrapper.getComponent().getNestedRecordValue().setByteValue((byte) 42); + wrapper.getComponent().getNestedRecordValue().setIntValue(9557748); + wrapper.getComponent().getNestedRecordValue().setShortValue((short) -1542); + wrapper.getComponent().getNestedRecordValue().setDoubleValue(Double.POSITIVE_INFINITY); + wrapper.getComponent().getNestedRecordValue().setLongValue(Long.MAX_VALUE); + wrapper.getComponent().getNestedRecordValue().setStringValue("Nested Hello World!"); + // + result = roundTrip(wrapper); + } + + @Test + public void testByteValue() { + assertThat(result.getComponent().getByteValue()).isEqualTo(wrapper.getComponent().getByteValue()); + } + + @Test + public void testShortValue() { + assertThat(result.getComponent().getShortValue()).isEqualTo(wrapper.getComponent().getShortValue()); + } + + @Test + public void testStringValue() { + assertThat(result.getComponent().getStringValue()).isEqualTo(wrapper.getComponent().getStringValue()); + } + + @Test + public void testDoubleValue() { + assertThat(result.getComponent().getDoubleValue()).isEqualTo(wrapper.getComponent().getDoubleValue()); + } + + @Test + public void testLongValue() { + assertThat(result.getComponent().getLongValue()).isEqualTo(wrapper.getComponent().getLongValue()); + } + + @Test + public void testIntegerValue() { + assertThat(result.getComponent().getIntValue()).isEqualTo(wrapper.getComponent().getIntValue()); + } + +} From 575645646465b1a5582bec3f255ddf006a1c342b Mon Sep 17 00:00:00 2001 From: Bryan Harclerode Date: Tue, 28 Mar 2017 15:55:49 -0500 Subject: [PATCH 2/2] [Avro] Re-Enable ignored namespace unit tests in 2.9 --- .../avro/interop/InteropTestBase.java | 24 +------------------ .../interop/annotations/AvroIgnoreTest.java | 19 ++++++--------- .../interop/annotations/AvroNameTest.java | 15 ++++-------- .../interop/arrays/ListWithComplexTest.java | 5 ---- .../avro/interop/maps/MapWithComplexTest.java | 6 ----- .../records/RecordWithComplexTest.java | 8 ------- .../records/RecordWithPrimitiveArrayTest.java | 11 ++------- .../records/RecordWithPrimitiveTest.java | 12 ++-------- .../RecordWithPrimitiveWrapperArrayTest.java | 12 ++-------- .../RecordWithPrimitiveWrapperTest.java | 14 +++-------- 10 files changed, 21 insertions(+), 105 deletions(-) diff --git a/avro/src/test/java/com/fasterxml/jackson/dataformat/avro/interop/InteropTestBase.java b/avro/src/test/java/com/fasterxml/jackson/dataformat/avro/interop/InteropTestBase.java index 5277e065b..97334c8e4 100644 --- a/avro/src/test/java/com/fasterxml/jackson/dataformat/avro/interop/InteropTestBase.java +++ b/avro/src/test/java/com/fasterxml/jackson/dataformat/avro/interop/InteropTestBase.java @@ -5,18 +5,10 @@ import java.lang.reflect.Type; import org.apache.avro.Schema; -import org.junit.Assume; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; -import static com.fasterxml.jackson.dataformat.avro.interop.ApacheAvroInteropUtil.apacheDeserializer; -import static com.fasterxml.jackson.dataformat.avro.interop.ApacheAvroInteropUtil.apacheSerializer; -import static com.fasterxml.jackson.dataformat.avro.interop.ApacheAvroInteropUtil.jacksonDeserializer; -import static com.fasterxml.jackson.dataformat.avro.interop.ApacheAvroInteropUtil.jacksonSerializer; -import static com.fasterxml.jackson.dataformat.avro.interop.ApacheAvroInteropUtil.getApacheSchema; -import static com.fasterxml.jackson.dataformat.avro.interop.ApacheAvroInteropUtil.getJacksonSchema; -import static com.fasterxml.jackson.dataformat.avro.interop.ApacheAvroInteropUtil.Function; -import static com.fasterxml.jackson.dataformat.avro.interop.ApacheAvroInteropUtil.BiFunction; +import static com.fasterxml.jackson.dataformat.avro.interop.ApacheAvroInteropUtil.*; /** * Parameterized base class for tests that populates {@link #schemaFunctor}, {@link #serializeFunctor}, and @@ -30,20 +22,6 @@ public enum DummyEnum { NORTH, SOUTH, EAST, WEST } - // To work around 2.8/2.9 difference wrt namespaces for enums - // See [dataformats-binary#58] for details - protected void assumeCompatibleNsForDeser() { - Assume.assumeTrue(deserializeFunctor != apacheDeserializer - || schemaFunctor != ApacheAvroInteropUtil.getJacksonSchema); - } - - // To work around 2.8/2.9 difference wrt namespaces for enums - // See [dataformats-binary#58] for details - protected void assumeCompatibleNsForSer() { - Assume.assumeTrue(serializeFunctor != apacheSerializer - || schemaFunctor != ApacheAvroInteropUtil.getJacksonSchema); - } - /** * Helper method for building a {@link ParameterizedType} for use with {@link #roundTrip(Type, Object)} * diff --git a/avro/src/test/java/com/fasterxml/jackson/dataformat/avro/interop/annotations/AvroIgnoreTest.java b/avro/src/test/java/com/fasterxml/jackson/dataformat/avro/interop/annotations/AvroIgnoreTest.java index 1ad579536..6e6f2faa3 100644 --- a/avro/src/test/java/com/fasterxml/jackson/dataformat/avro/interop/annotations/AvroIgnoreTest.java +++ b/avro/src/test/java/com/fasterxml/jackson/dataformat/avro/interop/annotations/AvroIgnoreTest.java @@ -1,17 +1,18 @@ package com.fasterxml.jackson.dataformat.avro.interop.annotations; +import java.io.IOException; + import org.apache.avro.reflect.AvroIgnore; -import org.junit.Before; import org.junit.Test; -import static org.hamcrest.CoreMatchers.*; +import com.fasterxml.jackson.dataformat.avro.interop.InteropTestBase; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.not; +import static org.hamcrest.CoreMatchers.nullValue; import static org.junit.Assert.assertThat; -import java.io.IOException; - -import com.fasterxml.jackson.dataformat.avro.interop.InteropTestBase; - public class AvroIgnoreTest extends InteropTestBase { static class RecordWithIgnoredField { @@ -22,12 +23,6 @@ public RecordWithIgnoredField() {} public String notIgnoredField; } - @Before - public void setup() { - // 2.8 doesn't generate schemas with compatible namespaces for Apache deserializer - assumeCompatibleNsForDeser(); - } - @Test public void testFieldIgnored() throws IOException { RecordWithIgnoredField r = new RecordWithIgnoredField(); diff --git a/avro/src/test/java/com/fasterxml/jackson/dataformat/avro/interop/annotations/AvroNameTest.java b/avro/src/test/java/com/fasterxml/jackson/dataformat/avro/interop/annotations/AvroNameTest.java index 3f72e4816..c7b5a9c42 100644 --- a/avro/src/test/java/com/fasterxml/jackson/dataformat/avro/interop/annotations/AvroNameTest.java +++ b/avro/src/test/java/com/fasterxml/jackson/dataformat/avro/interop/annotations/AvroNameTest.java @@ -1,17 +1,16 @@ package com.fasterxml.jackson.dataformat.avro.interop.annotations; -import com.fasterxml.jackson.dataformat.avro.AvroTestBase; -import com.fasterxml.jackson.dataformat.avro.interop.InteropTestBase; +import java.io.IOException; import org.apache.avro.reflect.AvroName; -import org.junit.Before; import org.junit.Test; +import com.fasterxml.jackson.dataformat.avro.AvroTestBase; +import com.fasterxml.jackson.dataformat.avro.interop.InteropTestBase; + import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.fail; -import java.io.IOException; - /** * Tests the {@link AvroName @AvroName} annotation */ @@ -34,12 +33,6 @@ public static class RecordWithNameCollision { public String otherField; } - @Before - public void setup() { - // 2.8 doesn't generate schemas with compatible namespaces for Apache deserializer - assumeCompatibleNsForDeser(); - } - @Test public void testRecordWithRenamedField() throws IOException{ RecordWithRenamed original = new RecordWithRenamed(); diff --git a/avro/src/test/java/com/fasterxml/jackson/dataformat/avro/interop/arrays/ListWithComplexTest.java b/avro/src/test/java/com/fasterxml/jackson/dataformat/avro/interop/arrays/ListWithComplexTest.java index a0b6dd576..a04a10f43 100644 --- a/avro/src/test/java/com/fasterxml/jackson/dataformat/avro/interop/arrays/ListWithComplexTest.java +++ b/avro/src/test/java/com/fasterxml/jackson/dataformat/avro/interop/arrays/ListWithComplexTest.java @@ -20,11 +20,6 @@ */ public class ListWithComplexTest extends InteropTestBase { - @Before - public void setup() { - // 2.8 doesn't generate schemas with compatible namespaces for Apache deserializer - assumeCompatibleNsForDeser(); - } @Test public void testEmptyListWithRecordElements() throws IOException { diff --git a/avro/src/test/java/com/fasterxml/jackson/dataformat/avro/interop/maps/MapWithComplexTest.java b/avro/src/test/java/com/fasterxml/jackson/dataformat/avro/interop/maps/MapWithComplexTest.java index ec097c1d1..0971fec3c 100644 --- a/avro/src/test/java/com/fasterxml/jackson/dataformat/avro/interop/maps/MapWithComplexTest.java +++ b/avro/src/test/java/com/fasterxml/jackson/dataformat/avro/interop/maps/MapWithComplexTest.java @@ -3,7 +3,6 @@ import java.io.IOException; import java.util.*; -import org.junit.Before; import org.junit.Test; import com.fasterxml.jackson.dataformat.avro.interop.DummyRecord; @@ -17,11 +16,6 @@ */ public class MapWithComplexTest extends InteropTestBase { - @Before - public void setup() { - // 2.8 doesn't generate schemas with compatible namespaces for Apache deserializer - assumeCompatibleNsForDeser(); - } @Test public void testMapWithRecordValues() throws IOException { diff --git a/avro/src/test/java/com/fasterxml/jackson/dataformat/avro/interop/records/RecordWithComplexTest.java b/avro/src/test/java/com/fasterxml/jackson/dataformat/avro/interop/records/RecordWithComplexTest.java index 32c3419cf..dfc03dc96 100644 --- a/avro/src/test/java/com/fasterxml/jackson/dataformat/avro/interop/records/RecordWithComplexTest.java +++ b/avro/src/test/java/com/fasterxml/jackson/dataformat/avro/interop/records/RecordWithComplexTest.java @@ -5,8 +5,6 @@ import java.util.Map; import org.apache.avro.AvroTypeException; - -import org.junit.Before; import org.junit.Test; import com.fasterxml.jackson.databind.JsonMappingException; @@ -21,12 +19,6 @@ */ public class RecordWithComplexTest extends InteropTestBase { - @Before - public void setup() { - // 2.8 doesn't generate schemas with compatible namespaces for Apache deserializer - assumeCompatibleNsForDeser(); - assumeCompatibleNsForSer(); - } @Test public void testEmptyRecordWithRecordValues() throws IOException { diff --git a/avro/src/test/java/com/fasterxml/jackson/dataformat/avro/interop/records/RecordWithPrimitiveArrayTest.java b/avro/src/test/java/com/fasterxml/jackson/dataformat/avro/interop/records/RecordWithPrimitiveArrayTest.java index d7b236e36..7e0bdfe07 100644 --- a/avro/src/test/java/com/fasterxml/jackson/dataformat/avro/interop/records/RecordWithPrimitiveArrayTest.java +++ b/avro/src/test/java/com/fasterxml/jackson/dataformat/avro/interop/records/RecordWithPrimitiveArrayTest.java @@ -1,26 +1,19 @@ package com.fasterxml.jackson.dataformat.avro.interop.records; -import lombok.Data; +import java.io.IOException; -import org.junit.Before; +import lombok.Data; import org.junit.Test; import com.fasterxml.jackson.dataformat.avro.interop.InteropTestBase; import static org.assertj.core.api.Assertions.assertThat; -import java.io.IOException; - /** * Tests serializing primitive array fields on records */ public class RecordWithPrimitiveArrayTest extends InteropTestBase { - @Before - public void setup() { - // 2.8 doesn't generate schemas with compatible namespaces for Apache deserializer - assumeCompatibleNsForDeser(); - } @Data public static class TestRecord { diff --git a/avro/src/test/java/com/fasterxml/jackson/dataformat/avro/interop/records/RecordWithPrimitiveTest.java b/avro/src/test/java/com/fasterxml/jackson/dataformat/avro/interop/records/RecordWithPrimitiveTest.java index f33c2a47c..52833aef2 100644 --- a/avro/src/test/java/com/fasterxml/jackson/dataformat/avro/interop/records/RecordWithPrimitiveTest.java +++ b/avro/src/test/java/com/fasterxml/jackson/dataformat/avro/interop/records/RecordWithPrimitiveTest.java @@ -1,16 +1,14 @@ package com.fasterxml.jackson.dataformat.avro.interop.records; -import lombok.Data; +import java.io.IOException; -import org.junit.Before; +import lombok.Data; import org.junit.Test; import com.fasterxml.jackson.dataformat.avro.interop.InteropTestBase; import static org.assertj.core.api.Assertions.assertThat; -import java.io.IOException; - /** * Tests serializing primitive fields on records */ @@ -26,12 +24,6 @@ public static class TestRecord { private float floatField; private double doubleField; } - - @Before - public void setup() { - // 2.8 doesn't generate schemas with compatible namespaces for Apache deserializer - assumeCompatibleNsForDeser(); - } @Test public void testByteField() throws IOException { diff --git a/avro/src/test/java/com/fasterxml/jackson/dataformat/avro/interop/records/RecordWithPrimitiveWrapperArrayTest.java b/avro/src/test/java/com/fasterxml/jackson/dataformat/avro/interop/records/RecordWithPrimitiveWrapperArrayTest.java index 2d1baf7c1..83b382829 100644 --- a/avro/src/test/java/com/fasterxml/jackson/dataformat/avro/interop/records/RecordWithPrimitiveWrapperArrayTest.java +++ b/avro/src/test/java/com/fasterxml/jackson/dataformat/avro/interop/records/RecordWithPrimitiveWrapperArrayTest.java @@ -1,16 +1,14 @@ package com.fasterxml.jackson.dataformat.avro.interop.records; -import lombok.Data; +import java.io.IOException; -import org.junit.Before; +import lombok.Data; import org.junit.Test; import com.fasterxml.jackson.dataformat.avro.interop.InteropTestBase; import static org.assertj.core.api.Assertions.assertThat; -import java.io.IOException; - /** * Tests serializing primitive array fields on records */ @@ -28,12 +26,6 @@ public static class TestRecord { private String[] stringArrayField = new String[0]; } - @Before - public void setup() { - // 2.8 doesn't generate schemas with compatible namespaces for Apache deserializer - assumeCompatibleNsForDeser(); - } - @Test public void testByteField() throws IOException { TestRecord record = new TestRecord(); diff --git a/avro/src/test/java/com/fasterxml/jackson/dataformat/avro/interop/records/RecordWithPrimitiveWrapperTest.java b/avro/src/test/java/com/fasterxml/jackson/dataformat/avro/interop/records/RecordWithPrimitiveWrapperTest.java index 2bb5ce259..516f7c013 100644 --- a/avro/src/test/java/com/fasterxml/jackson/dataformat/avro/interop/records/RecordWithPrimitiveWrapperTest.java +++ b/avro/src/test/java/com/fasterxml/jackson/dataformat/avro/interop/records/RecordWithPrimitiveWrapperTest.java @@ -1,15 +1,13 @@ package com.fasterxml.jackson.dataformat.avro.interop.records; -import com.fasterxml.jackson.dataformat.avro.interop.InteropTestBase; +import java.io.IOException; import lombok.Data; - -import org.junit.Before; import org.junit.Test; -import static org.assertj.core.api.Assertions.assertThat; +import com.fasterxml.jackson.dataformat.avro.interop.InteropTestBase; -import java.io.IOException; +import static org.assertj.core.api.Assertions.assertThat; /** * Tests serializing wrapper types for primitives on records @@ -27,12 +25,6 @@ public static class TestRecord { private Double doubleField = 0D; private String stringField = ""; } - - @Before - public void setup() { - // 2.8 doesn't generate schemas with compatible namespaces for Apache deserializer - assumeCompatibleNsForDeser(); - } @Test public void testByteField() throws IOException {