Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Couldn't find PersistentEntity for type class when using @EnableMongoAuditing

I am getting "Couldn't find PersistentEntity for type class" error when I am using @EnableMongoAuditing features along with MongoRepository. This happens when I save a document when collection isn't already present in database.

I tried whatever is mentioned in:

  • https://github.com/spring-projects/spring-boot/issues/12023
  • https://jira.spring.io/browse/DATAMONGO-1999
  • Spring boot mongodb auditing error

but nothing is working.

Mentioned things are:

Extend MongoConfig by AbstractMongoConfiguration and override all methods.

Here is my code which reproduced the same error:

MongoConfig class

@Configuration
public class MongoConfig extends AbstractMongoConfiguration {

    @Value("${spring.data.mongodb.host}")
    private String mongoHost;

    @Value("${spring.data.mongodb.port}")
    private String mongoPort;

    @Value("${spring.data.mongodb.database}")
    private String mongoDB;

    @Override
    public MongoDbFactory mongoDbFactory() {
        return new SimpleMongoDbFactory(new MongoClient(mongoHost + ":" + mongoPort), mongoDB);
    }

    @Override
    public MongoClient mongoClient() {
        return new MongoClient(mongoHost, Integer.parseInt(mongoPort));
    }

    @Override
    public MongoTemplate mongoTemplate() {
        return new MongoTemplate(mongoDbFactory());
    }

    @Override
    public MappingMongoConverter mappingMongoConverter() {
        return new MappingMongoConverter(new DefaultDbRefResolver(mongoDbFactory()), new MongoMappingContext());
    }

    @Override
    protected String getDatabaseName() {
        return mongoDB;
    }
}

Person Collection class

@Document
public class Person {
    @Id
    private String id;

    private String name;

    @CreatedDate
    private LocalDateTime createdAt;
    @LastModifiedDate
    private LocalDateTime lastModified;
    // Getter Setters Constructors omitted for brevity
}

Main Application class

@EnableMongoAuditing
@EnableMongoRepositories ({"com.example.*", "org.apache.*"})
@SpringBootApplication
@ComponentScan({"com.example.*", "org.apache.*"})
public class DemoApplication implements CommandLineRunner {

    @Autowired
    PersonRepository personRepository;
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

    @Override
    public void run(String... args) throws Exception {
        Person p1 = new Person("1", "prakhar");
        personRepository.save(p1);

    }
}

Expected Result is Person entity should be saved in database. Actual Result is "Couldn't find PersistentEntity for type class Person" error

like image 746
prakharjainril Avatar asked Apr 30 '19 07:04

prakharjainril


People also ask

How to enable Mongo auditing in MongoDB using mongoclient?

@Configuration @EnableMongoAuditing public class AnyConfig {} You should write a configuration class in which you can connect to MongoDB database using mongoClient by passing db url. and add the anootaion of @EnableMongoAuditing on top of that class.

Is there a @enablemongoauditing annotation for spring data?

In the new upcoming release (1.4.0) there is an @EnableMongoAuditing annotation. But currently you are bound to the xml configuration. Just noticed in the GIT commit logs that the new release train for Spring Data is being released. There should be a Spring Data MongoDB 1.4.0.RELEASE out shortly, which contains said annotation.

How to handle zoneddatetime objects in MongoDB?

We can handle ZonedDateTime objects (across all models) by defining a converter for reading from a MongoDB and one for writing into it. For reading, we're converting from a Date object into a ZonedDateTime object. In the next example, we use the ZoneOffset.UTC since Date object does not store zone information:

Where does the mongoconfiguration class is used?

Where does the MongoConfiguration class is used? The annotation @Configuration says that the class is configration similar as XML but in Java code. You can have many configuration classes just put packageScan to package there configuration classes are.


1 Answers

Looks like you ran into https://github.com/spring-projects/spring-boot/issues/12023

Extending AbstractMongoConfiguration will switch off Spring Boot's auto-configuration of various Mongo components and also customises the base packages that are used to scan for mappings. I would recommend that you don't use it in Spring Boot.

Update

I managed to get the example running with the configuration as simple as

@Configuration
public class MongoConfig {

    @Value("${spring.data.mongodb.host}")
    private String mongoHost;

    @Value("${spring.data.mongodb.port}")
    private String mongoPort;

    @Value("${spring.data.mongodb.database}")
    private String mongoDB;

    @Bean
    public MongoDbFactory mongoDbFactory() {
        return new SimpleMongoDbFactory(new MongoClient(mongoHost + ":" + mongoPort), mongoDB);
    }

    @Bean
    public MongoClient mongoClient() {
        return new MongoClient(mongoHost, Integer.parseInt(mongoPort));
    }
}

and the app class

@EnableMongoAuditing
@SpringBootApplication
public class DemoApplication implements CommandLineRunner {

    @Autowired
    PersonRepository personRepository;
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

    @Override
    public void run(String... args) throws Exception {
        Thread.sleep(2000);
        Person p1 = new Person("1", "prakhar");
        personRepository.save(p1);

    }
}

Notice that I followed my own advice and did't inherit from AbstractMongoConfiguration

Explaination

The problem lies in the initialization of

 @Bean
 public MappingMongoConverter mappingMongoConverter() {
     return new MappingMongoConverter(new DefaultDbRefResolver(mongoDbFactory()), new MongoMappingContext());
}

You simply call MongoMappingContext constructor, without calling setInitialEntitySet. Compare that with MongoDataConfiguration auto-configuration class.

@Bean
@ConditionalOnMissingBean
public MongoMappingContext mongoMappingContext(MongoCustomConversions conversions)
        throws ClassNotFoundException {
    MongoMappingContext context = new MongoMappingContext();
    context.setInitialEntitySet(new EntityScanner(this.applicationContext)
            .scan(Document.class, Persistent.class));
    Class<?> strategyClass = this.properties.getFieldNamingStrategy();
    if (strategyClass != null) {
        context.setFieldNamingStrategy(
                (FieldNamingStrategy) BeanUtils.instantiateClass(strategyClass));
    }
    context.setSimpleTypeHolder(conversions.getSimpleTypeHolder());
    return context;
}

Even worse, you don't register MongoMappingContext as a managed bean. Due to this fact, auto-configuration class is still created. This leads to a race condition, I tried to run the original code and could easily reproduce the error, but with a breakpoint in AbstractMappingContext.addPersistentEntity the test always passed.

like image 63
Lesiak Avatar answered Oct 03 '22 23:10

Lesiak