简体   繁体   中英

Retrive repository by entity type in Java

I'm writing Java program, which interacts with Db via Hibernate.

All my persistent classes extend from common abstract class Entity which implements interface IEntity . For example:

public interface IEntity {
    long getId();
    void setId(long id);
}

public abstract class Entity implements IEntity {
    private long id;
    //get + set id
}

public class User extends Entity {
    private string name;
    //get + set name
}

public class Item extends Entity {
    private string description;
    //get + set description
}

For operations with Db I created repository classes which extend from Repository<T extends IEntity> with standard CRUD methods for all entities and this class implements interface IRepository<T extends IEntity> :

public interface IRepository<T extends IEntity> {
    void create(T object) throws JDBCException;
    //other CRUD operations
}

public abstract class Repository<T extends IEntity> implements IRepository<T> {
    private final Class<T> entityClass;
    protected final EntityManager entityManager;

    public Repository(Class<T> entityClass, EntityManager entityManager) {
        this.entityClass = entityClass;
        this.entityManager = entityManager;
    }

    @Override
    public void create(T object) throws JDBCException {
        entityManager.getTransaction().begin();
        entityManager.persist(object);
        entityManager.getTransaction().commit();
    }
    //other CRUD operations implementation
}

public class UserRepository extends Repository<User> {
    public UserRepository (EntityManager entityManager) {
        super(AmountUnit.class, entityManager);
    }
}

public class ItemRepository extends Repository<Item> {
    public ItemRepository (EntityManager entityManager) {
        super(AmountUnit.class, entityManager);
    }
}

This structure worked well until I decided to create method to obtain specific repository by its entity class. I see this method as something like this:

public <T extends IEntity, U extends IRepository<T>> U getByType(T object) {
        // code here
    }

Let's say, that class User extends Entity and have repository class UserRepository extends Repository<User> I'm expecting, that this method should return Repository for User object`.

From my point of view this can be achieved in two ways:

  1. Elegant. Create method for IRepository - Class<T> getEntityClass and then compare classes of input and result of getEntityClass
  2. Stupid. Make many if/else statements inside this method and return repository. if(object instanceof A) return ARepository

     public class Storage { private IRepository<? extends IEntity>[] repositories; public <T extends IEntity, U extends IRepository<T>> U getByTypeVar1(T object) { for (IRepository<?> repo : repositories) { if (object instanceof repo.getEntityClass ()) // cannot resolve getEntityClass return repo; } } public <T extends IEntity, U extends IRepository<T>> U getByTypeVar2(T object) { if (object instanceof UserRepository.getEntityClass ()) return UserRepository; //incompatible type //more if else here } } 

But both of these implementation are failed to compile. May be you have any ideas how to write this method correctly

You can implement the getByType method like this (I changed the parameter type):

private List<IRepository<? extends IEntity>> repositories;

@SuppressWarnings("unchecked")
public <E extends IEntity> IRepository<E> getByType(Class<E> entityClass) {
    for (IRepository<?> repository : repositories) {
        if (repository.getEntityClass().equals(entityClass)) {
            return (IRepository<E>) repository;
        }
    }
    throw new IllegalArgumentException(
            "No repository for entity class " + entityClass.getName());
}

When you post your code that failed to compile, we can figure out where the problem was.

Update (code comments)

You should add the getEntityClass() method to IRepository . To make the code less complicated, you can replace:

<T extends IEntity, U extends IRepository<T>> U getByType()

with

<T extends IEntity> IRepository<T> getByType getByType()

Using instanceof in

object instanceof repo.getEntityClass ()

can be problematic, since you can have entity hierarchies and you can get a wrong (subclass) repository for an object. If you don't know a class of the object, you can get it by (the object can be a Hibernate proxy):

org.hibernate.Hibernate.unproxy(object).getClass()

and then compare the classes by repository.getEntityClass().equals(entityClass) .

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