mongodb - Spring Data MongoDB - 持久化列表时出现类转换异常

标签 mongodb spring-batch spring-data-mongodb

我正在使用 Spring-Batch 和 MongoDbWriter。

所以我们使用 Spring-Data-MongoDB,当调用 ItemWriter 时抛出 Class-Cast-Exception:

 10:40:13.795 [jobLauncherTaskExecutor-1] DEBUG o.s.b.c.r.dao.JdbcJobExecutionDao - Truncating long message before update of JobExecution: JobExecution: id=0, version=1, startTime=Wed Jun 17 10:40:01 CEST 2015, endTime=Wed Jun 17 10:40:13 CEST 2015, lastUpdated=Wed Jun 17 10:40:13 CEST 2015, status=FAILED, exitStatus=exitCode=FAILED;exitDescription=java.lang.ClassCastException: com.mongodb.BasicDBObject cannot be cast to com.mongodb.BasicDBList
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.writeInternal(MappingMongoConverter.java:384)
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.write(MappingMongoConverter.java:353)
    at org.springframework.data.mongodb.core.convert.MappingMongoConverter.write(MappingMongoConverter.java:78)
    at org.springframework.data.mongodb.core.MongoTemplate.toDbObject(MongoTemplate.java:809)
    at org.springframework.data.mongodb.core.MongoTemplate.doSave(MongoTemplate.java:962)
    at org.springframework.data.mongodb.core.MongoTemplate.save(MongoTemplate.java:911)
    at org.springframework.batch.item.data.MongoItemWriter.doWrite(MongoItemWriter.java:128)
    at org.springframework.batch.item.data.MongoItemWriter$1.beforeCommit(MongoItemWriter.java:156)
    at org.springframework.transaction.support.TransactionSynchronizationUtils.triggerBeforeCommit(TransactionSynchronizationUtils.java:95)
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.triggerBeforeCommit(AbstractPlatformTransactionManager.java:928)
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:740)
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:726)
    at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:150)
    at org.springframework.batch.core.step.tasklet.TaskletStep$2.doInChunkContext(TaskletStep.java:271)
    at org.springframework.batch.core.scope.context.StepContextRepeatCallback.doInIteration(StepContextRepeatCallback.java:77)
    at org.springframework.batch.repeat.support.RepeatTemplate.getNextResult(RepeatTemplate.java:368)
    at org.springframework.batch.repeat.support.RepeatTemplate.executeInternal(RepeatTemplate.java:215)
    at org.springframework.batch.repeat.support.RepeatTemplate.iterate(RepeatTemplate.java:144)
    at org.springframework.batch.core.step.tasklet.TaskletStep.doExecute(TaskletStep.java:257)
    at org.springframework.batch.core.step.AbstractStep.execute(AbstractStep.java:198)
    at org.springframework.batch.core.job.SimpleStepHandler.handleStep(SimpleStepHandler.java:148)
    at org.springframework.batch.core.job.AbstractJob.handleStep(AbstractJob.java:386)
    at org.springframework.batch.core.job.SimpleJob.doExecute(SimpleJob.java:135)
    at org.springframework.batch.core.job.AbstractJob.execute(AbstractJob.java:304)
    at org.springframework.batch.core.launch.support.SimpleJobLauncher$1.run(SimpleJobLauncher.java:135)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:745)
, job=[JobInstance: id=0, version=0, Job=[NBO.READER.]], jobParameters=[{}]

我们使用 spring-data-mongodb-1.7.0.RELEASE,但我认为有一个错误:

MongoTemplate 中的“doSave”方法调用 toDbObject,此方法始终返回一个 BasicDBObject,除了它是一个字符串。所以当我保存一个列表时,这个方法返回一个 BasicDBObject...

    private <T> DBObject toDbObject(T objectToSave, MongoWriter<T> writer) {

        if (!(objectToSave instanceof String)) {
            DBObject dbDoc = new BasicDBObject();
            writer.write(objectToSave, dbDoc);
            return dbDoc;
        } else {
            try {
                return (DBObject) JSON.parse((String) objectToSave);
            } catch (JSONParseException e) {
                throw new MappingException("Could not parse given String to save into a JSON document!", e);
            }
        }
    }

