Java 仅为一个字段写入Mongo转换器

Java 仅为一个字段写入Mongo转换器,java,mongodb,spring-data,Java,Mongodb,Spring Data,我有一个简单的POJO,其中有一个长字段,实际上是一个时间戳 此字段必须位于由ISODate表示的mongo数据库中 我可以为整个Pojo编写一个转换器,但由于25个字段中只有一个字段没有多大意义,而且当一个字段发生更改或添加了一个字段时,这是另一个错误点 是否有一种方法可以调用默认转换器服务,并在默认转换服务之后更改另外两个,这将对性能产生很大影响。 或者是否有要覆盖的默认转换器接口 这里的最佳做法是什么 也许有一个注释我可以应用到这个领域 是的,我也可以写一个长脚转换器,但这会影响所有的PO

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

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

我可以为整个Pojo编写一个转换器,但由于25个字段中只有一个字段没有多大意义,而且当一个字段发生更改或添加了一个字段时,这是另一个错误点

是否有一种方法可以调用默认转换器服务,并在默认转换服务之后更改另外两个,这将对性能产生很大影响。 或者是否有要覆盖的默认转换器接口

这里的最佳做法是什么

也许有一个注释我可以应用到这个领域

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

下面是示例POJO:

public class Person {
   private long someTimestamp;
//getters and setters
}
如果没有转换器,这看起来是这样的:

{
    "_id" : ObjectId("52ae8eede4b0249cde22059e"),
    "someTimestamp" : NumberLong(1392714950940)
}
结果应该是这样的:

{
    "_id" : ObjectId("52ae8eede4b0249cde22059e"),
    "someTimestamp" : ISODate("2013-12-23T23:00:00.000Z")
}
如果exmaple的嵌套文档中有这样一个TIMESTAMP值,则描述的问题会变得更加复杂:

{
    "_id" : ObjectId("52ae8eede4b0249cde22059e"),
    "items" : [
        "someTimestamp" : NumberLong(1392714950940)
    ]
}
POJO:

公共类人物{
私人收藏物品;
//接球手和接球手
}

也许我应该提到,我正在使用Spring来实现这一点。()

不能仅为一个类定义
转换器。但在morphia将数据映射回类之前,您可以使用
@PreLoad
对数据进行处理:

    @PreLoad
    void convertDate(final DBObject dbObject) {
        dbObject.put("someTimestamp", new Date(dbObject.get("someTimestamp")));
    }
有效果的东西应该能满足你的需要。这种方法有一些缺点

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

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

    听起来您需要注释驱动的转换。第6.6.2节讨论了格式化程序,甚至有一个带有时间戳的示例

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


    问题是我刚刚尝试了这个,但无法让它工作,因为元数据正在丢失。我已经提交了一份报告,看看是否有办法解决这个问题。

    解决方案之一是使用spring data mongodb listener:

    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();
            }
        }
    }
    
    package com.rc.user.auth.model.listener;
    导入com.mongodb.DBObject;
    导入com.nimbusds.jwt.JWTParser;
    导入com.rc.user.auth.model.OAuth2AccessTokenEntity;
    导入org.springframework.data.mongodb.core.mapping.event.AbstractMongoEventListener;
    导入org.springframework.data.mongodb.core.mapping.event.AfterConvertEvent;
    导入org.springframework.data.mongodb.core.mapping.event.BeforeSaveEvent;
    导入org.springframework.stereotype.Component;
    导入java.text.ParseException;
    @组成部分
    公共类OAuth2AccessTokenEntityListener扩展了AbstractMongoEventListener{
    @凌驾
    公共void onBeforeSave(beforesavevent事件){
    OAuth2AccessTokenEntity oat=event.getSource();
    DBObject db=event.getDBObject();
    put(“tokenValue”,oat.getJwt().serialize());
    }
    @凌驾
    AfterConvert上的公共无效(AfterConvertEvent事件){
    OAuth2AccessTokenEntity oat=event.getSource();
    DBObject db=event.getDBObject();
    试一试{
    setJwt(JWTParser.parse(db.get(“tokenValue”).toString());
    }捕获(解析异常){
    e、 printStackTrace();
    }
    }
    }
    
    解决方案二是使用变频器:

    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();
        }
    }
    
    package com.rc.user.auth.model.convert;
    进口com.nimbusds.jwt.jwt;
    导入org.springframework.core.convert.converter.converter;
    导入org.springframework.data.convert.WritingConverter;
    @写转换器
    公共类JWTToString Converter实现转换器{
    @凌驾
    公共字符串转换(JWT-JWT){
    返回jwt.serialize();
    }
    }
    
    从Spring Data MongoDB 3.2开始,似乎无法轻松定义特定于字段(而非全局)的类型转换器

    配置bean中的方法影响所有域对象

    但是您可以使用一个简单的变通方法,使用不同类型的字段和访问器方法(getter/setter)来完成您想要的

    公共类人物{
    @AccessType(AccessType.Type.FIELD)
    私有即时时间戳;
    公共长getTimestamp(){
    返回这个.timestamp.getEpochSecond();
    }
    公共无效设置时间戳(最终长ts){
    this.timestamp=瞬间秒(ts);
    }
    }
    
    在上面的代码中,MongoDB的持久性映射器将看到
    java.time.Instant
    type 字段和
    timestamp
    字段将映射到MongoDB中的
    Date
    ISODate
    )类型

    但是,其他Java程序将通过
    long
    类型访问
    Person.timestamp
    字段,因为getter和setter使用
    long
    类型

    尽管这种方法不太喜欢使用字段级注释(如果存在),但它简单直观

    是Java8之后日期/时间的基本类之一。它似乎最适合f
    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();
        }
    }