只为一个字段编写一个Mongo Converter

Zar*_*tra 12 java mongodb spring-data

我有一个案例,我有一个简单的POJO,其中有一个长字段,实际上是一个时间戳.

该字段必须位于由ISODate表示的mongo数据库中.

我可以在整个Pojo中编写一个转换器,但由于它只有25个中的一个字段没有多大意义,并且当字段发生变化或者另外一个被添加时,它是另一个错误点.

有没有办法在默认转换服务之后调用默认转换器服务并更改另外两个服务,这将对性能产生很大影响.或者是否有一个默认的Converter接口来覆盖?

什么是最好的做法?

也许有一个注释可以应用于这个领域?

是的,我也可以写一个LongToDate转换器,但这会影响所有POJO,而不仅仅是这一个.

这里的样本POJO:

public class Person {
   private long someTimestamp;
//getters and setters
}
Run Code Online (Sandbox Code Playgroud)

没有转换器,这将是这样的:

{
    "_id" : ObjectId("52ae8eede4b0249cde22059e"),
    "someTimestamp" : NumberLong(1392714950940)
}
Run Code Online (Sandbox Code Playgroud)

那个结果应该是这样的:

{
    "_id" : ObjectId("52ae8eede4b0249cde22059e"),
    "someTimestamp" : ISODate("2013-12-23T23:00:00.000Z")
}
Run Code Online (Sandbox Code Playgroud)

当这样的时间戳值在嵌套文档中时,所描述的问题变得更加复杂:

{
    "_id" : ObjectId("52ae8eede4b0249cde22059e"),
    "items" : [
        "someTimestamp" : NumberLong(1392714950940)
    ]
}
Run Code Online (Sandbox Code Playgroud)

POJO:

public class Person {
   private Collection<OtherPojoThatHoldsTimestamps> items;
//getters and setters
}
Run Code Online (Sandbox Code Playgroud)

也许我应该提到我使用Spring来实现这一目标.(http://projects.spring.io/spring-data-mongodb/)

Eme*_*gia 5

听起来你需要注释驱动的转换.参考手册中的6.6.2节对格式化器进行了讨论,甚至还有一个带时间戳的例子.

一般的想法是,你要标记需要使用注释进行特殊处理的字段(这是一个很好的注释使用,你毕竟指定了元数据).然后,您将为具有该注释的字段注册转换器.

问题是我刚试过这个并且无法使它工作,因为元数据正在丢失.我已经提交了一张JIRA票,看看是否有解决方法.


jam*_*lee 5

解决方案一是使用 spring data mongodb 监听器:

package com.rc.user.auth.model.listener;

import com.mongodb.DBObject;
import com.nimbusds.jwt.JWTParser;
import com.rc.user.auth.model.OAuth2AccessTokenEntity;
import org.springframework.data.mongodb.core.mapping.event.AbstractMongoEventListener;
import org.springframework.data.mongodb.core.mapping.event.AfterConvertEvent;
import org.springframework.data.mongodb.core.mapping.event.BeforeSaveEvent;
import org.springframework.stereotype.Component;

import java.text.ParseException;

@Component
public class OAuth2AccessTokenEntityListener extends AbstractMongoEventListener<OAuth2AccessTokenEntity> {

    @Override
    public void onBeforeSave(BeforeSaveEvent<OAuth2AccessTokenEntity> event) {
        OAuth2AccessTokenEntity oat = event.getSource();
        DBObject db = event.getDBObject();

        db.put("tokenValue", oat.getJwt().serialize());
    }

    @Override
    public void onAfterConvert(AfterConvertEvent<OAuth2AccessTokenEntity> event) {

        OAuth2AccessTokenEntity oat = event.getSource();
        DBObject db = event.getDBObject();

       try {
          oat.setJwt(JWTParser.parse(db.get("tokenValue").toString()));
      } catch (ParseException e) {
          e.printStackTrace();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

解决方案二是使用转换器:

package com.rc.user.auth.model.convert;

import com.nimbusds.jwt.JWT;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.convert.WritingConverter;


@WritingConverter
public class JWTToStringConverter implements Converter<JWT, String> {

    @Override
    public String convert(JWT jwt) {
        return jwt.serialize();
    }
}
Run Code Online (Sandbox Code Playgroud)


eva*_*oly 0

你不能Converter只为一个类定义 a 。但您可以在@PreLoad吗啡将其映射回您的类之前对这些数据进行处理:

    @PreLoad
    void convertDate(final DBObject dbObject) {
        dbObject.put("someTimestamp", new Date(dbObject.get("someTimestamp")));
    }
Run Code Online (Sandbox Code Playgroud)

一些有效的东西应该能让你得到你所需要的。这种方法有一些缺点。

  1. 您必须针对您发现自己处于这种情况的每个领域执行此操作。因此,上面的“items”示例在方法中需要类似的代码@PreLoad。希望这种情况不会经常发生,因此不会造成太大负担。
  2. 这是一个惰性转换。如果您的查询依赖于日期属性,它们将找不到尚未转换的记录。一种解决方案是通过吗啡简单地加载/保存每个项目。除非您对对象进行版本控制,否则这可能会破坏对这些文档的其他写入。或者您可以编写一些 javascript 在 shell 中运行来加载这些文档、创建一个新日期并简单地将 $set 返回到该字段。(当然,您也可以使用吗啡和一些低级 java 驱动程序代码执行类似的操作)。这些解决方案中的任何一个如果没有启用版本控制,都可能需要一些停机时间,具体取决于您的应用程序及其使用情况。

希望这能让您朝着正确的方向开始。祝你好运。