【问题标题】:How do I parse a Mongodb's UUID object using jackson ObjectMapper?如何使用 jackson ObjectMapper 解析 Mongodb 的 UUID 对象?
【发布时间】:2020-04-01 02:31:42
【问题描述】:

我在 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)
}

异常堆栈跟踪:

线程“主”com.fasterxml.jackson.databind.JsonMappingException 中的异常:当前令牌 (START_OBJECT) 不是 VALUE_STRING 或 VALUE_EMBEDDED_OBJECT,不能作为二进制访问 在 [Source: (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,不能作为二进制访问 在 [Source: (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))
        }
    }
}

【问题讨论】:

    标签: java mongodb kotlin jackson


    【解决方案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;
    }
    

    【讨论】:

    • 谢谢@ck1。这正是我正在寻找的。请问您如何获取有关将java.util.UUID 转换为Mongodb 的LUUID() 的信息
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-16
    • 1970-01-01
    • 1970-01-01
    • 2014-12-22
    相关资源
    最近更新 更多