在此之后,MappingMongoConverter的write()方法被调用并抛出异常,因为:

    if (!handledByCustomConverter && !(dbo instanceof BasicDBList)) {
                typeMapper.writeType(type, dbo);
            }

但它不是 BasicDBList,因为 toDbObject-Method。 然后调用 writeInternal-Method 并在那里:

if (Collection.class.isAssignableFrom(entityType)) {
            writeCollectionInternal((Collection<?>) obj, ClassTypeInformation.LIST, (BasicDBList) dbo);
            return;
        }

这让繁荣^^

好像是toDbObject-Method不对?这是一个错误吗?

问候

最佳答案

解决方法是覆盖 MongoTemplate 类:

public class MongoHack extends MongoTemplate
{

    public MongoHack(MongoDbFactory mongoDbFactory)
    {
        super(mongoDbFactory);
        // TODO Auto-generated constructor stub
    }

    @Override
    protected <T> void doSave(String collectionName, T objectToSave, MongoWriter<T> writer)
    {

        this.assertUpdateableIdIfNotSet(objectToSave);

        maybeEmitEvent(new BeforeConvertEvent<T>(objectToSave));

        DBObject dbDoc = this.toDbObject(objectToSave, writer);

        maybeEmitEvent(new BeforeSaveEvent<T>(objectToSave, dbDoc));
        Object id = saveDBObject(collectionName, dbDoc, objectToSave.getClass());

        populateIdIfNecessary(objectToSave, id);
        maybeEmitEvent(new AfterSaveEvent<T>(objectToSave, dbDoc));
    }

    private void assertUpdateableIdIfNotSet(Object entity)
    {

        MongoPersistentEntity<?> persistentEntity = super.getConverter().getMappingContext()
                .getPersistentEntity(entity.getClass());
        MongoPersistentProperty idProperty = persistentEntity == null ? null : persistentEntity.getIdProperty();

        if (idProperty == null || persistentEntity == null) {
            return;
        }

        Object idValue = persistentEntity.getPropertyAccessor(entity).getProperty(idProperty);

        if (idValue == null && !MongoSimpleTypes.AUTOGENERATED_ID_TYPES.contains(idProperty.getType())) {
            throw new InvalidDataAccessApiUsageException(String.format(
                    "Cannot autogenerate id of type %s for entity of type %s!", idProperty.getType().getName(), entity
                            .getClass().getName()));
        }
    }

    private <T> DBObject toDbObject(T objectToSave, MongoWriter<T> writer)
    {

        if (Collection.class.isAssignableFrom(objectToSave.getClass())) {
            DBObject dbDoc = new BasicDBObject();
            Collection<T> objects = (Collection<T>) objectToSave;
            Iterator<T> iterator = objects.iterator();
            while(iterator.hasNext()) {
                writer.write(iterator.next(), dbDoc);
            }
            return dbDoc;
        }

        else if (!(objectToSave instanceof String)) {
            DBObject dbDoc = new BasicDBObject();
            writer.write(objectToSave, dbDoc);
            return dbDoc;

        }

        else {
            try {
                return (DBObject) JSON.parse((String) objectToSave);
            }
            catch (JSONParseException e) {
                throw new MappingException("Could not parse given String to save into a JSON document!", e);
            }
        }
    }

}

这对我有用......但我不知道这是否是一个有用的用例?

关于mongodb - Spring Data MongoDB - 持久化列表时出现类转换异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30889689/

相关文章:

java - 使用 spring-data-mongodb 流式传输聚合操作的结果

java - 重新注入(inject) Spring Autowired 依赖项

mongodb - 使用 MongoDB,有什么简单的方法可以重用 Map/Reduce 结果?

node.js - 无法从 mongojs 连接,但命令行正常

java - 如何从 spring 批处理器 process() 方法向 Spring 批处理作业启动方法抛出异常?

java - Spring Data Mongo 找不到 Enum 的 PersistentEntity

mongodb - Golang Mongodb %!(额外

javascript - 如何在MongoDB中存储和区分数据?

spring-batch - 如何设计 spring batch 来避免请求排长队和重启失败的作业

spring.job.启用: true causing junit jobs to run twice