maxi
maxi

Reputation: 369

Spring repository auto casts entities with different class types

I'm using MongoRepository interface to extend my custom repositories for different entities. Now I faced with problem, let's assume an example: I have 2 entities:

@Document(collection = "person")
public class Employee {
    private String position;
}

and

@Document(collection = "person")
public class Manager {
    private String major;
}

repositories for both:

@Repository
public interface ManagerRepository extends MongoRepository<Manager, String> {}

and

@Repository
public interface EmployeeRepository extends MongoRepository<Employee, String> {}

Everything goes well when I saving 2 models:

{
    "_id" : ObjectId("5541f988d4c603ebac18a147"),
    "_class" : "com.igmtechnology.gravity.core.init.test.Manager",
    "major" : "majority"
}
{
    "_id" : ObjectId("5541f988d4c603ebac18a148"),
    "_class" : "com.igmtechnology.gravity.core.init.test.Employee",
    "position" : "developer"
}

But when I'm doing findAll() from one of repositories I'm getting 2 objects and one of them spring is automatically casting to another one. How can avoid this auto casting? Or how can specify which class I need to get?

Upvotes: 7

Views: 2891

Answers (1)

Konstantin Yovkov
Konstantin Yovkov

Reputation: 62854

For both of the repositories, you can use the @Query annotation to specify a MongoDB JSON query string that will be used instead of query derived from the method's name (you must know that there's a convention for parsing the repository's method names and for building MongoDB queries).

So, by using @Query, you can do:

@Repository
public interface ManagerRepository extends MongoRepository<Employee, String>

  @Query(value="{ '_class' : 'com.igmtechnology.gravity.core.init.test.Manager' }")
  List<Person> findAllManagers();

}

Behind the scenes, this will generate a query, similar to this one:

db.person.findAll({'_class' ; 'com.igmtechnology.gravity.core.init.test.Manager'});

However, there's a minor problem with this code. If you change the fully-qualified class name of Manager, then the query would not throw a RuntimeException, but would return nothing. In this case you can use a wildcard within the @Query.

@Query(value="{ '_class' : ?0 }")
List<Person> findAllManagers(String className);

Then, when you invoke the method, you can just do:

managerRepository.findAllManagers(Manager.class.getName());

The provided Manager.class.getName() will replace the ?0 wildcard and your query will built properly.

Same goes for the Employee repository with the difference that you have to provide the fully-qualified class name of Employee in the @Query's value attribute.

More info:

Upvotes: 7

Related Questions