EAP 7.3 JPA+Hibernate REST 双向 ManyToOne 关系的序列化(NOT SPRING)

EAP 7.3 JPA+Hibernate REST Serialization of Bidirectional ManyToOne relationship (NOT SPRING)

我来自 Payara/EclipseLink 的背景,在这种背景下,它开箱即用。我的合同要求我使用不支持 EclipseLink.persistance 的 EAP,我总是更喜欢“提供”而不是添加库。

我正在创建一个非常简单的 REST 微服务,其中的对象关系非常简单。但是,当我尝试访问一个对象时,出现序列化错误(具体如下)。

实体一号

@Entity
@Table(name = "training_centers")
@NamedQuery(name = TrainingCenterEntity.findAll, query = "SELECT c FROM TrainingCenterEntity c")
@JsonbVisibility(PrivateVisibilityStrategy.class)
public class TrainingCenterEntity implements Serializable, ValidEntity {

    private static final long serialVersionUID = 9197911968578298904L;
    public static final String PREFIX = "centers.entity.TrainingCenter.";
    public static final String findAll = PREFIX + "findAll";

    @Id
    @Column(name = "program_code")
    private String program_code;

    @Column(name = "program_name", length = 255, nullable = false)
    private String program_name;

    public TrainingCenterEntity(String code, String name) {
        this.program_code = code;
        this.program_name = name;
        this.classifications = new ArrayList<ClassificationEntity>();
    }
    
    public TrainingCenterEntity() {
        this.classifications = new ArrayList<ClassificationEntity>();
    }

    public String getProgramCode() {
        return program_code;
    }

    public void setProgramCode(String program_code) {
        this.program_code = program_code;
    }
    
    @OneToMany(
            fetch = FetchType.LAZY,
            cascade = CascadeType.ALL,
            orphanRemoval = true,
            mappedBy = "center")
    private List<ClassificationEntity> classifications;

实体二

@Entity
@Table(name = "classifications")
@NamedQueries({
    @NamedQuery(name = ClassificationEntity.findByProgramCode, query = "SELECT c FROM ClassificationEntity c WHERE c.center = :programCode"),
    @NamedQuery(name = ClassificationEntity.findAll, query = "SELECT c FROM ClassificationEntity c")
})
@JsonbVisibility(PrivateVisibilityStrategy.class)
public class ClassificationEntity implements Serializable, ValidEntity{
    
    private static final long serialVersionUID = 5138672261884252346L;
    public static final String PREFIX = "centers.entity.ClassificationEntity.";
    public static final String findByProgramCode = PREFIX + "findByProgramCode";
    public static final String findAll = PREFIX + "findAll";

    @Id
    @Column(name = "classification_id", columnDefinition = "serial")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @Column(name = "classification_type", unique = true, nullable = false)
    private ClassificationType classificationType;
    
    @Column(name = "classification_name", nullable = true, length = 255)
    private String classificationName;
    
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "program_code", referencedColumnName = "program_code")
    private TrainingCenterEntity center;
    
    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public ClassificationEntity() {
        this.center = new TrainingCenterEntity();
    }

实体一的休息端点

@GET
@Produces({MediaType.APPLICATION_JSON})
public List<TrainingCenterEntity> findAll() {
    return this.manager.findAll();
}

REST 端点的 StackTrace

11:44:03,129 SEVERE [org.eclipse.yasson.internal.Marshaller] (default task-1) Unable to serialize property 'classifications' from ptsi.service.centers.entity.TrainingCenterEntity
11:44:03,129 SEVERE [org.eclipse.yasson.internal.Marshaller] (default task-1) Generating incomplete JSON
11:44:03,129 INFO  [io.jaegertracing.internal.reporters.LoggingReporter] (default task-1) Span reported: 33fb13e2e5f679d8:33fb13e2e5f679d8:0:1 - GET:ptsi.service.centers.boundary.TrainingCenterResource.findAll
11:44:03,129 ERROR [io.undertow.request] (default task-1) UT005023: Exception handling request to /learning-hibernate/api/centers: org.jboss.resteasy.spi.UnhandledException: javax.ws.rs.ProcessingException: RESTEASY008205: JSON Binding serialization error javax.json.bind.JsonbException: Unable to serialize property 'classifications' from ptsi.service.centers.entity.TrainingCenterEntity
    at org.jboss.resteasy.resteasy-jaxrs@3.11.2.Final-redhat-00002//org.jboss.resteasy.core.ExceptionHandler.handleException(ExceptionHandler.java:356)
    at org.jboss.resteasy.resteasy-jaxrs@3.11.2.Final-redhat-00002//org.jboss.resteasy.core.SynchronousDispatcher.writeException(SynchronousDispatcher.java:193)
    at org.jboss.resteasy.resteasy-jaxrs@3.11.2.Final-redhat-00002//org.jboss.resteasy.core.SynchronousDispatcher.writeResponse(SynchronousDispatcher.java:539)
    at org.jboss.resteasy.resteasy-jaxrs@3.11.2.Final-redhat-00002//org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:461)
    at org.jboss.resteasy.resteasy-jaxrs@3.11.2.Final-redhat-00002//org.jboss.resteasy.core.SynchronousDispatcher.lambda$invoke(SynchronousDispatcher.java:229)
    at org.jboss.resteasy.resteasy-jaxrs@3.11.2.Final-redhat-00002//org.jboss.resteasy.core.SynchronousDispatcher.lambda$preprocess[=14=](SynchronousDispatcher.java:135)
    at org.jboss.resteasy.resteasy-jaxrs@3.11.2.Final-redhat-00002//org.jboss.resteasy.core.interception.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:356)
    at org.jboss.resteasy.resteasy-jaxrs@3.11.2.Final-redhat-00002//org.jboss.resteasy.core.SynchronousDispatcher.preprocess(SynchronousDispatcher.java:138)
    at org.jboss.resteasy.resteasy-jaxrs@3.11.2.Final-redhat-00002//org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:215)
    at org.jboss.resteasy.resteasy-jaxrs@3.11.2.Final-redhat-00002//org.jboss.resteasy.plugins.server.servlet.ServletContainerDispatcher.service(ServletContainerDispatcher.java:227)
    at org.jboss.resteasy.resteasy-jaxrs@3.11.2.Final-redhat-00002//org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java:56)
    at org.jboss.resteasy.resteasy-jaxrs@3.11.2.Final-redhat-00002//org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java:51)
    at javax.servlet.api@2.0.0.Final-redhat-00001//javax.servlet.http.HttpServlet.service(HttpServlet.java:590)
    at io.undertow.servlet@2.0.30.SP3-redhat-00001//io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:74)
    at io.undertow.servlet@2.0.30.SP3-redhat-00001//io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:129)
    at io.opentracing.contrib.opentracing-jaxrs2//io.opentracing.contrib.jaxrs2.server.SpanFinishingFilter.doFilter(SpanFinishingFilter.java:52)
    at io.undertow.servlet@2.0.30.SP3-redhat-00001//io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61)
    at io.undertow.servlet@2.0.30.SP3-redhat-00001//io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)
    at io.undertow.servlet@2.0.30.SP3-redhat-00001//io.undertow.servlet.handlers.FilterHandler.handleRequest(FilterHandler.java:84)
    at io.undertow.servlet@2.0.30.SP3-redhat-00001//io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:62)
    at io.undertow.servlet@2.0.30.SP3-redhat-00001//io.undertow.servlet.handlers.ServletChain.handleRequest(ServletChain.java:68)
    at io.undertow.servlet@2.0.30.SP3-redhat-00001//io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36)
    at org.wildfly.extension.undertow@7.3.1.GA-redhat-00003//org.wildfly.extension.undertow.security.SecurityContextAssociationHandler.handleRequest(SecurityContextAssociationHandler.java:78)
    at io.undertow.core@2.0.30.SP3-redhat-00001//io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
    at io.undertow.servlet@2.0.30.SP3-redhat-00001//io.undertow.servlet.handlers.RedirectDirHandler.handleRequest(RedirectDirHandler.java:68)
    at io.undertow.servlet@2.0.30.SP3-redhat-00001//io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:132)
    at io.undertow.servlet@2.0.30.SP3-redhat-00001//io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:57)
    at io.undertow.core@2.0.30.SP3-redhat-00001//io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
    at io.undertow.core@2.0.30.SP3-redhat-00001//io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:46)
    at io.undertow.servlet@2.0.30.SP3-redhat-00001//io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:64)
    at io.undertow.core@2.0.30.SP3-redhat-00001//io.undertow.security.handlers.AuthenticationMechanismsHandler.handleRequest(AuthenticationMechanismsHandler.java:60)
    at io.undertow.servlet@2.0.30.SP3-redhat-00001//io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java:77)
    at io.undertow.core@2.0.30.SP3-redhat-00001//io.undertow.security.handlers.NotificationReceiverHandler.handleRequest(NotificationReceiverHandler.java:50)
    at io.undertow.core@2.0.30.SP3-redhat-00001//io.undertow.security.handlers.AbstractSecurityContextAssociationHandler.handleRequest(AbstractSecurityContextAssociationHandler.java:43)
    at io.undertow.core@2.0.30.SP3-redhat-00001//io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
    at org.wildfly.extension.undertow@7.3.1.GA-redhat-00003//org.wildfly.extension.undertow.security.jacc.JACCContextIdHandler.handleRequest(JACCContextIdHandler.java:61)
    at io.undertow.core@2.0.30.SP3-redhat-00001//io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
    at org.wildfly.extension.undertow@7.3.1.GA-redhat-00003//org.wildfly.extension.undertow.deployment.GlobalRequestControllerHandler.handleRequest(GlobalRequestControllerHandler.java:68)
    at io.undertow.core@2.0.30.SP3-redhat-00001//io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
    at io.undertow.servlet@2.0.30.SP3-redhat-00001//io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:269)
    at io.undertow.servlet@2.0.30.SP3-redhat-00001//io.undertow.servlet.handlers.ServletInitialHandler.access0(ServletInitialHandler.java:78)
    at io.undertow.servlet@2.0.30.SP3-redhat-00001//io.undertow.servlet.handlers.ServletInitialHandler.call(ServletInitialHandler.java:133)
    at io.undertow.servlet@2.0.30.SP3-redhat-00001//io.undertow.servlet.handlers.ServletInitialHandler.call(ServletInitialHandler.java:130)
    at io.undertow.servlet@2.0.30.SP3-redhat-00001//io.undertow.servlet.core.ServletRequestContextThreadSetupAction.call(ServletRequestContextThreadSetupAction.java:48)
    at io.undertow.servlet@2.0.30.SP3-redhat-00001//io.undertow.servlet.core.ContextClassLoaderSetupAction.call(ContextClassLoaderSetupAction.java:43)
    at org.wildfly.extension.undertow@7.3.1.GA-redhat-00003//org.wildfly.extension.undertow.security.SecurityContextThreadSetupAction.lambda$create[=14=](SecurityContextThreadSetupAction.java:105)
    at org.wildfly.extension.undertow@7.3.1.GA-redhat-00003//org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create[=14=](UndertowDeploymentInfoService.java:1541)
    at org.wildfly.extension.undertow@7.3.1.GA-redhat-00003//org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create[=14=](UndertowDeploymentInfoService.java:1541)
    at org.wildfly.extension.undertow@7.3.1.GA-redhat-00003//org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create[=14=](UndertowDeploymentInfoService.java:1541)
    at org.wildfly.extension.undertow@7.3.1.GA-redhat-00003//org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create[=14=](UndertowDeploymentInfoService.java:1541)
    at org.wildfly.extension.undertow@7.3.1.GA-redhat-00003//org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create[=14=](UndertowDeploymentInfoService.java:1541)
    at io.undertow.servlet@2.0.30.SP3-redhat-00001//io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:249)
    at io.undertow.servlet@2.0.30.SP3-redhat-00001//io.undertow.servlet.handlers.ServletInitialHandler.access[=14=]0(ServletInitialHandler.java:78)
    at io.undertow.servlet@2.0.30.SP3-redhat-00001//io.undertow.servlet.handlers.ServletInitialHandler.handleRequest(ServletInitialHandler.java:99)
    at io.undertow.core@2.0.30.SP3-redhat-00001//io.undertow.server.Connectors.executeRootHandler(Connectors.java:376)
    at io.undertow.core@2.0.30.SP3-redhat-00001//io.undertow.server.HttpServerExchange.run(HttpServerExchange.java:830)
    at org.jboss.threads@2.3.3.Final-redhat-00001//org.jboss.threads.ContextClassLoaderSavingRunnable.run(ContextClassLoaderSavingRunnable.java:35)
    at org.jboss.threads@2.3.3.Final-redhat-00001//org.jboss.threads.EnhancedQueueExecutor.safeRun(EnhancedQueueExecutor.java:1982)
    at org.jboss.threads@2.3.3.Final-redhat-00001//org.jboss.threads.EnhancedQueueExecutor$ThreadBody.doRunTask(EnhancedQueueExecutor.java:1486)
    at org.jboss.threads@2.3.3.Final-redhat-00001//org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1377)
    at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: javax.ws.rs.ProcessingException: RESTEASY008205: JSON Binding serialization error javax.json.bind.JsonbException: Unable to serialize property 'classifications' from ptsi.service.centers.entity.TrainingCenterEntity
    at org.jboss.resteasy.resteasy-json-binding-provider@3.11.2.Final-redhat-00002//org.jboss.resteasy.plugins.providers.jsonb.JsonBindingProvider.writeTo(JsonBindingProvider.java:160)
    at org.jboss.resteasy.resteasy-jaxrs@3.11.2.Final-redhat-00002//org.jboss.resteasy.core.interception.AbstractWriterInterceptorContext.writeTo(AbstractWriterInterceptorContext.java:137)
    at org.jboss.resteasy.resteasy-jaxrs@3.11.2.Final-redhat-00002//org.jboss.resteasy.core.interception.ServerWriterInterceptorContext.writeTo(ServerWriterInterceptorContext.java:61)
    at org.jboss.resteasy.resteasy-jaxrs@3.11.2.Final-redhat-00002//org.jboss.resteasy.core.interception.AbstractWriterInterceptorContext.proceed(AbstractWriterInterceptorContext.java:124)
    at org.jboss.resteasy.resteasy-crypto@3.11.2.Final-redhat-00002//org.jboss.resteasy.security.doseta.DigitalSigningInterceptor.aroundWriteTo(DigitalSigningInterceptor.java:147)
    at org.jboss.resteasy.resteasy-jaxrs@3.11.2.Final-redhat-00002//org.jboss.resteasy.core.interception.AbstractWriterInterceptorContext.proceed(AbstractWriterInterceptorContext.java:129)
    at org.jboss.resteasy.resteasy-jaxrs@3.11.2.Final-redhat-00002//org.jboss.resteasy.core.ServerResponseWriter.lambda$writeNomapResponse(ServerResponseWriter.java:151)
    at org.jboss.resteasy.resteasy-jaxrs@3.11.2.Final-redhat-00002//org.jboss.resteasy.core.interception.ContainerResponseContextImpl.filter(ContainerResponseContextImpl.java:398)
    at org.jboss.resteasy.resteasy-jaxrs@3.11.2.Final-redhat-00002//org.jboss.resteasy.core.ServerResponseWriter.executeFilters(ServerResponseWriter.java:219)
    at org.jboss.resteasy.resteasy-jaxrs@3.11.2.Final-redhat-00002//org.jboss.resteasy.core.ServerResponseWriter.writeNomapResponse(ServerResponseWriter.java:95)
    at org.jboss.resteasy.resteasy-jaxrs@3.11.2.Final-redhat-00002//org.jboss.resteasy.core.ServerResponseWriter.writeNomapResponse(ServerResponseWriter.java:69)
    at org.jboss.resteasy.resteasy-jaxrs@3.11.2.Final-redhat-00002//org.jboss.resteasy.core.SynchronousDispatcher.writeResponse(SynchronousDispatcher.java:530)
    ... 58 more
Caused by: javax.json.bind.JsonbException: Unable to serialize property 'classifications' from ptsi.service.centers.entity.TrainingCenterEntity
    at org.eclipse.yasson@1.0.5.redhat-00001//org.eclipse.yasson.internal.serializer.ObjectSerializer.serializeInternal(ObjectSerializer.java:67)
    at org.eclipse.yasson@1.0.5.redhat-00001//org.eclipse.yasson.internal.serializer.AbstractContainerSerializer.serialize(AbstractContainerSerializer.java:64)
    at org.eclipse.yasson@1.0.5.redhat-00001//org.eclipse.yasson.internal.serializer.AbstractContainerSerializer.serializerCaptor(AbstractContainerSerializer.java:96)
    at org.eclipse.yasson@1.0.5.redhat-00001//org.eclipse.yasson.internal.serializer.AbstractContainerSerializer.serializeItem(AbstractContainerSerializer.java:157)
    at org.eclipse.yasson@1.0.5.redhat-00001//org.eclipse.yasson.internal.serializer.CollectionSerializer.serializeInternal(CollectionSerializer.java:39)
    at org.eclipse.yasson@1.0.5.redhat-00001//org.eclipse.yasson.internal.serializer.CollectionSerializer.serializeInternal(CollectionSerializer.java:27)
    at org.eclipse.yasson@1.0.5.redhat-00001//org.eclipse.yasson.internal.serializer.AbstractContainerSerializer.serialize(AbstractContainerSerializer.java:64)
    at org.eclipse.yasson@1.0.5.redhat-00001//org.eclipse.yasson.internal.Marshaller.serializeRoot(Marshaller.java:148)
    at org.eclipse.yasson@1.0.5.redhat-00001//org.eclipse.yasson.internal.Marshaller.marshall(Marshaller.java:76)
    at org.eclipse.yasson@1.0.5.redhat-00001//org.eclipse.yasson.internal.Marshaller.marshall(Marshaller.java:102)
    at org.eclipse.yasson@1.0.5.redhat-00001//org.eclipse.yasson.internal.JsonBinding.toJson(JsonBinding.java:118)
    at org.jboss.resteasy.resteasy-json-binding-provider@3.11.2.Final-redhat-00002//org.jboss.resteasy.plugins.providers.jsonb.JsonBindingProvider.writeTo(JsonBindingProvider.java:156)
    ... 69 more
Caused by: org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: ptsi.service.centers.entity.TrainingCenterEntity.classifications, could not initialize proxy - no Session
    at org.hibernate@5.3.16.Final-redhat-00001//org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:602)
    at org.hibernate@5.3.16.Final-redhat-00001//org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:217)
    at org.hibernate@5.3.16.Final-redhat-00001//org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:581)
    at org.hibernate@5.3.16.Final-redhat-00001//org.hibernate.collection.internal.AbstractPersistentCollection.read(AbstractPersistentCollection.java:148)
    at org.hibernate@5.3.16.Final-redhat-00001//org.hibernate.collection.internal.PersistentBag.iterator(PersistentBag.java:390)
    at org.eclipse.yasson@1.0.5.redhat-00001//org.eclipse.yasson.internal.serializer.CollectionSerializer.serializeInternal(CollectionSerializer.java:38)
    at org.eclipse.yasson@1.0.5.redhat-00001//org.eclipse.yasson.internal.serializer.CollectionSerializer.serializeInternal(CollectionSerializer.java:27)
    at org.eclipse.yasson@1.0.5.redhat-00001//org.eclipse.yasson.internal.serializer.AbstractContainerSerializer.serialize(AbstractContainerSerializer.java:64)
    at org.eclipse.yasson@1.0.5.redhat-00001//org.eclipse.yasson.internal.serializer.AbstractContainerSerializer.serializerCaptor(AbstractContainerSerializer.java:96)
    at org.eclipse.yasson@1.0.5.redhat-00001//org.eclipse.yasson.internal.serializer.ObjectSerializer.marshallProperty(ObjectSerializer.java:110)
    at org.eclipse.yasson@1.0.5.redhat-00001//org.eclipse.yasson.internal.serializer.ObjectSerializer.serializeInternal(ObjectSerializer.java:65)
    ... 80 more

另一侧出现同样的错误。使用 EclipseLink 时,它开箱即用,我已经尝试了几天,但我看到的每个示例似乎都没有解决我的具体问题。

为清楚起见,这里是实体一号的边界代码

实体一的资源

@Stateless
@Path("centers")
public class TrainingCenterResource {
    
    @Inject
    TrainingCenterManager manager;

    // POST should return 201 with Location URI in header
    @POST
    @Consumes({MediaType.APPLICATION_JSON})
    public Response save(TrainingCenterEntity center, @Context UriInfo info) {
        TrainingCenterEntity saved = this.manager.save(center);
        String id = saved.getProgramCode();
        URI uri = info.getAbsolutePathBuilder().path("/" + id).build();
        return Response.created(uri).build();
    }

    @GET
    @Path("{id}")
    @Produces({MediaType.APPLICATION_JSON})
    public Response find(@PathParam("id") String id) {
        TrainingCenterEntity center = this.manager.findById(id);
        if (center != null) {
            return Response.ok(center).build();
        }
        else {
            return Response.status(Response.Status.NOT_FOUND).build();
        }
    }
    
    @GET
    @Produces({MediaType.APPLICATION_JSON})
    public List<TrainingCenterEntity> findAll() {
        return this.manager.findAll();
    }

    @PUT
    @Path("{id}")
    @Consumes({MediaType.APPLICATION_JSON})
    @Produces({MediaType.APPLICATION_JSON})
    public TrainingCenterEntity update(@PathParam("id") String id, TrainingCenterEntity center) {
        center.setProgramCode(id);
        return this.manager.save(center);
    }

    @DELETE
    @Path("{id}")
    public void delete(@PathParam("id") String id) {
        this.manager.delete(id);
    }
}

实体一的持久性管理器

@Stateless
public class TrainingCenterManager {

    @Inject
    private Logger LOGGER;

    @Inject
    private EntityManager em;

    
    public TrainingCenterEntity save(TrainingCenterEntity center) {
        try {
            return this.em.merge(center);
        } catch (PersistenceException pex) {
            LOGGER.log(Level.FINE, pex.toString(), pex);
            return null;
        }
    }
    
    public TrainingCenterEntity findById(String code) {
        try {
            return this.em.find(TrainingCenterEntity.class, code);
        } catch (Exception e) {
            LOGGER.log(Level.FINE, e.toString(), e);
            return null;
        }
    }
    
    public List<TrainingCenterEntity> findAll() {
        try {
            return this.em.createNamedQuery(TrainingCenterEntity.findAll, TrainingCenterEntity.class).getResultList();
        } catch (Exception e) {
            LOGGER.log(Level.FINE, e.toString(), e);
            return null;
        }
    }
    
    public void delete(String code) {
        try {
            TrainingCenterEntity reference = this.em.getReference(TrainingCenterEntity.class, code);
            this.em.remove(this.em.merge(reference));
        } catch (PersistenceException pex) {
            LOGGER.log(Level.FINE, pex.toString(), pex);
        }
    }
}

根据规范,您的管理器 EJB 会找到所有实体,然后加载到返回的列表中,但 JPA 默认列表(例如您实体中的分类)作为 延迟加载 字段。

当您的 findAll 方法 returns 时,不再有事务并且列表中的实体从 EntityManager 分离。因此,实体管理器无法加载每个分类字段的内容以允许序列化。

您可以使用一些内部属性更改您的实体管理器的行为,甚至可以将您的分类字段定义为急切获取,但这可能会在您使用 TrainingCenterEntity 而不访问分类字段时引起性能问题(分类将被检索每次获得中心时从数据库中获取)。

最好的方法是将命名查询更改为使用 JOIN FETCH:

@NamedQuery(name = TrainingCenterEntity.findAll, query = "SELECT c FROM TrainingCenterEntity c JOIN FETCH c.classifications")

JOIN FETCH 允许 JPA 预先获取延迟加载字段的内容。

请注意:

  • 任何 findAll 方法都倾向于暴露大量数据;和
  • JSON 序列化库的某些实现不够智能,无法检测循环关系,因此您的分类 -> trainingcenter 如果未正确注释为在序列化时忽略(@JsonIgnore 在 Jackson 案例中),可能会导致堆栈溢出.

您的代码使用 EclipseLink 时没有问题,这可能是因为您的实体不是 static weaved prior execution. Some defaults configurations of EclipseLink also allows to load lazy fields in some different scenarios even with static weaved lazy loaded definitions. In hibernate, the weaving is called bytecode enhancement 而是自动创建的。

在你的方法中添加 @JsonbTransient 注解,returns 一个集合。