简体   繁体   中英

Spring boot mongodb auditing error

I'm trying to configure mongodb auditing in my spring boot app, and I having this error when trying to persist my domain class:

java.lang.IllegalArgumentException: Couldn't find PersistentEntity for type class com.example.hateoasapi.domain.Post!

Docs from here https://docs.spring.io/spring-data/mongodb/docs/current/reference/html/#auditing says that all this configs enough, but I don't know why it doesn't work in my project. Could someone help me?

My mongodb config class:

    package com.example.hateoasapi.config;


import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.config.AbstractMongoConfiguration;
import org.springframework.data.mongodb.config.EnableMongoAuditing;
import org.springframework.data.mongodb.core.MongoTemplate;

import com.mongodb.MongoClient;
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;

import java.util.Collection;
import java.util.Collections;


@Configuration
@EnableMongoAuditing
@EnableMongoRepositories(value = "com.example.hateoasapi.repository")
public class MongoConfig extends AbstractMongoConfiguration {

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

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

    @Value("${spring.data.mongodb.port}")
    private Integer databasePort;

    @Override
    protected String getDatabaseName() {
        return this.databaseName;
    }

    @Bean
    @Override
    public MongoClient mongoClient() {
        return new MongoClient(databaseHost, databasePort);
    }

    @Bean
    public MongoTemplate mongoTemplate() {
        return new MongoTemplate(mongoClient(), databaseName);
    }

    @Override
    protected Collection<String> getMappingBasePackages() {
        return Collections.singleton("com.example.hateoasapi.domain");
    }
}

AuditorAware implementation:

package com.example.hateoasapi.config;


import com.example.hateoasapi.domain.User;
import org.springframework.data.domain.AuditorAware;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;

import java.util.Optional;

@Component
public class SecurityAuditor implements AuditorAware<User> {

    @Override
    public Optional<User> getCurrentAuditor() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();

        if (authentication == null || !authentication.isAuthenticated()) {
            return null;
        }

        return Optional.of((User) authentication.getPrincipal());
    }
}

And my domain class:

package com.example.hateoasapi.domain;

import javax.persistence.Id;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;

import org.joda.time.DateTime;
import org.springframework.data.annotation.CreatedBy;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.mongodb.core.mapping.DBRef;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.Field;
import org.springframework.hateoas.ResourceSupport;
import com.fasterxml.jackson.annotation.JsonCreator;

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

import static org.springframework.hateoas.mvc.ControllerLinkBuilder.*;

import java.io.Serializable;
import java.util.List;

import com.example.hateoasapi.controller.*;

@Getter
@Setter
@ToString
@Document
public class Post extends ResourceSupport implements Serializable {

    @Id
    @Field(value = "_id")
    private String objectId;

    @DBRef
    private List<Comment> comments;

    @DBRef
    private User author;

    @NotBlank
    private String body;

    @NotBlank
    private String title;

    private String categoryId;

    @NotEmpty(message = "Tags cannot be empty")
    private List<PostTag> tags;

    @CreatedDate
    private DateTime createdDate;

    @LastModifiedDate
    private DateTime lastModifiedDate;

    @CreatedBy
    private User createdBy;

    private Long views;    
    private List<PostRating> likes;
    private List<PostRating> dislikes;


    @JsonCreator
    public Post() {}

    public Post(String title, String body) {
        this.body = body;
        this.title = title;
    }

    public Post(User author, String body, String title, String categoryId, List<PostTag> tags) {
        this.author = author;
        this.body = body;
        this.title = title;
        this.categoryId = categoryId;
        this.tags = tags;
    }

    public void addLinks() {
        this.add(linkTo(methodOn(PostController.class).getAllPosts(null)).withSelfRel());
    }
}

I solved this issue with the next configuration:

@Configuration
@EnableMongoRepositories(basePackages = "YOUR.PACKAGE")
@EnableMongoAuditing
public class MongoConfig extends AbstractMongoConfiguration {

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

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

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

    @Override
    public MongoClient mongoClient() {
        return new MongoClient(host, port);
    }

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

    @Bean
    public MongoTemplate mongoTemplate() throws Exception {
        return new MongoTemplate(mongoDbFactory(), mappingMongoConverter());
    }

    @Bean
    public MongoDbFactory mongoDbFactory() {
        return new SimpleMongoDbFactory(mongoClient(), database);
    }
}

just add the bean for MongoTemplate with the constructor of MongoTemplate(MongoDbFactory mongoDbFactory, @Nullable MongoConverter mongoConverter)

Quoting from JIRA ticket

You need to pipe the MappingMongoConverter that's available in the environment into MongoTemplate as well, ie use new MongoTemplate(dbFactory, converter). The constructor you use is for convenience, one-off usages. We usually recommend to use AbstractMongoConfiguration in case you'd like to customize anything MongoDB specific as this makes sure the components are wired together correctly.

More specifically, you need to inject pre-configured MappingMongoConverter or if you need to use your own converter, at least use pre-configured MongoMappingContext.

I had this problem also with spring boot 2.2 I had both @EnableMongoRepositories and @EnableMongoAuditing as configuration and i got the error Couldn't find PersistentEntity for type class

the problem in my case was the structure of the packages: Application class was a level lower than part of my model that used auditing.

I found on many forum posts that the 2 annotations are not compatible together in spring 2.2, but after restructuring the packages I was able to use both with success in spring boot 2.2

If you use the last version of Spring boot (2.0) and Spring Data, @EnableMongoAuditing @EnableMongoRepositories are not compatible. It's the same with EnableReactiveMongoRepositories annotation.

If you want to enable mongo auditing, you need to remove your MongoConfig class, use config file to define your mongodb connection and everything will work.

If you use the last version of Spring boot (2.0) and Spring Data, @EnableMongoAuditing and @EnableMongoRepositories, try remove @EnableMongoRepositories. It should be working just this sample project - https://github.com/hantsy/spring-reactive-sample/tree/master/boot-data-mongo

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM