20

MongoDB Java Driver を使用して DBObject を POJOに変換するのと似ていますが、マッピングに Jackson を使用することに特に関心があるという点で、私の質問は異なります。

Mongo DBObject インスタンスに変換したいオブジェクトがあります。Jackson JSON フレームワークを使用して仕事をしたいと考えています。

これを行う 1 つの方法は次のとおりです。

DBObject dbo = (DBObject)JSON.parse(m_objectMapper.writeValueAsString(entity));

ただし、https://github.com/FasterXML/jackson-docs/wiki/Presentation:-Jackson-Performanceによると、これは最悪の方法です。だから、私は代替手段を探しています。DBObject理想的には、JSON 生成パイプラインにフックして、その場でインスタンスを生成できるようにしたいと考えています。BasicDBObject私の場合、ターゲットは Map インターフェイスを実装するインスタンスであるため、これが可能です。したがって、パイプラインに簡単に収まるはずです。

これで、関数を使用してオブジェクトを Map に変換し、その型のマップ コンストラクターを使用してマップObjectMapper.convertValueをインスタンスに再帰的に変換できることがわかりました。しかし、中間マップを削除して直接作成できるかどうか知りたいです。BasicDBObjectBasicDBObjectBasicDBObject

aBasicDBObjectは本質的にマップであるため、逆の変換、つまりスカラーDBObjectから POJO への変換は簡単であり、非常に効率的であることに注意してください。

DBObject dbo = getDBO();
Class clazz = getObjectClass();
Object pojo = m_objectMapper.convertValue(dbo, clazz);

最後に、私の POJO には JSON アノテーションがありません。このままにしておきたいと思います。

4

5 に答える 5

11

おそらく、Mixin アノテーションを使用して POJO とBasicDBObject(またはDBObject) にアノテーションを付けることができるため、アノテーションは問題になりません。はマップなので、put メソッドでBasicDBOject使用できます。@JsonAnySetter

m_objectMapper.addMixInAnnotations(YourMixIn.class, BasicDBObject.class);

public interface YourMixIn.class {
    @JsonAnySetter
    void put(String key, Object value);
}

私は MongoDB オブジェクトの経験がまったくないので、思いつくのはこれだけです。

更新: MixInは基本的に、クラスを変更せずにクラスに注釈を追加する Jackson メカニズムです。これは、マーシャリングするクラスを制御できない場合 (外部 jar からの場合など) や、クラスを注釈で混乱させたくない場合に最適です。

ここでのあなたのケースでは、インターフェースをBasicDBObject実装すると言いました。そのMapため、クラスにはputmap インターフェースで定義されているメソッドがあります。そのメソッドに@JsonAnySetterを追加することで、Jackson に、クラスのイントロスペクション後にわからないプロパティを見つけたときはいつでもメソッドを使用してプロパティをオブジェクトに挿入するように指示します。キーはプロパティの名前で、値はプロパティの値です。

これをすべて組み合わせると、BasicDBOjectJson からそのクラスを逆シリアル化する方法がわかっているため、Jackson は に直接変換するため、中間マップはなくなります。その構成では、次のことができます。

DBObject dbo = m_objectMapper.convertValue(pojo, BasicDBObject.class);

私は MongoDB を扱っていないため、これをテストしていないことに注意してください。ただし、同様のユースケースに対して同じメカニズムを問題なく使用しました。クラスによってはYMMV。

于 2013-04-03T15:45:51.273 に答える
4

バージョン 3 の Mongo driver で使用できる、POJO から BsonDocument への単純なシリアライザー (Scala で作成) の例を次に示します。デシリアライザの記述はやや難しくなります。

BsonObjectGeneratorMongo Bson へのストリーミング シリアル化を直接行うオブジェクトを作成します。

val generator = new BsonObjectGenerator
mapper.writeValue(generator, POJO)
generator.result()

シリアライザーのコードは次のとおりです。

class BsonObjectGenerator extends JsonGenerator {

  sealed trait MongoJsonStreamContext extends JsonStreamContext

  case class MongoRoot(root: BsonDocument = BsonDocument()) extends MongoJsonStreamContext {
    _type = JsonStreamContext.TYPE_ROOT

    override def getCurrentName: String = null

    override def getParent: MongoJsonStreamContext = null
  }

  case class MongoArray(parent: MongoJsonStreamContext, arr: BsonArray = BsonArray()) extends MongoJsonStreamContext {
    _type = JsonStreamContext.TYPE_ARRAY

    override def getCurrentName: String = null

    override def getParent: MongoJsonStreamContext = parent
  }

  case class MongoObject(name: String, parent: MongoJsonStreamContext, obj: BsonDocument = BsonDocument()) extends MongoJsonStreamContext {
    _type = JsonStreamContext.TYPE_OBJECT

    override def getCurrentName: String = name

    override def getParent: MongoJsonStreamContext = parent
  }

  private val root = MongoRoot()
  private var node: MongoJsonStreamContext = root

  private var fieldName: String = _

  def result(): BsonDocument = root.root

  private def unsupported(): Nothing = throw new UnsupportedOperationException

  override def disable(f: Feature): JsonGenerator = this

