Получить тип домена для собственного репозитория в Spring - PullRequest
0 голосов
/ 07 января 2019

Добрый день, это мой первый вопрос здесь, на StackOverflow.

Я не являюсь экспертом в среде Spring, и иногда я теряюсь на много времени из-за проблем, которые относительно легко решить, но на этот раз я действительно не могу выбраться из этого.

Я пытаюсь реализовать метод внутри собственного Spring Data Repository, который должен работать с несколькими сущностями и выполнять некоторые операции с базой данных, основываясь на наличии определенных аннотаций в полях сущности.

Я пробовал много обходных путей, найденных в Интернете, но на самом деле я не в состоянии достичь нужного мне результата. Я постараюсь быть более конкретным:

Это пример сущности с аннотациями:

@Data
@Entity
@MyAnnotation
public class User{

    @Id
    @MyDataAnnotation
    private Long id;

    @MyDataAnnotation
    private String firstName;

    @MyDataAnnotation
    private String lastName;

    private String userName;
    private int followers;
    private int following;
}

У меня внутри класса UserService что-то вроде этого:

@Service
public class UserService {

    private final UserRepository repository;

    public void doSomethingOnUser(Long id){
        repository.myCustomMethod(id);
    }
}

Для UserRepository я сделал что-то вроде этого, просто очень простые вещи:

@Repository
public interface UserRepository extends CrudRepository<User,Long>,MyCustomRepository<User,Long> {}

У меня есть пользовательский интерфейс репо:

public interface MyCustomRepository<T,ID>{

    public void myCustomMethod(ID id);
}

И, наконец, реализация myCustomMethod:

public class MyCustomRepositoryImpl <T,ID> implements MyCustomRepository{

    @PersistenceContext
    EntityManager entityManager;


    @Override
    public void myCustomMethod(Object id){

        User user = entityManager.find(User.class,id);

        List<Field> markedFields =   MyAnnotationProcessor.getAnnotated(user.getClass());

        //Here I'll manipulate the fields that i've obtained
        ...

        entityManager.persist(u);

        //And then i'm persisting the modified entity
    }
} 

На самом деле это работает с User Entity, но мне нужно найти способ, чтобы он работал для каждого типа домена, управляемого репозиторием, расширяющим MyCustomRepository.

Например, если у меня есть:

public interface WhateverRepository extends CrudRepository<WhateverClass,Long>,MyCustomRepository<WhatheverClass,Long>

myCustomMethod все равно должен делать свои вещи.

Я пытался получить экземпляр Class<T> с помощью этого фрагмента кода:

 private final Class<T> type;

 public MyCustomRepositoryImpl(Class<T> type) {
      this.type = type;
 }

И использование типа вместо User.class, но не удается загрузить ApplicationContext:

Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'java.lang.Class<?>' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}`

Спасибо, если вы читали до сих пор, надеюсь, что вы можете дать мне несколько советов, и если я не был достаточно ясен, пожалуйста, не стесняйтесь спрашивать меня для получения дополнительной информации.

Обновление:

После ответа @amineT я попытался использовать GenericTypeResolver, предоставленный Spring, но вместо типов я фактически получаю нулевое значение. Документация гласит, что если возвращается значение null, это означает, что он не смог разрешить тип.

Это код, который я использовал:

private final Class<?>[] genericType;

    public MyCustomRepositoryImpl(){
        this.genericType = GenericTypeResolver.resolveTypeArguments(getClass(), MyCustomRepositoryImpl.class);
    }

Я думаю, что каким-то образом эта "проблема" связана со всеми прокси-серверами, которые Spring делает под капотом, но у меня пока нет точного представления.

Если у кого-то есть какие-либо подсказки, пожалуйста, запишите это здесь, это будет оценено.

Ответы [ 2 ]

0 голосов
/ 09 января 2019

На самом деле, ссылаясь на ответ , на который указывает @ amineT , я создал пример проекта, чтобы проверить, подходит ли он вашей проблеме.

Насколько я понимаю, вы должны определить тип компонента во время выполнения, а не тип CustomRepositoryImpl. После того, как я собрал свой пример проекта, я обнаружил, что ваш код почти правильный.

Вот пример того, что я хотел бы сделать с вашим кодом, чтобы он работал:

    @Override
    public void myCustomMethod(Class cls, Object id){

        Object user = entityManager.find(cls,id);

        List<Field> markedFields =   MyAnnotationProcessor.getAnnotated(cls);

        //Here I'll manipulate the fields that i've obtained
        ...

        entityManager.persist(u);

        //And then i'm persisting the modified entity
    }

Кроме того, вот мой github для созданного мной примера проекта.

0 голосов
/ 07 января 2019

У меня была похожая проблема, и этот ответ помог мне. Вы получаете NoSuchBeanDefinitionException, потому что вы пытаетесь внедрить поле типа класса, но не создали его в контексте Spring. Вам нужно использовать GenericTypeResolver в Spring, чтобы найти универсальный тип и соответствующим образом обработать ваши данные. Надеюсь, это поможет

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...