首页 > 解决方案 > 如何从 SimpleJpaRepository 取回 Repository Interface 对象具有代理解析的对象

问题描述

存储库类

@Repository
public interface AllFileRepository extends JpaRepository<AllFile, Long> {
    @Query("SELECT a From AllFile a where a.guid = :guid")
    AllFile findByGuid(@Param("guid") String guid);
}

服务等级

@Service
@Data
public class PipelineService implements Serializable {
    /**
     *
     */
    private static final long serialVersionUID = 1L;

    @Autowired
    AllFileRepository allFileRepository;
}

创建对象 SimpleJpaRepository<AllFile, Long>

PipelineService pipelineService = new PipelineService();

void methodX() {
    AnnotationConfigApplicationContext applicationContext = (AnnotationConfigApplicationContext) 
    ApplicationContextUtils.getApplicationContext();
    AutowireCapableBeanFactory autowireCapableBeanFactory = 
        applicationContext.getAutowireCapableBeanFactory();
    autowireCapableBeanFactory.autowireBean(pipelineService);
    JpaRepository<AllFile, Long> jpaRepository = (SimpleJpaRepository<AllFile, Long>) 
        AopProxyUtils.getSingletonTarget(pipelineService.getAllFileRepository());

    // (AllFileRepository) jpaRepository casting causes ClassCastException
 }

例外

java.lang.ClassCastException: org.springframework.data.jpa.repository.support.SimpleJpaRepository cannot be cast to ....repository.AllFileRepository

如何获取 AllFileRepository 接口的对象?我可以访问的地方findByGuid("");

更新

我能够获得SimpleJpaRepository<AllFile, Long>属于接口 AllFileRepository 的对象,该接口又扩展了 JpaRepository

public void initialize() {
        AnnotationConfigApplicationContext applicationContext = (AnnotationConfigApplicationContext) ApplicationContextUtils
                .getApplicationContext();
        EntityManager em = applicationContext.getBean(EntityManager.class);
        AllFileRepository allFileRepository = new JpaRepositoryFactory(em).getRepository(AllFileRepository.class);
        allFileRepository.findByGuid(""); // Method is accessible here but the object is proxy
        SimpleJpaRepository<AllFile, Long> simpleJpaRepository = (SimpleJpaRepository<AllFile, Long>) (AopProxyUtils
                .getSingletonTarget(allFileRepository)); // But proxy resolution yeilds SimpleJpaRepository cannot
                                                         // explicitly cast to AllFileRepository
        ((AllFileRepository) simpleJpaRepository).findByGuid(""); // class
                                                                  // org.springframework.data.jpa.repository.support.SimpleJpaRepository
                                                                  // cannot be cast to class
                                                                  // com.example.spingaoprepository.repository.AllFileRepository
                                                                  // (org.springframework.data.jpa.repository.support.SimpleJpaRepository
                                                                  // and
                                                                  // com.example.spingaoprepository.repository.AllFileRepository
                                                                  // are in unnamed module of loader 'app'

    }

这是示例程序的链接

标签: javaspringspring-data-jpaspring-aop

解决方案


尝试将不兼容的类型相互转换是没有用的。这不是 Spring 问题,而是 Java 基础知识。我已经告诉过你如何在 Spring 中解决这个问题:你需要提供一个实际实现的类AllFileRepository,并确保 Spring Data JPA 将它用作存储库而不是接口。为此,您需要

  • 将接口注释从 更改@Repository@NoRepositoryBean,
  • 创建类@Repository AllFileRepositoryImpl并在那里提供AllFile findByGuid(String guid)做一些有意义的事情的实现。

然后您可以轻松地以您想要的方式进行转换,因为您的代理的目标对象将是一个AllFileRepositoryImpl实例。

我向您发送了一个拉取请求,您只需要接受即可。相关提交 @5705cbb中更改的类如下所示:

package com.example.spingaoprepository.repository;

import com.example.spingaoprepository.model.AllFile;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.data.repository.NoRepositoryBean;

@NoRepositoryBean
public interface AllFileRepository extends JpaRepository<AllFile, Long> {
    @Query("SELECT a From AllFile a where a.guid = :guid")
    AllFile findByGuid(@Param("guid") String guid);
}
package com.example.spingaoprepository.repository;

import com.example.spingaoprepository.model.AllFile;
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;
import org.springframework.stereotype.Repository;

import javax.persistence.EntityManager;

@Repository
public class AllFileRepositoryImpl extends SimpleJpaRepository<AllFile, Long> implements AllFileRepository {
  public AllFileRepositoryImpl(EntityManager em) {
    super(AllFile.class, em);
  }

  @Override
  public AllFile findByGuid(String guid) {
    System.out.println("Finding AllFile by GUID " + guid);
    return null;
  }
}
package com.example.spingaoprepository.serializable;

import com.example.spingaoprepository.repository.AllFileRepository;
import com.example.spingaoprepository.service.PipelineService;
import com.example.spingaoprepository.utils.ApplicationContextUtils;

import org.springframework.aop.framework.AopProxyUtils;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.context.ApplicationContext;

public class PipelineConfigurer {
    private ApplicationContext applicationContext = ApplicationContextUtils.getApplicationContext();
    private PipelineService pipelineService = applicationContext.getBean(PipelineService.class);

    public void initialize() {
        AutowireCapableBeanFactory autowireCapableBeanFactory = applicationContext.getAutowireCapableBeanFactory();
        autowireCapableBeanFactory.autowireBean(pipelineService);
        AllFileRepository allFileRepository = (AllFileRepository) AopProxyUtils
                .getSingletonTarget(pipelineService.getAllFileRepository());
        allFileRepository.findByGuid("XY-123");
    }

}

推荐阅读