Arsen Afaunov
Arsen Afaunov

Reputation: 63

Bound mismatch error writing generic repository and service

I am writing a Spring MVC web app. There are three main domain entities: User, Project, Task. Also there are some common operations performed on those so I try to write generic interfaces and abstract classes to aggregate the common logic.

There is GenericRepository interface representing repository behavior:

package org.example.btracker.repository;

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

public interface GenericRepository<E, K extends Serializable> {
    K save(E entity);
    List<E> findSeveralById(K id);
    E findOneById(K id);
    K update(E changedEntity);
    void delete(K id);
}

There is AbstractGenericRepository where the shared logic is implemented:

package org.example.btracker.repository;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;

@SuppressWarnings("unchecked")
public abstract class AbstractGenericRepository<E, K extends Serializable> implements GenericRepository<E, K> {

    @Autowired
    private SessionFactory sessionFactory;

    protected Session session;

    protected Class<E> type;


    public AbstractGenericRepository() {
        Type t = getClass().getGenericSuperclass();
        ParameterizedType pt = (ParameterizedType) t;
        type = (Class<E>) pt.getActualTypeArguments()[0];

        session = getSession();
    }

    //method implementation omitted for brevity
    //implemented all but findSeveralById method which is specific for each entity

    private Session getSession() {
        return sessionFactory.getCurrentSession();
    }
}

There are three interfaces for each entity. Here is the code for Project entity:

package org.example.btracker.repository;

import org.example.btracker.domain.Project;

public interface ProjectRepository extends GenericRepository<Project, Integer> {

}

There are concrete implementations of the above mentioned interfaces for each entity. Here is the code for Project entity with a specific implementation of findSeveralById method:

package org.example.btracker.repository;

import java.util.List;

import org.example.btracker.domain.Project;

public class ProjectRepositoryImpl extends AbstractGenericRepository<Project, Integer> implements ProjectRepository {

    @Override
    public List<Project> findSeveralById(Integer id) {
        //TODO write an implementation
        return null;
    }
}

There is a GenericService interface representing common Service behavior:

package org.example.btracker.service;

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

public interface GenericService<E, K extends Serializable> {
    K create(E entity);
    List<E> getAll(K id);
    E getOne(K id);
    K update(E changedEntity);
    void delete(K id);
}

There is also an abstract service where the shared logic is implemented:

package org.example.btracker.service;

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

import org.example.btracker.repository.GenericRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

@Transactional
public abstract class AbstractGenericService<E, K extends Serializable, R extends GenericRepository<E, K>> implements GenericService<E, K> {

    @Autowired
    protected R repository;

    //method implementation omitted for brevity

}

There are three interfaces for each entity. Here is the code for Project entity with a specific join method signature:

package org.example.btracker.service;

import org.example.btracker.dto.ProjectDto;

public interface ProjectService extends GenericService<ProjectDto, Integer> {
    Integer join(Integer id);
}

There are three concrete implementations of above mentioned interfaces. Here is the code for Project entity with the implementation of the join method:

package org.example.btracker.service;

import org.example.btracker.dto.ProjectDto;
import org.example.btracker.repository.ProjectRepository;
import org.example.btracker.repository.ProjectRepositoryImpl;
import org.springframework.stereotype.Service;

@Service
public class ProjectServiceImpl extends AbstractGenericService<ProjectDto, Integer, ProjectRepository> implements ProjectService {

    @Override
    public Integer join(Integer id) {
        // TODO write an implementation
        return null;
    }
}

Here in the ProjectServiceImpl class I get the error:

Bound mismatch: The type ProjectRepository is not a valid substitute for the bounded parameter <R extends GenericRepository<E,K>> of the type AbstractGenericService<E,K,R>

I can't understand what is wrong. Please advise! Thank you in advance.

Upvotes: 0

Views: 597

Answers (1)

Francesco Pitzalis
Francesco Pitzalis

Reputation: 2112

You defined:

public class ProjectServiceImpl extends AbstractGenericService<ProjectDto, Integer, ProjectRepository>
public abstract class AbstractGenericService<E, K extends Serializable, R extends GenericRepository<E, K>>

Here your R extends GenericRepository<E,K> is ProjectRepository:

public interface ProjectRepository extends GenericRepository<Project, Integer>

so your E type is Project and your K type is Integer
BUT
in your ProjectServiceImpl your E type is ProjectDto, not Project.

Upvotes: 2

Related Questions