如何使用杰克逊ObjectMapper解析Mongodb的UUID对象?

时间:2019-12-07 08:32:34

标签: java mongodb kotlin jackson

我在MongoDB集合sample中有以下文档,我想将该文档映射回Kotlin对象Sample

我编写了一个自定义反序列化器以读取UUID的二进制值,但是失败。任何帮助将不胜感激。

db.signals.findOne():
/* 1 */
{
    "_id" : ObjectId("5deb5bb749772bab4217199e"),
    "name" : "Tom",
    "sampleId" : LUUID("6b48b8d3-b64f-cfae-9df1-76dd01933281")
}

Sample.kt

@JsonIgnoreProperties(ignoreUnknown = true)
class Sample @JsonCreator constructor(
    @JsonProperty("name")var name: String) {
    @JsonProperty("sampleId") val sampleId = UUID.randomUUID();
}

主应用。

fun main() {
    val config = loadConfig()

    val mongoClientURI = config.mongodb;
    val mongoClient = MongoClients.create(mongoClientURI);
    val db = mongoClient.getDatabase("db");

    val objectMapper = ObjectMapper();
    val module = SimpleModule();
    module.addSerializer(UUID::class.java, mongo.UUIDSerializer)
    module.addDeserializer(UUID::class.java, mongo.UUIDDeserializer)
    objectMapper.registerModule(module);

    val samples = db.getCollection("sample");   //Document{{_id=5deb5bb749772bab4217199e, name=Tom, sampleId=aecf4fb6-d3b8-486b-8132-9301dd76f19d}}
    val sampleDoc: Document? = samples.findOne();
    println(sampleDoc)

    val sample = objectMapper.readValue(sampleDoc?.toJson(), Sample::class.java);
    println(sample)
}

异常堆栈跟踪:

  

线程“ main”中的异常com.fasterxml.jackson.databind.JsonMappingException:当前令牌(START_OBJECT)不是VALUE_STRING或VALUE_EMBEDDED_OBJECT,不能作为二进制文件访问    在[来源:(String)“ {” _ id“:{” $ oid“:” 5deb5bb749772bab4217199e“},” name“:” Tom“,” sampleId“:{” $ binary“:” a0i407ZPz66d8XbdAZMygQ ==“,” $类型“:” 03“}}”;行:1,列:74](通过参考链:mongodb.Sample [“ sampleId”])       在com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:394)       在com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:353)       在com.fasterxml.jackson.databind.deser.BeanDeserializerBase.wrapAndThrow(BeanDeserializerBase.java:1714)       在com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:254)       在com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeUsingPropertyBased(BeanDeserializer.java:441)       在com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1287)       在com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:326)       在com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:159)       在com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4202)       在com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3205)       在com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3173)       在mongodb.MongoKt.main(mongo.kt:70)       在mongodb.MongoKt.main(mongo.kt)   引起原因:com.fasterxml.jackson.core.JsonParseException:当前令牌(START_OBJECT)不是VALUE_STRING或VALUE_EMBEDDED_OBJECT,不能作为二进制文件访问    在[来源:(String)“ {” _ id“:{” $ oid“:” 5deb5bb749772bab4217199e“},” name“:” Tom“,” sampleId“:{” $ binary“:” a0i407ZPz66d8XbdAZMygQ ==“,” $类型“:” 03“}}”;行:1,列:75]       com.fasterxml.jackson.core.JsonParser._constructError(JsonParser.java:1840)       在com.fasterxml.jackson.core.base.ParserMinimalBase._reportError(ParserMinimalBase.java:712)       在com.fasterxml.jackson.core.json.ReaderBasedJsonParser.getBinaryValue(ReaderBasedJsonParser.java:467)       在com.fasterxml.jackson.core.JsonParser.getBinaryValue(JsonParser.java:1484)       在mongodb.mongo $ UUIDDeserializer.deserialize(mongo.kt:41)       在mongodb.mongo $ UUIDDeserializer.deserialize(mongo.kt:39)       在com.fasterxml.jackson.databind.deser.impl.FieldProperty.deserializeAndSet(FieldProperty.java:138)       在com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:252)       ...还有9个

