使用Spring Data Jpa和Hibernate时,JSR303验证不验证@Id是否不是@GeneratedValue

d0x*_*d0x 4 java jpa lombok spring-data spring-data-jpa

在一个简单的项目中,我喜欢测试@NotNull验证(以及其他一些自定义验证).

因此我写了一些单元测试来执行这个: @Test(expect=ValidationException.class

一个最小的mavinized示例来重现我在github上传的问题:

我声称如果它@Id是一个生成的值,它运行良好.但如果@Id由系统给出,则忽略验证.

这个类将显示重现问题的最小设置:

这两个实体(一个具有生成值,一个没有h:

@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
public class GeneratedId {
    @Id
    @GeneratedValue
    private Long    id;

    @NotNull
    private String  content;
}

@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
public class GivenId {
    @Id
    private Long    id;

    @NotNull
    private String  content;
}
Run Code Online (Sandbox Code Playgroud)

单元测试:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath*:/applicationContext.xml")
@Transactional
@ActiveProfiles("embedded")
public class MyEntityTest
{
    @Autowired GeneratedIdService   generatedIdService;

    @Autowired GivenIdService       givenIdService;

    // This test will pass
    @Test(expected = ValidationException.class)
    public void shouldNotAllowNullValues1()
    {
        this.generatedIdService.save(new GeneratedId());
    }

    // This test will fail
    @Test(expected = ValidationException.class)
    public void shouldNotAllowNullValues2()
    {
        this.givenIdService.save(new GivenId(1L, null));
    }
}
Run Code Online (Sandbox Code Playgroud)

这是样板服务和存储库

public interface GeneratedIdRepository extends JpaRepository<GeneratedId, Long> {
}

public interface GivenIdRepository extends JpaRepository<GivenId, Long> {
}

@Service
public class GeneratedIdService {
    @Autowired GeneratedIdRepository    repository;

    public GeneratedId save(final GeneratedId entity) {
        return this.repository.save(entity);
    }
}

@Service
public class GivenIdService {
    @Autowired GivenIdRepository    repository;

    public GivenId save(final GivenId entity) {
        return this.repository.save(entity);
    }
}
Run Code Online (Sandbox Code Playgroud)

目前我使用的是Spring 3.1.4,Spring-Data 1.3.4,Hibernate 4.1.10和Hibernate-Validator 4.2.0.

验证被跳过的任何建议方式?

编辑1:

我在两个实体上都没有使用lombok尝试过,但仍然会发生错误.

Oli*_*ohm 5

如果要强制持久性提供刷新EntityManager 之前的事务提交或回滚您可能需要手动清除或使用saveAndFlush(…)的JpaRepository.

原因是在自动生成的ID情况下,持久性提供程序必须刷新才能将ID绑定到Java对象.在手动分配ID的情况下,根本不需要在任何更早的时间点刷新,而不是在事务结束时,因此持久性提供程序避免了数据库交互.

除了这些技术细节之外,我认为依赖持久性提供程序来进行这种验证无论如何都在架构上存在问题.如果提供程序检测到违规,您实际上通过各种业务逻辑管道输出了无效对象.为了确保您不必进行防御性编码(null检查每个或每个地方),您可以通过检查传递给构造函数或setter的值来简单地强制该属性不可为空.这样,你基本上知道,每当你得到一个对象的实例时null,无论是否调用了某个第三个框架,或者某个开发人员意外忘记调用它,该值都将永远不会.