  override def writeStartArray(): Unit = {
    val array = new BsonArray
    node match {
      case MongoRoot(o) =>
        o.append(fieldName, array)
        fieldName = null
      case MongoArray(_, a) =>
        a.add(array)
      case MongoObject(_, _, o) =>
        o.append(fieldName, array)
        fieldName = null
    }
    node = MongoArray(node, array)
  }

  private def writeBsonValue(value: BsonValue): Unit = node match {
    case MongoRoot(o) =>
      o.append(fieldName, value)
      fieldName = null
    case MongoArray(_, a) =>
      a.add(value)
    case MongoObject(_, _, o) =>
      o.append(fieldName, value)
      fieldName = null
  }

  private def writeBsonString(text: String): Unit = {
    writeBsonValue(BsonString(text))
  }

  override def writeString(text: String): Unit = writeBsonString(text)

  override def writeString(text: Array[Char], offset: Int, len: Int): Unit = writeBsonString(new String(text, offset, len))

  override def writeString(text: SerializableString): Unit = writeBsonString(text.getValue)

  private def writeBsonFieldName(name: String): Unit = {
    fieldName = name
  }

  override def writeFieldName(name: String): Unit = writeBsonFieldName(name)

  override def writeFieldName(name: SerializableString): Unit = writeBsonFieldName(name.getValue)

  override def setCodec(oc: ObjectCodec): JsonGenerator = this

  override def useDefaultPrettyPrinter(): JsonGenerator = this

  override def getFeatureMask: Int = 0

  private def writeBsonBinary(data: Array[Byte]): Unit = {
    writeBsonValue(BsonBinary(data))
  }

  override def writeBinary(bv: Base64Variant, data: Array[Byte], offset: Int, len: Int): Unit = {
    val res = if (offset != 0 || len != data.length) {
      val subset = new Array[Byte](len)
      System.arraycopy(data, offset, subset, 0, len)
      subset
    } else {
      data
    }
    writeBsonBinary(res)
  }

  override def writeBinary(bv: Base64Variant, data: InputStream, dataLength: Int): Int = unsupported()

  override def isEnabled(f: Feature): Boolean = false

  override def writeRawUTF8String(text: Array[Byte], offset: Int, length: Int): Unit = writeBsonString(new String(text, offset, length, "UTF-8"))

  override def writeRaw(text: String): Unit = unsupported()

  override def writeRaw(text: String, offset: Int, len: Int): Unit = unsupported()

  override def writeRaw(text: Array[Char], offset: Int, len: Int): Unit = unsupported()

  override def writeRaw(c: Char): Unit = unsupported()

  override def flush(): Unit = ()

  override def writeRawValue(text: String): Unit = writeBsonString(text)

  override def writeRawValue(text: String, offset: Int, len: Int): Unit = writeBsonString(text.substring(offset, offset + len))

  override def writeRawValue(text: Array[Char], offset: Int, len: Int): Unit = writeBsonString(new String(text, offset, len))

  override def writeBoolean(state: Boolean): Unit = {
    writeBsonValue(BsonBoolean(state))
  }

  override def writeStartObject(): Unit = {
    node = node match {
      case p@MongoRoot(o) =>
        MongoObject(null, p, o)
      case p@MongoArray(_, a) =>
        val doc = new BsonDocument
        a.add(doc)
        MongoObject(null, p, doc)
      case p@MongoObject(_, _, o) =>
        val doc = new BsonDocument
        val f = fieldName
        o.append(f, doc)
        fieldName = null
        MongoObject(f, p, doc)
    }
  }

  override def writeObject(pojo: scala.Any): Unit = unsupported()

  override def enable(f: Feature): JsonGenerator = this

  override def writeEndArray(): Unit = {
    node = node match {
      case MongoRoot(_) => unsupported()
      case MongoArray(p, a) => p
      case MongoObject(_, _, _) => unsupported()
    }
  }

  override def writeUTF8String(text: Array[Byte], offset: Int, length: Int): Unit = writeBsonString(new String(text, offset, length, "UTF-8"))

  override def close(): Unit = ()

  override def writeTree(rootNode: TreeNode): Unit = unsupported()

  override def setFeatureMask(values: Int): JsonGenerator = this

  override def isClosed: Boolean = unsupported()

  override def writeNull(): Unit = {
    writeBsonValue(BsonNull())
  }

  override def writeNumber(v: Int): Unit = {
    writeBsonValue(BsonInt32(v))
  }

  override def writeNumber(v: Long): Unit = {
    writeBsonValue(BsonInt64(v))
  }

  override def writeNumber(v: BigInteger): Unit = unsupported()

  override def writeNumber(v: Double): Unit = {
    writeBsonValue(BsonDouble(v))
  }

  override def writeNumber(v: Float): Unit = {
    writeBsonValue(BsonDouble(v))
  }

  override def writeNumber(v: BigDecimal): Unit = unsupported()

  override def writeNumber(encodedValue: String): Unit = unsupported()

  override def version(): Version = unsupported()

  override def getCodec: ObjectCodec = unsupported()

  override def getOutputContext: JsonStreamContext = node

  override def writeEndObject(): Unit = {
    node = node match {
      case p@MongoRoot(_) => p
      case MongoArray(p, a) => unsupported()
      case MongoObject(_, p, _) => p
    }
  }
}
于 2016-10-10T12:47:22.723 に答える