Spring Boot & Data Repositories - fragment implementation x does not implement x - spring

I upgraded from Spring Boot v.1.5.8 to v.2.1.5. When I try to start the application I get the following error:
IllegalArgumentException: Fragment implementation .OtmUniParentRepository2019GeneratedImpl$$EnhancerBySpringCGLIB$$cdf9e294 does not implement x.OtmUniParentRepository2019Generated!
Why I can't start it anymore?
The files:
OtoUniChildRepository2019
#RepositoryRestResource(collectionResourceRel = "OtoUniChild2019", path = "OtoUniChild2019")
public interface OtoUniChildRepository2019 extends OtoUniChildRepository2019Generated {
}
#Transactional
class OtoUniChildRepository2019Impl extends HeartcoreRepositoryImpl<OtoUniChild> {
#PostConstruct
private void setIni() {
super.setIni(OtoUniChild.TABLENAME, OtoUniChild.getColumnName(), OtoUniChild.class, "AGRIDB2019");
}
}
OtoUniChildRepository2019Generated
public interface OtoUniChildRepository2019Generated extends HeartcoreRepository<OtoUniChild> {
OtoUniChild findByIdAndOtoUniParentIsNotNull(#Param("id") String id);
OtoUniChild findByOtoUniParentId(#Param("id") String id);
}
#Transactional
class OtoUniChildRepository2019GeneratedImpl extends HeartcoreRepositoryImpl<OtoUniChild> {
#PostConstruct
private void setIni() {
super.setIni(OtoUniChild.TABLENAME, OtoUniChild.getColumnName(), OtoUniChild.class, "AGRIDB2019");
}
}
HeartcoreRepository
#NoRepositoryBean
public interface HeartcoreRepository<T extends Heartcore> extends RevisionRepository<T, String, Integer>, PagingAndSortingRepository<T, String>, HeartcoreCustomRepository<T> {
#Override
T findOne(String id);
boolean existsById(String id);
#Override
Collection<T> findAll();
List<T> findAllByKanton(#Param("kanton") String kanton);
}
HeartcoreCustomRepository
public interface HeartcoreCustomRepository<T extends Heartcore> {
List<T> findCustom(String sqlQuery);
List<T> findCustom(String select, String where);
Class<T> getType();
T findOne(String id);
Collection<T> findAll();
String getSequence(String sequenceName);
}
HeartcoreCustomRepositoryImpl
#Transactional
public class HeartcoreRepositoryImpl<T extends Heartcore> implements HeartcoreCustomRepository<T> {
#PersistenceContext
protected EntityManager entityManager;
// irrelevant code
public void setIni(String tablename, List<String> columns, Class<T> type, String schema) {
this.tablename = tablename;
this.columns = columns;
this.type = type;
this.schema = schema;
MultitenantDataSource multitenantDataSource = (MultitenantDataSource) entityManager.getEntityManagerFactory().getProperties().get("hibernate.connection.datasource");
DataSource dataSource = (DataSource) multitenantDataSource.determineTargetDataSource();
try {
this.dbDriver = dataSource.getConnection().getMetaData().getDriverName();
}
catch (SQLException e) {
e.printStackTrace();
}
}
// irrelevant code
With 1.5.8 it works fine and I couldn't find infos about breaking changes.
EDIT: Is something wrong with this inheritance structure of the repositories? I tried some different approaches but none worked. Is there an other way to implement some basic functionality for repositories?

Related

How to ignore some parameter in JPA

I pass arguments to get data from database by JPA.
There are two arguments.
The first argument is ServiceType ; to switch database from Aspect (AOP)
The second argument is used to make query.
However there is org.springframework.data.jpa.repository.query.ParameterBinder.bind error
in conclusion, how to ignore the first(ServiceType) argument to make JPA query.
The code is like that.
#Repository
public interface BlogRepository extends JpaRepository<Blog, Integer> {
List<Blog> findByName(ServiceType serviceType, String name, Pageable pageable);
}
#Aspect
#Order(1)
#Component
public class MDBDecisionAspect {
private static ThreadLocal<ServiceType> localService = new ThreadLocal<>();
#Pointcut("execution(public * com.test.jpa.mdb..*.*(com.test.enums.ServiceType, ..))")
public void repositoryAspectTarget() {
}
#Around("repositoryAspectTarget()")
public Object initDaoService(ProceedingJoinPoint joinPoint) throws Throwable {
Object[] args = joinPoint.getArgs();
if (args[0] != null && ServiceType.class.equals(args[0].getClass())) {
setServiceType(((ServiceType) args[0]));
}
return joinPoint.proceed();
}
#AfterReturning("repositoryAspectTarget()")
public void afterInitDaoServiceReturningTargetMethod() {
setServiceType(null);
}
public static ServiceType getServiceType() {
return localService.get();
}
public static void setServiceType(ServiceType serviceType) {
localService.set(serviceType);
}
}
create a service class and call repository in it. So you can use serviceType inside service class.
#Repository
public interface BlogRepository extends JpaRepository<Blog, Integer> {
List<Blog> findByName(String name, Pageable pageable);
}
class BlogService{
public List<Blog> getListOfBlog(ServiceType st, String name){
blogRepository. findByName(name);
}
}
change aspect pointcut to check service class.

JUNIT - Null pointer Exception while calling findAll in spring Data JPA

I am new to Junits and Mockito, I am writing a Unit test class to test my service class CourseService.java which is calling findAll() method of CourseRepository.class which implements CrudRepository<Topics,Long>
Service Class
#Service
public class CourseService {
#Autowired
CourseRepository courseRepository;
public void setCourseRepository(CourseRepository courseRepository) {
this.courseRepository = courseRepository;
}
public Boolean getAllTopics() {
ArrayList<Topics> topicList=(ArrayList<Topics>) courseRepository.findAll();
if(topicList.isEmpty())
{
return false;
}
return true;
}
}
Repository class
public interface CourseRepository extends CrudRepository<Topics,Long>{
}
Domain class
#Entity
#Table(name="Book")
public class Topics {
#Id
#Column(name="Topicid")
private long topicId;
#Column(name="Topictitle",nullable=false)
private String topicTitle;
#Column(name="Topicauthor",nullable=false)
private String topicAuthor;
public long getTopicId() {
return topicId;
}
public void setTopicId(long topicId) {
this.topicId = topicId;
}
public String getTopicTitle() {
return topicTitle;
}
public void setTopicTitle(String topicTitle) {
this.topicTitle = topicTitle;
}
public String getTopicAuthor() {
return topicAuthor;
}
public void setTopicAuthor(String topicAuthor) {
this.topicAuthor = topicAuthor;
}
public Topics(long topicId, String topicTitle, String topicAuthor) {
super();
this.topicId = topicId;
this.topicTitle = topicTitle;
this.topicAuthor = topicAuthor;
}
}
Following is the Junit class I have written but courseRepository is getting initialized to NULL and hence I am getting NullPointerException.
public class CourseServiceTest {
#Mock
private CourseRepository courseRepository;
#InjectMocks
private CourseService courseService;
Topics topics;
#Mock
private Iterable<Topics> topicsList;
#Before
public void setUp() {
MockitoAnnotations.initMocks(CourseServiceTest.class);
}
#Test
public void test_Get_Topic_Details() {
List<Topics> topics = new ArrayList<Topics>();
Mockito.when(courseRepository.findAll()).thenReturn(topics);
boolean result=courseService.getAllTopics();
assertTrue(result);
}
}
Change the setUp() method to:
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
Probably you are dealing with some problem on the framework to make the mocked class be injected by the framework.
I recommend to use Constructor Injection, so you don't need to rely on the reflection and #Inject/#Mock annotations to make this work:
#Service
public class CourseService {
private final CourseRepository courseRepository;
// #Autowired annotation is optional when using constructor injection
CourseService (CourseRepository courseRepository) {
this.courseRepository = courseRepository;
}
// .... code
}
The test:
#Test
public void test_Get_Topic_Details() {
List<Topics> topics = new ArrayList<Topics>();
Mockito.when(courseRepository.findAll()).thenReturn(topics);
CourseService courseService = new CourseService(courseRepository);
boolean result = courseService.getAllTopics();
assertTrue(result);
}

Junit test for saving data with JPA

Am trying to make a junit test to save data with JPA. Below is my entity class
#Entity
#Table(name="book")
public class test {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name="BOOK_REF_ID",nullable=false)
private int bookRefId;
#Column(name="BOOK_CODE",nullable=false)
private String bookCode;
#Column(name="BOOK_NAME",nullable=false)
private String bookDescription;
public int getBookRefId() {
return bookRefId;
}
public void setBookRefId(int bookRefId) {
this.bookRefId = bookRefId;
}
public String getBookCode() {
return bookCode;
}
public void setBookCode(String bookCode) {
this.bookCode = bookCode;
}
public String getBookDescription() {
return bookDescription;
}
public void setBookDescription(String bookDescription) {
this.bookDescription = bookDescription;
}
}
Service class is
public interface BookService()
{
public Book create(Book book);
}
Repository class is
public interface BookRepository extends
JpaRepository<Book,Integer>
{ }
Service Implementation class is
public BookServiceImpli implements BookService()
{
#Resource
BookRepository repository;
#Override
public Book create(Book book) {
// TODO Auto-generated method stub
return repository.save(book);
}
}
Now my test class is
#RunWith(SpringRunner.class)
#DataJpaTest
#SpringBootTest(classes= {JPAConfig.class})
#AutoConfigureTestDatabase(replace=Replace.NONE)
#TestPropertySource(
locations = "classpath:application.properties")
public class TestBook {
#Autowired
private BookService bookService ;
#Test
public void test() {
Book book = new Book();
book.setBookCode("abc");
book.setBookDescription("safd");
bookService.create(book);
}
Application properties contains password and database details and JPAConfig contain JPA configuration details such as entity scan database details. When am trying to run the test case am getting an error like
A component required a bean of type
'com.repository.sample.BookRepository' that could not be found.
I don't have main method in it.Am new to unit testing please anyone help me to solve the issue.

How to get entityName or interface name in SpEL for generic repositories in PreAuthorize

I'd like to create a generic security crud repository and annotate each method with preauthorize, however I cannot get how to retrieve entity class name
#NoRepositoryBean
public interface AbstractEntityRepository<T extends AbstractEntity> extends CrudRepository<T, String> {
#Override
#PreAuthorize("hasPermission(null, #entityName, 'find');
Iterable<T> findAll();
}
public interface UserRepository extends AbstractEntityRepository<User> {}
in this case, entityName is always null.
#Component
#Log
public class CustomPermissionEvaluator implements PermissionEvaluator {
#Override
public boolean hasPermission(Authentication authentication, Serializable targetId, String targetType, Object permission)
log.fine("type " + targetType); // <- null
return true;
}
...
Any idea how to get either "User" or "UserRepository" ?
#Component
public class ClassTypeResolver {
public static String resolve(Object object) {
if (AopUtils.isJdkDynamicProxy(object)) {
try {
return ((SimpleJpaRepository) ((Advised)object).getTargetSource().getTarget()).getDomainClass().getCanonicalName();
} catch (Exception e) {
return null;
}
} else {
return ((SimpleJpaRepository) object).getDomainClass().getCanonicalName();
}
}
}

QueryDslMongoRepository for different collections

I am trying to implement a QueryDslMongoRepository for a model "Document"
#QueryEntity
#Document(collection="currentDocuments")
public class DocumentImpl extends TranslatableObjectImpl implements Document
In our current implementation a to be deleted document moves von "currentDocuments" into "deletedDocuments" collection.
I cant find a solution to create a repository like this
public interface DocumentRepository extends MongoRepository<DocumentImpl, String> ,QueryDslPredicateExecutor<DocumentImpl> {}
with a dynamic collection name.
My goal is to have the advantages of queryDsl in one Repository for different collections and to be able to move models from one collection into another like
public move(DocumentImpl entity, String sourceCollection, String targetCollection){
repository.delete(entity,sourceCollection);
repository.save(entity,targetCollection);
}
or something like
public List<Document> findAllDocumentsWithAttachments(String collectionName){
return repository.findAll(QDocumentImpl.documentImpl.attachments.isNotEmpty(), collectionName);
}
Any suggestions?
I implemented this feature by creating an own FactoryBean extending MongoRepositoryFactoryBean.
According to the Answer of this -> Question <- I implemeted following solution.
Entity
#QueryEntity
public class Document extends AbstractObject {
}
Custom QuerydslMongoRepository
public interface CustomQuerydslMongoRepository<T extends AbstractObject,ID extends Serializable> extends MongoRepository<T, ID> ,QueryDslPredicateExecutor<T>{
List<T> findAll(Predicate predicate, String collectionName);
T save(T entity, String collectionName);
...
}
Custom QuerydslMongoRepository Implementation
public class CustomQuerydslMongoRepositoryImpl<T extends AbstractObject,ID extends Serializable> extends QueryDslMongoRepository<T,ID> implements CustomQuerydslMongoRepository<T,ID> {
//All instance variables are available in super, but they are private
private static final EntityPathResolver DEFAULT_ENTITY_PATH_RESOLVER = SimpleEntityPathResolver.INSTANCE;
private final EntityPath<T> path;
private final PathBuilder<T> pathBuilder;
private final MongoOperations mongoOperations;
public CustomQuerydslMongoRepositoryImpl(MongoEntityInformation<T, ID> entityInformation, MongoOperations mongoOperations) {
this(entityInformation, mongoOperations,DEFAULT_ENTITY_PATH_RESOLVER);
}
public CustomQuerydslMongoRepositoryImpl(MongoEntityInformation<T, ID> entityInformation, MongoOperations mongoOperations, EntityPathResolver resolver) {
super(entityInformation, mongoOperations, resolver);
this.path=resolver.createPath(entityInformation.getJavaType());
this.pathBuilder = new PathBuilder<T>(path.getType(), path.getMetadata());
this.mongoOperations=mongoOperations;
}
#Override
public List<T> findAll(Predicate predicate, String collectionName) {
MongodbQuery<T> query = createQueryFor(predicate,collectionName);
return query.list();
}
#Override
public T save(T entity,String collectionName){
Assert.notNull(entity, "Entity must not be null!");
mongoOperations.save(entity, collectionName);
return entity;
}
private MongodbQuery<T> createQueryFor(Predicate predicate,String collectionName) {
Class<T> domainType = getEntityInformation().getJavaType();
MongodbQuery<T> query = new SpringDataMongodbQuery<T>(getMongoOperations(), domainType,collectionName);
return query.where(predicate);
}
}
Custom Repository Factory
public class CustomQueryDslMongodbRepositoryFactoryBean<R extends QueryDslMongoRepository<T, I>, T, I extends Serializable> extends MongoRepositoryFactoryBean<R, T, I> {
#Override
protected RepositoryFactorySupport getFactoryInstance(MongoOperations operations) {
return new CustomQueryDslMongodbRepositoryFactory<T,I>(operations);
}
public static class CustomQueryDslMongodbRepositoryFactory<T, I extends Serializable> extends MongoRepositoryFactory {
private MongoOperations operations;
public CustomQueryDslMongodbRepositoryFactory(MongoOperations mongoOperations) {
super(mongoOperations);
this.operations = mongoOperations;
}
#SuppressWarnings({ "rawtypes", "unchecked" })
protected Object getTargetRepository(RepositoryMetadata metadata) {
return new CustomQuerydslMongoRepositoryImpl(getEntityInformation(metadata.getDomainType()), operations);
}
protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {
return CustomQuerydslMongoRepository.class;
}
}
}
Entity Repository
public interface DocumentRepository extends CustomQuerydslMongoRepository<Document, String>{
}
Usage in Service
#Autowired
DocumentRepository repository;
public List<Document> getAllDocuments(Predicate predicate){
return repository.findAll(predicate,"myCustomCollection");
}

Resources