package com.fasterxml.jackson.dataformat.avro.ser;

import java.nio.ByteBuffer;
import java.util.Arrays;

import org.apache.avro.Schema;
import org.apache.avro.generic.GenericData;
import org.apache.avro.generic.GenericRecord;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.dataformat.avro.AvroGenerator;

public final class ObjectWriteContext
    extends KeyValueContext
{
    protected final GenericRecord _record;

    
Definition of property that is to be written next, if any; null if property is to be skipped.
/** * Definition of property that is to be written next, if any; * null if property is to be skipped. */
protected Schema.Field _nextField; public ObjectWriteContext(AvroWriteContext parent, AvroGenerator generator, GenericRecord record, Object currValue) { super(parent, generator, record.getSchema(), currValue); _record = record; } @Override public Object rawValue() { return _record; } @Override public final AvroWriteContext createChildArrayContext(Object currValue) { _verifyValueWrite(); Schema.Field field = _findField(); if (field == null) { // unknown, to ignore return new NopWriteContext(TYPE_ARRAY, this, _generator, currValue); } AvroWriteContext child = new ArrayWriteContext(this, _generator, _createArray(field.schema()), currValue); _record.put(_currentName, child.rawValue()); return child; } @Override public AvroWriteContext createChildObjectContext(Object currValue) throws JsonMappingException { _verifyValueWrite(); Schema.Field field = _findField(); if (field == null) { // unknown, to ignore return new NopWriteContext(TYPE_OBJECT, this, _generator, currValue); } AvroWriteContext child = _createObjectContext(field.schema(), currValue); _record.put(_currentName, child.rawValue()); return child; } @Override public final boolean writeFieldName(String name) { _currentName = name; _expectValue = true; Schema.Field field = _schema.getField(name); if (field == null) { _reportUnknownField(name); _nextField = null; return false; } _nextField = field; return true; } @Override public void writeValue(Object value) throws JsonMappingException { _verifyValueWrite(); if (_nextField != null) { Schema schema = _nextField.schema(); 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; byte[] bytes = bb.array(); if (bb.arrayOffset() != 0 || bb.remaining() != bytes.length) { bytes = Arrays.copyOfRange(bytes, bb.arrayOffset(), bb.remaining()); } value = new GenericData.Fixed(schema, bytes); } _record.put(_nextField.pos(), value); } } @Override public void writeString(String value) { _verifyValueWrite(); if (_nextField != null) { _record.put(_nextField.pos(), value); } } @Override public void writeNull() { _verifyValueWrite(); if (_nextField != null) { _record.put(_nextField.pos(), null); } } protected final void _verifyValueWrite() { if (!_expectValue) { throw new IllegalStateException("Expecting FIELD_NAME, not value"); } _expectValue = false; } protected Schema.Field _findField() { if (_currentName == null) { throw new IllegalStateException("No current field name"); } Schema.Field f = _schema.getField(_currentName); if (f == null) { _reportUnknownField(_currentName); } return f; } protected void _reportUnknownField(String name) { if (!_generator.isEnabled(JsonGenerator.Feature.IGNORE_UNKNOWN)) { throw new IllegalStateException("No field named '"+_currentName+"'"); } } }