Skip to content

Custom serializer with type information and yaml output #192

@migel

Description

@migel

Hi, I'm trying to write a custom serializer for an Nd4j array (see http://nd4j.org). I was about to get it working with json but when I try yaml output I get an exception:

  Cause: com.fasterxml.jackson.dataformat.yaml.snakeyaml.emitter.EmitterException: expected NodeEvent, but got <com.fasterxml.jackson.dataformat.yaml.snakeyaml.events.DocumentEndEvent()>
  at com.fasterxml.jackson.dataformat.yaml.snakeyaml.emitter.Emitter.expectNode(Emitter.java:409)
  at com.fasterxml.jackson.dataformat.yaml.snakeyaml.emitter.Emitter.access$1600(Emitter.java:63)
  at com.fasterxml.jackson.dataformat.yaml.snakeyaml.emitter.Emitter$ExpectBlockMappingValue.expect(Emitter.java:651)
  at com.fasterxml.jackson.dataformat.yaml.snakeyaml.emitter.Emitter.emit(Emitter.java:217)
  at com.fasterxml.jackson.dataformat.yaml.YAMLGenerator.close(YAMLGenerator.java:308)
  at com.fasterxml.jackson.databind.ObjectMapper._configAndWriteValue(ObjectMapper.java:3398)
  at com.fasterxml.jackson.databind.ObjectMapper.writeValueAsString(ObjectMapper.java:2779)

In order to simplify the test I created dummy classes for Nd4j so I know the issue is not specific to that package. This test case:

import com.fasterxml.jackson.databind.JsonSerializer
//import org.nd4j.linalg.api.ndarray.INDArray
import com.fasterxml.jackson.core.JsonGenerator
import com.fasterxml.jackson.databind.SerializerProvider
//import org.nd4j.linalg.api.buffer.DataBuffer
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.scala.DefaultScalaModule
import com.fasterxml.jackson.databind.module.SimpleModule
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory
import com.fasterxml.jackson.databind.jsontype.TypeSerializer
//import org.nd4j.linalg.factory.Nd4j
import com.fasterxml.jackson.annotation.JsonTypeInfo
import org.scalatest.FunSuite

// Dummy INDArray
class INDArray {
  val _data = new DataBuffer
  def shape() = Array[Int](1, 3)
  def data = _data
  def ordering() = 'f'
}

// Dummy DataBuffer
class DataBuffer {
  def dataType = 1
  def asBytes() = Array[Byte](1, 2, 3)
}

// Custom serializer for INDArray
class NDArraySerializer extends JsonSerializer[INDArray] {

  def serialize(
    value: INDArray,
    jgen: JsonGenerator,
    provider: SerializerProvider) {

    jgen.writeStartObject()

    jgen.writeArrayFieldStart("shape")
    for (i <- value.shape()) jgen.writeNumber(i)
    jgen.writeEndArray()

    val dtype =
      if (value.data.dataType == 1 /*DataBuffer.FLOAT*/ )
        "float"
      else
        "double"
    jgen.writeStringField("dtype", dtype)

    jgen.writeStringField("order", value.ordering().toString())

    jgen.writeBinaryField("data", value.data.asBytes())

    jgen.writeEndObject()
  }

  override def serializeWithType(
    value: INDArray,
    jgen: JsonGenerator,
    provider: SerializerProvider,
    typeSer: TypeSerializer) {

    typeSer.writeTypePrefixForObject(value, jgen)
    serialize(value, jgen, provider)
    typeSer.writeTypeSuffixForObject(value, jgen)
  }
}

class TestYAML extends FunSuite {

  test("yaml") {

    try {
      val nd4jModule = new SimpleModule()

      nd4jModule.addSerializer(classOf[INDArray], new NDArraySerializer())

      val jsonMapper = new ObjectMapper

      jsonMapper.registerModule(DefaultScalaModule)

      jsonMapper.registerModule(nd4jModule)

      jsonMapper.enableDefaultTyping(
        ObjectMapper.DefaultTyping.NON_FINAL,
        JsonTypeInfo.As.PROPERTY)

      val yamlMapper = new ObjectMapper(new YAMLFactory)

      yamlMapper.registerModule(DefaultScalaModule)

      yamlMapper.registerModule(nd4jModule)

      yamlMapper.enableDefaultTyping(
        ObjectMapper.DefaultTyping.NON_FINAL,
        JsonTypeInfo.As.PROPERTY)

      val array = new INDArray

      jsonMapper.writeValueAsString(array)

      yamlMapper.writeValueAsString(array)
    }
    catch {
      case e: Throwable => fail("shouldn't throw an exception.", e)
    }
  }
}

If I comment out the enableDefaultTyping call it works.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions