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

Micronaut Data JDBC+JPA注解下findAll/findById无法映射实体对象

Micronaut Data JDBC + JPA 实体属性映射偶发失效问题(Micronaut 4.7.3)

在Micronaut 4.7.3环境中,使用Micronaut Data结合JDBC与JPA注解开发时,调用IJobRepository的findAll或findById方法后,返回的Job实体对象属性未正确映射。已尝试为Job实体添加@Introspected注解、将增量编译配置incremental设为false,修改Service层代码后问题仍偶发,执行gradlew clean与build操作也无法解决。

依赖配置

dependencies {
    annotationProcessor("org.projectlombok:lombok")
    annotationProcessor("io.micronaut:micronaut-http-validation")
    annotationProcessor("io.micronaut.data:micronaut-data-processor")
    annotationProcessor("io.micronaut.openapi:micronaut-openapi")
    annotationProcessor("io.micronaut.serde:micronaut-serde-processor")
    annotationProcessor("io.micronaut.validation:micronaut-validation-processor")

    implementation("io.micronaut:micronaut-jackson-databind")
    implementation("school.staff:common:0.0.1")
    implementation("io.micronaut.data:micronaut-data-jdbc")
    implementation("io.micronaut:micronaut-management")
    implementation("org.flywaydb:flyway-core:11.1.0")
    implementation("io.micronaut.flyway:micronaut-flyway")
    implementation("io.micronaut.validation:micronaut-validation")


    compileOnly("org.projectlombok:lombok")
    compileOnly("io.micronaut:micronaut-http-client")
    compileOnly("jakarta.persistence:jakarta.persistence-api")
    compileOnly("io.micronaut.openapi:micronaut-openapi-annotations")

    runtimeOnly("ch.qos.logback:logback-classic")
    runtimeOnly("org.postgresql:postgresql")
    runtimeOnly("io.micronaut.sql:micronaut-jdbc-hikari")
    runtimeOnly("org.flywaydb:flyway-database-postgresql") // 用于Micronaut测试资源的PostgreSQL支持,否则会抛出版本不兼容错误

    testImplementation("io.micronaut:micronaut-http-client")
    testRuntimeOnly("org.postgresql:postgresql")
}

Repository代码

@JdbcRepository(dialect = Dialect.POSTGRES)
public interface IJobRepository extends CrudRepository<Job, UUID>, JpaSpecificationExecutor<Job> {
    Optional<Job> findById(UUID id);
    Optional<Job> findByTitle(String title);
}

Service层代码

初始实现

@Singleton
public non-sealed class JobService implements IJobService {

@Override
public Result<ResponseMeta<List<JobResponse>>> find(FilterSortRequest jobRequest) {
    var result = iJobRepository.findAll()
            .stream()
            .map(jobResponseMapper)
            .toList();

    ResponseMeta.Metadata metadata = ResponseMeta.Metadata.builder()
            .supportedFilters(Job.SUPPORTED_FILTERS)
            .supportedSorts(Job.SUPPORTED_SORTS)
            .build();
    return Result.of(new ResponseMeta<>(result, metadata));
}

    @Override
    public Result<JobResponse> get(@Nonnull UUID id) {
        return iJobRepository.findById(id)
                .map(x -> Result.of(jobResponseMapper.apply(x)))
                .orElseGet(() -> Result.of(new Exception(ApplicationMessage.TagMessage.TAG_NOTFOUND)));
    }
}

修改后的测试实现(问题仍偶发)

@Override
public Result<JobResponse> get(@Nonnull UUID id) {
    var job = iJobRepository.findById(id).orElse(null);
    if (job == null)
        Result.of(new Exception(ApplicationMessage.TagMessage.TAG_NOTFOUND));
    return Result.of(jobResponseMapper.apply(job));
}

Job实体类

@AllArgsConstructor
@Builder
@Setter
@Getter
@Entity
public final class Job extends AuditTrail {

