You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring与TestNG中@DataJpaTest未触发@Convert的AttributeConverter

问题分析与解决方案

核心问题原因

  1. JPA一级缓存规避了数据库查询:执行save后,实体被存入EntityManager的一级缓存,后续findById直接从缓存取数据,不会触发数据库读取操作,因此不会调用convertToEntityAttribute方法,自然不会抛出预期异常。
  2. 转换器未生效或逻辑缺失:要么Spring未扫描到转换器/实体导致注解失效,要么convertToDatabaseColumn未实现实际加密逻辑,导致数据未被加密存储。

具体修复方案

1. 打破缓存,强制从数据库读取

修改测试用例,通过清除EntityManager缓存或拆分事务,迫使查询从数据库获取数据:

@DataJpaTest(excludeAutoConfiguration = {LiquibaseAutoConfiguration.class})
public class AccountRepositoryTest extends AbstractTransactionalTestNGSpringContextTests {
  @Autowired
  private AccountRepository accountRepository;
  @PersistenceContext
  private EntityManager entityManager;

  public void shouldThrowExceptionOnReadingSensitiveData() throws Exception {
    Account expectedAccount = new Account("1", "sensitive info");
    accountRepository.save(expectedAccount);

    // 清除一级缓存,强制后续查询走数据库
    entityManager.clear();

    // 预期抛出UnsupportedOperationException
    Assertions.assertThrows(UnsupportedOperationException.class, () -> {
        accountRepository.findById("1");
    });
  }
}

2. 完善转换器加密逻辑

给convertToDatabaseColumn添加实际哈希加密实现,确保数据存入数据库前被加密:

import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class EncryptorConverter implements AttributeConverter<String, byte[]> {
    private static final String HASH_ALGORITHM = "SHA-256";

    @Override
    public byte[] convertToDatabaseColumn(String attribute) {
        if (attribute == null) {
            return null;
        }
        try {
            MessageDigest digest = MessageDigest.getInstance(HASH_ALGORITHM);
            return digest.digest(attribute.getBytes(StandardCharsets.UTF_8));
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("Hash algorithm not supported", e);
        }
    }

    @Override
    public String convertToEntityAttribute(byte[] dbData) {
        throw new UnsupportedOperationException("Hashed data cannot be converted back to plaintext");
    }
}

3. 确保配置与实体注解有效性

  • 检查TestDatabaseConfig的packagesToScan参数,确保包含实体类和转换器所在的包,让Spring能扫描到这些组件。
  • 给实体字段指定匹配的数据库类型,确保byte[]类型能正确存储:
import jakarta.persistence.*;
import java.util.Objects;

@Entity
public class Account {
  @Id
  private String id;
  // 指定数据库字段类型为VARBINARY,适配byte[]存储
  @Column(columnDefinition = "VARBINARY(255)")
  @Convert(converter = EncryptorConverter.class)
  private String sensitiveInfo;

  public Account(String id, String sensitiveInfo) {
      this.id = id;
      this.sensitiveInfo = sensitiveInfo;
  }

  // 重写equals和hashCode,确保测试断言有效
  @Override
  public boolean equals(Object o) {
      if (this == o) return true;
      if (o == null || getClass() != o.getClass()) return false;
      Account account = (Account) o;
      return Objects.equals(id, account.id) && Objects.equals(sensitiveInfo, account.sensitiveInfo);
  }

  @Override
  public int hashCode() {
      return Objects.hash(id, sensitiveInfo);
  }
}

4. 修正测试预期逻辑

原测试用例的断言逻辑与预期矛盾,应该改为验证异常抛出,而非断言实体相等:

public void shouldThrowExceptionOnReadingSensitiveData() throws Exception {
    Account expectedAccount = new Account("1", "sensitive info");
    accountRepository.save(expectedAccount);
    entityManager.clear();

    // 验证查询时抛出指定异常
    Assertions.assertThrows(UnsupportedOperationException.class, () -> {
        accountRepository.findById("1");
    });
}

内容的提问来源于stack exchange,提问作者Rodrigo Novaes

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 18:05:37