序列化器和反序列化器:

class mongo {
    companion object {
        fun getBytesFromUUID(uuid: UUID): ByteArray {
            val bb: ByteBuffer = ByteBuffer.wrap(ByteArray(16))
            bb.putLong(uuid.mostSignificantBits)
            bb.putLong(uuid.leastSignificantBits)
            return bb.array()
        }

        fun getUUIDFromBytes(bytes: ByteArray): UUID {
            val byteBuffer: ByteBuffer = ByteBuffer.wrap(bytes)
            val high: Long = byteBuffer.getLong()
            val low: Long = byteBuffer.getLong()
            return UUID(high, low)
        }
    }

    object UUIDDeserializer : StdDeserializer<UUID>(UUID::class.java) {
        override fun deserialize(parser: JsonParser, deserializer: DeserializationContext): UUID {
            val binary: ByteArray = parser.binaryValue
            val uuid = getUUIDFromBytes(binary);

            return uuid;
        }
    }

    object UUIDSerializer : StdSerializer<UUID>(UUID::class.java) {
        override fun serialize(uuid: UUID, jsonGenerator: JsonGenerator, serializerProvider: SerializerProvider) {
            jsonGenerator.writeBinary(getBytesFromUUID(uuid))
        }
    }
}

1 个答案:

答案 0 :(得分:1)

您可以使用以下Jackson自定义序列化器和反序列化器来处理到Java UUID的转换:

LUUID序列化程序

/**
 * Jackson serializer for MongoDB legacy UUIDs.  An LUUID is composed of a Base64 encoded UUID, and a type.
 *
 * <p><p><p>
 * Example as JSON serialized string:
 * <pre>
 * {@code
 *  {"$binary": "a0i407ZPz66d8XbdAZMygQ==", "$type": "03"}
 * }
 * </pre>
 */
public class LegacyUuidSerializer extends StdSerializer<UUID> {
    public LegacyUuidSerializer() {
        super(UUID.class);
    }

    @Override
    public void serialize(UUID value, JsonGenerator generator, SerializerProvider provider) throws IOException {
        byte[] bytes = new byte[16];
        ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
        byteBuffer.putLong(value.getMostSignificantBits());
        byteBuffer.putLong(value.getLeastSignificantBits());
        String base64EncodedUuid = Base64.getEncoder().encodeToString(bytes);
        generator.writeStartObject();
        generator.writeStringField("$binary", base64EncodedUuid);
        generator.writeStringField("$type", "03"); // Assume always type 3.
        generator.writeEndObject();
    }
}

LUUID反序列化器

/**
 * Jackson deserializer for MongoDB legacy UUIDs.  An LUUID is composed of a Base64 encoded UUID, and a type.
 *
 * <p><p><p>
 * Example as JSON serialized string:
 * <pre>
 * {@code
 *  {"$binary": "a0i407ZPz66d8XbdAZMygQ==", "$type": "03"}
 * }
 * </pre>
 */
public class LegacyUuidDeserializer extends StdDeserializer<UUID> {
    public LegacyUuidDeserializer() {
        super(UUID.class);
    }

    @Override
    public UUID deserialize(JsonParser parser, DeserializationContext context) throws IOException {
        parser.nextToken(); // $binary
        parser.nextToken(); // Base64 encoded UUID.
        String base64EncodedUuid = parser.getText();
        parser.nextToken(); // $type
        parser.nextToken(); // $type value, e.g. 03
        byte[] bytes = Base64.getDecoder().decode(base64EncodedUuid);
        ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
        long mostSigBits = byteBuffer.getLong();
        long leastSigBits = byteBuffer.getLong();
        return new UUID(mostSigBits, leastSigBits);
    }
}

域对象

@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class Sample {
    private String name;

    @JsonSerialize(using = LegacyUuidSerializer.class)
    @JsonDeserialize(using = LegacyUuidDeserializer.class)
    private UUID sampleId;
}