Search code examples
javaspringmongodbspring-data-mongodbspring-el

mongodb multi tenacy spel with @Document


This is related to MongoDB and SpEL Expressions in @Document annotations

This is the way I am creating my mongo template

@Bean
public MongoDbFactory mongoDbFactory() throws UnknownHostException {
    String dbname = getCustid();
    return new SimpleMongoDbFactory(new MongoClient("localhost"), "mydb");
}

@Bean
MongoTemplate mongoTemplate() throws UnknownHostException {
    MappingMongoConverter converter = 
            new MappingMongoConverter(mongoDbFactory(), new MongoMappingContext());
    return new MongoTemplate(mongoDbFactory(), converter);
}

I have a tenant provider class

@Component("tenantProvider")
public class TenantProvider {

    public String getTenantId() {
      --custome Thread local logic for getting a name
    }
}

And my domain class

    @Document(collection = "#{@tenantProvider.getTenantId()}_device")
     public class Device {
    -- my fields here
    }

As you see I have created my mongotemplate as specified in the post, but I still get the below error

Exception in thread "main" org.springframework.expression.spel.SpelEvaluationException: EL1057E:(pos 1): No bean resolver registered in the context to resolve access to bean 'tenantProvider'

What am I doing wrong?


Solution

  • Finally figured out why i was getting this issue.

    When using Servlet 3 initialization make sure that you add the application context to the mongo context as follows

        @Autowired
    private ApplicationContext appContext;
    
    public MongoDbFactory mongoDbFactory() throws UnknownHostException {
        return new SimpleMongoDbFactory(new MongoClient("localhost"), "apollo-mongodb");
    }
    
    @Bean
    MongoTemplate mongoTemplate() throws UnknownHostException {
        final MongoDbFactory factory = mongoDbFactory();
    
        final MongoMappingContext mongoMappingContext = new MongoMappingContext();
        mongoMappingContext.setApplicationContext(appContext);
    
        // Learned from web, prevents Spring from including the _class attribute
        final MappingMongoConverter converter = new MappingMongoConverter(factory, mongoMappingContext);
        converter.setTypeMapper(new DefaultMongoTypeMapper(null));
    
        return new MongoTemplate(factory, converter);
    }
    

    Check the autowiring of the context and also mongoMappingContext.setApplicationContext(appContext);

    With these two lines i was able to get the component wired correctly to use it in multi tenant mode