arklad
arklad

Reputation: 91

Cannot resolve bean in SpEL for Spring Data MongoDB collection name

I am trying to customize the collection name where an entity class is saved into and indexed, using Spring Data MongoDB and Spring Batch. The class is declared as follows:

@Document
@CompoundIndex(name = "unique_source", def = "{'fid': 1, 'sid': 1}", unique = true, background = true)
public class VariantSource {
    ...
}

And the item writer:

public class VariantSourceMongoWriter extends MongoItemWriter<VariantSource> {

    public VariantSourceEntityMongoWriter(MongoOperations mongoOperations, String collectionName) {
        setTemplate(mongoOperations);
        setCollection(collectionName);
    }
}

Saving works fine: the objects are written into the collection provided as argument. The problem is that the indexes are created in the default collection, named after the class name (variantSource).

After reading this and this, I created the following:

public class MongoCollections {

    public String getCollectionFilesName() {
        return "my_custom_collection_name"; // TODO Dynamic value
    }
}


@Configuration
public class MongoCollectionsConfiguration {

    @Bean
    public MongoCollections mongoCollections() {
        return new MongoCollections(); 
    }


@RunWith(SpringRunner.class)
@ContextConfiguration(classes = {MongoCollectionsConfiguration.class})
public class VariantSourceMongoWriterTest {

    @Autowired
    private MongoCollections mongoCollections;

}

I have checked the instance is correctly autowired into the unit tests, but I can't make it work with SpEL.

After changing the @Document annotation to look like this:

@Document(collection = "#{@mongoCollections.getCollectionFilesName()}")

the following exception is thrown:

org.springframework.expression.spel.SpelEvaluationException: EL1057E:(pos 1): No bean resolver registered in the context to resolve access to bean 'mongoCollections'

And if I use this:

@Document(collection = "#{mongoCollections.getCollectionFilesName()}")

the exception is this one:

org.springframework.expression.spel.SpelEvaluationException: EL1007E:(pos 0): Property or field 'mongoCollections' cannot be found on null

Finally, the following creates a collection with the name as specified, symbols included:

@Document(collection = "@mongoCollections.getCollectionFilesName()")

Upvotes: 9

Views: 4572

Answers (3)

Raphael
Raphael

Reputation: 552

I was able to get my @Document tag to access a bean by simply changing my MongoTemplate configuration file.

Previously, I had it set up like this:

@Configuration
public class MongoTemplateConfiguration {

    ...

    @Bean
    public MongoTemplate mongoTemplate() {
        ...
        return new MongoTemplate(...);
    }
}

Changing it to follow this (3.2 Java Configuration) format was all I needed in order to remove the "bean resolver" error:

@Configuration
public class MongoTemplateConfiguration extends AbstractMongoClientConfiguration {

    ...

    @Override
    @Bean
    public com.mongodb.client.MongoClient mongoClient() {
        MongoClientSettings settings = ...;
        return MongoClients.create(settings);
    }
}

Upvotes: 0

Felipe Tapia
Felipe Tapia

Reputation: 369

Make sure that your bean mongoCollections is registered in the application context, and also correct the SpEL expression as below.

@Document(collection = "#{@mongoCollections.getCollectionFilesName()}")

Upvotes: 1

jmmut
jmmut

Reputation: 904

As pointed by this answer, to fix the injection:

@Document(collection = "#{mongoCollections.getCollectionFilesName()}") 

SpelEvaluationException: EL1007E:(pos 0): Property or field 'mongoCollections' cannot be found on null

(or a direct method bean: @Document(collection = "#{getCollectionFilesName}")), try setting the ApplicationContext into the MongoMappingContext (which is used to instantiate the MongoConverter, and later the MongoTemplate):

@Bean
public MongoMappingContext MongoMappingContext() {
    MongoMappingContext mappingContext = new MongoMappingContext();
    mappingContext.setApplicationContext(applicationContext);
    return mappingContext;
}

Upvotes: 5

Related Questions