    @NotNull
    private String title;

    @TypeDef(type = DataType.JSON)
    @Column(columnDefinition = "jsonb")
    @Nullable
    private List<UUID> tag = new ArrayList<>();

    @Column(columnDefinition = "TEXT")
    private String description;

    @Column(columnDefinition = "TIMESTAMP WITH TIME ZONE")
    @NotNull
    private Instant startDate;

    @Column(columnDefinition = "TIMESTAMP WITH TIME ZONE")
    @NotNull
    private Instant endDate;

    @Enumerated(EnumType.STRING)
    @NotNull
    private JobType type;

    @Enumerated(EnumType.STRING)
    @Column(length = 100)
    @NotNull
    private TeachingLevel teachingLevel;

    private String externalLink;

    @Enumerated(EnumType.STRING)
    @Column(length = 100)
    @NotNull
    private ResidenceStatus residenceStatus;

    @Enumerated(EnumType.STRING)
    @Column(length = 100)
    @NotNull
    private Experience experience;

    private String subjectToTeach;

    @TypeDef(type = DataType.JSON)
    @Column(columnDefinition = "jsonb")
    @Nullable
    private List<UUID> perk;

    @Enumerated(EnumType.STRING)
    @Column(length = 100)
    @NotNull
    private JobStatus status;

    public static final List<SortOption> SUPPORTED_SORTS = List.of(
            SortOption.of("title", SortOperators.ASC)
    );

    public static final List<FilterOption> SUPPORTED_FILTERS = List.of(
            FilterOption.of("title", FilterOperators.EQUAL, Collections.emptyMap()),
            FilterOption.of("startDate", FilterOperators.IN, Collections.emptyMap())
    );

    public Job() {
        super();
    }
}

AuditTrail父类

@MappedSuperclass
@Setter
@Getter
@NoArgsConstructor
@AllArgsConstructor
@EntityListeners(AuditTrailEventListener.class)
public sealed class AuditTrail extends EntityId
        permits Job {
    private UUID createdBy;

    @Column(columnDefinition = "TIMESTAMP WITH TIME ZONE")
    private Instant createdDate;

    private UUID lastModifiedBy;

    @Column(columnDefinition = "TIMESTAMP WITH TIME ZONE")
    private Instant lastModifiedDate;
}

EntityId父类

@NoArgsConstructor
@Getter
@Setter
@AllArgsConstructor
@MappedSuperclass
public sealed class EntityId permits AuditTrail {
    @Id
    @AutoPopulated
    private UUID id;
}

排查与解决建议

  • Lombok兼容性调整:当前Lombok仅作为编译依赖引入,尝试添加implementation("org.projectlombok:lombok"),或暂时移除Lombok手动编写getter/setter和构造函数,验证是否是Lombok生成代码与Micronaut代理冲突导致的问题。
  • 密封类兼容性测试:移除Job、AuditTrail、EntityId的sealed修饰符,改为普通继承类,测试是否还会出现属性映射失效——Micronaut Data对密封类的代理生成可能存在偶发bug。
  • JSON字段映射优化:将@TypeDef(type = DataType.JSON)替换为JPA标准的@Type(type = "jsonb"),或检查是否缺少PostgreSQL JSON处理的依赖配置。
  • Repository接口简化:暂时移除JpaSpecificationExecutor继承,仅保留CrudRepository,避免Micronaut Data同时处理JDBC和JPA规范导致的代理生成异常;若需要JPA规范支持,改用JpaRepository替代CrudRepository。
  • 版本一致性检查:确保所有Micronaut相关依赖(core、data、jdbc等)版本统一为4.7.3,使用Micronaut BOM管理版本可避免版本不一致问题。
  • 实体监听器排查:暂时注释@EntityListeners(AuditTrailEventListener.class),验证监听器是否在实体加载时干扰了属性赋值流程。

内容的提问来源于stack exchange,提问作者San Jaisy

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 03:15:57