【问题标题】:Spring Data JPA - Why do I get null bean exception in the test?Spring Data JPA - 为什么我在测试中得到空 bean 异常?
【发布时间】:2014-08-01 18:21:55
【问题描述】:

我想使用 Spring Data JPA 来做 ORM。我有以下声明的存储库接口:

public interface SegmentRepository extends JpaRepository<Segment, Integer> {
    // query methods ...
}

以下是 Java Config 类:

@Configuration
@EnableJpaRepositories("com.example.cap.repositories")
@EnableTransactionManagement
public class CAPRepositoryConfig {
    @Bean
    public DataSource dataSource() {
        BasicDataSource ds = new BasicDataSource();
        ds.setDriverClassName(org.postgresql.Driver.class.getName());
        ds.setUsername("postgres");
        ds.setPassword("password");
        ds.setUrl("jdbc:postgresql://localhost:5432/postgres");
        ds.setInitialSize(10);
        return ds;
    }

    @Bean
    public EntityManagerFactory entityManagerFactory() {

        EclipseLinkJpaVendorAdapter vendorAdapter = new EclipseLinkJpaVendorAdapter();
        vendorAdapter.setGenerateDdl(true);

        LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
        Map<String, Object> jpaProperties = new HashMap<String, Object>();
        jpaProperties.put("eclipselink.weaving", "false");
        factory.setJpaVendorAdapter(vendorAdapter);
        factory.setPackagesToScan("com.example.cap.repositories");
        factory.setDataSource(dataSource());
        factory.setJpaPropertyMap(jpaProperties);
        factory.afterPropertiesSet();

        return factory.getObject();
    }

    @Bean
    public PlatformTransactionManager transactionManager() {

        JpaTransactionManager txManager = new JpaTransactionManager();
        txManager.setEntityManagerFactory(entityManagerFactory());
        return txManager;
    }
}

Segment 类在com.example.cap.repositories 中定义为:

@Entity
public class Segment {
    @Id
    private int segmentID;
    private int caseID;
    private Timestamp segStartTime;
    private Timestamp segEndTime;

    //setter and getters
}

但是当我使用自动注入的 bean SegmentRepository 运行 JUnit 测试时,我得到了 bean repository 的空点异常:

@ContextConfiguration(classes=CAPRepositoryConfig.class)
public class CAPRepositoryTest {

    @Autowired
    private SegmentRepository repository;

    @Test
    public void testRepository() {
        Segment seg = repository.findOne(123);    //null pointer exception for repository
    }
}

根据 Spring Data JPA 文档,只要我在 Java Config 类中指定 @EnableJpaRepositoriesSegmentRepository bean repository 就应该自动注入。但是为什么我在 JUnit 测试类中得到 repository 的空指针异常?由于SegmentRepository是一个接口而不是一个类,所以我无法通过Java Config类创建实例。

【问题讨论】:

    标签: java jpa dependency-injection spring-data-jpa spring-java-config


    【解决方案1】:

    我想你忘记了 SpringJUnit4ClassRunner 使 @Autowired 在测试中起作用:

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(classes=CAPRepositoryConfig.class)
    public class CAPRepositoryTest { ... }
    

    【讨论】:

    • 谢谢。这解决了 NullPointerException。但是当我运行 JUnit 测试时,我得到了java.lang.IllegalStateException: Failed to load ApplicationContext。它还显示Caused by: java.lang.IllegalStateException: No persistence exception translators found in bean factory. Cannot perform exception translation.那么这里有什么问题?
    • 尝试直接从您的@Bean 方法返回LocalContainerEntityManagerFactoryBean,而不调用getObject()。然后您可以将EntityManagerFactory 作为方法参数传递给transactionManager()
    • 我发现了问题。这是由于建议here 在Java Config 中缺少EclipseLink bean。但是我的Segment 类中的segmentID 字段与我的PostgreSQL 表segmentID 中定义为segmentID serial 的数据字段之间的类型不匹配仍然存在异常。我应该给segmentID 提供什么Java 类型以匹配PostgreSQL 中的serial 类型?
    • 我觉得int应该没问题,但是我对EclipseLink不熟悉
    • 感谢 axtavt。我发现他可能是由于 EclipseLink 中的一个错误。我需要将字段从 int segmentID 更改为 Integer segmentID 以匹配 @Id 注释。但我又遇到了另一个例外:Error creating bean with name 'segmentRepository': Invocation of init method failed; nested exception is java.util.NoSuchElementException。你知道这可能是什么原因吗?我需要指定什么init 方法?谢谢。
    【解决方案2】:

    当我使用测试类并且需要进行单元测试时,我更喜欢实例化该类,因为尽管您有一个接口,但您也需要一个实现类。就我而言,我会这样做:

     @ContextConfiguration(classes=CAPRepositoryConfig.class)
     public class CAPRepositoryTest {
    
         private SegmentRepository repository;
    
         @Before
         public void testRepository() {
             repository = new SegmentRepositoryImpl();
         }
    
         @Test
         public void testRepository() {
             Segment seg = repository.findOne(123);
         }
     }
    

    【讨论】:

    • 我认为不应该在 Spring Data JPA 中实现 Repository 类。它应该由框架自动处理。
    猜你喜欢
    • 2012-03-12
    • 2013-04-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-21
    • 2016-07-19
    • 2011-12-13
    • 2011-04-14
    相关资源
    最近更新 更多