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

huangapple go评论65阅读模式
英文:

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

问题

以下是你提供的代码的中文翻译:

实体一

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

    // ... 省略部分代码 ...

    @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 {

    // ... 省略部分代码 ...

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "program_code", referencedColumnName = "program_code")
    private TrainingCenterEntity center;
}

REST端点

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

异常堆栈信息

11:44:03,129 SEVERE [org.eclipse.yasson.internal.Marshaller] (default task-1) 无法序列化属性 'classifications' 来自 ptsi.service.centers.entity.TrainingCenterEntity
11:44:03,129 SEVERE [org.eclipse.yasson.internal.Marshaller] (default task-1) 生成不完整的 JSON
11:44:03,129 INFO  [io.jaegertracing.internal.reporters.LoggingReporter] (default task-1) 报告的跨度:33fb13e2e5f679d8:33fb13e2e5f679d8:0:1 - GET:ptsi.service.centers.boundary.TrainingCenterResource.findAll
11:44:03,129 ERROR [io.undertow.request] (default task-1) 处理请求时出现异常,路径为 /learning-hibernate/api/centers:org.jboss.resteasy.spi.UnhandledException: javax.ws.rs.ProcessingException: RESTEASY008205: JSON 绑定序列化错误 javax.json.bind.JsonbException: 无法序列化属性 'classifications' 来自 ptsi.service.centers.entity.TrainingCenterEntity
    // ... 省略部分异常堆栈信息 ...

资源实体一

@Stateless
@Path("centers")
public class TrainingCenterResource {

    // ... 省略部分代码 ...

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

    // ... 省略部分代码 ...
}

持久化管理器实体一

@Stateless
public class TrainingCenterManager {

    // ... 省略部分代码 ...

    public TrainingCenterEntity save(TrainingCenterEntity center) {
        try {
            return this.em.merge(center);
        } catch (PersistenceException pex) {
            LOGGER.log(Level.FINE, pex.toString(), pex);
            return null;
        }
    }

    // ... 省略部分代码 ...
}

请注意,我已根据你的要求只返回了代码的翻译部分,没有额外的内容。如果你有更多需要翻译的代码或问题,请随时提问。

英文:

I come from a Payara/EclipseLink background where this just works out of the box. My contract requires me to use EAP which does not support EclipseLink.persistance and I always prefer the "provided" over adding libraries.

I am creating a very simple REST microservice with very simple relationships for my objects. However, when I try to access an object, I am getting a serialization error (specifics below).

ENTITY ONE

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

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

	@Id
	@Column(name = &quot;program_code&quot;)
	private String program_code;

	@Column(name = &quot;program_name&quot;, 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&lt;ClassificationEntity&gt;();
	}
	
	public TrainingCenterEntity() {
		this.classifications = new ArrayList&lt;ClassificationEntity&gt;();
	}

	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 = &quot;center&quot;)
    private List&lt;ClassificationEntity&gt; classifications;

ENTITY TWO

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

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

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

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

REST END POINT FOR ENTITY ONE

@GET
@Produces({MediaType.APPLICATION_JSON})
public List&lt;TrainingCenterEntity&gt; findAll() {
  	return this.manager.findAll();
}

StackTrace for REST Endpoint

11:44:03,129 SEVERE [org.eclipse.yasson.internal.Marshaller] (default task-1) Unable to serialize property &#39;classifications&#39; 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 &#39;classifications&#39; 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$4(SynchronousDispatcher.java:229)
at org.jboss.resteasy.resteasy-jaxrs@3.11.2.Final-redhat-00002//org.jboss.resteasy.core.SynchronousDispatcher.lambda$preprocess$0(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$1.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.access$100(ServletInitialHandler.java:78)
at io.undertow.servlet@2.0.30.SP3-redhat-00001//io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:133)
at io.undertow.servlet@2.0.30.SP3-redhat-00001//io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:130)
at io.undertow.servlet@2.0.30.SP3-redhat-00001//io.undertow.servlet.core.ServletRequestContextThreadSetupAction$1.call(ServletRequestContextThreadSetupAction.java:48)
at io.undertow.servlet@2.0.30.SP3-redhat-00001//io.undertow.servlet.core.ContextClassLoaderSetupAction$1.call(ContextClassLoaderSetupAction.java:43)
at org.wildfly.extension.undertow@7.3.1.GA-redhat-00003//org.wildfly.extension.undertow.security.SecurityContextThreadSetupAction.lambda$create$0(SecurityContextThreadSetupAction.java:105)
at org.wildfly.extension.undertow@7.3.1.GA-redhat-00003//org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1541)
at org.wildfly.extension.undertow@7.3.1.GA-redhat-00003//org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1541)
at org.wildfly.extension.undertow@7.3.1.GA-redhat-00003//org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1541)
at org.wildfly.extension.undertow@7.3.1.GA-redhat-00003//org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1541)
at org.wildfly.extension.undertow@7.3.1.GA-redhat-00003//org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(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$000(ServletInitialHandler.java:78)
at io.undertow.servlet@2.0.30.SP3-redhat-00001//io.undertow.servlet.handlers.ServletInitialHandler$1.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$1.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 &#39;classifications&#39; 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$2(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 &#39;classifications&#39; 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

The same error appears for the other side. When using EclipseLink, this just works out of the box, and I have tried a couple fo days but every example I have seen does not seem to address my specific issue.

For Clarity, here is the boundary code for ENTITY ONE

RESOURCE for ENTITY ONE

@Stateless
@Path(&quot;centers&quot;)
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(&quot;/&quot; + id).build();
return Response.created(uri).build();
}
@GET
@Path(&quot;{id}&quot;)
@Produces({MediaType.APPLICATION_JSON})
public Response find(@PathParam(&quot;id&quot;) 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&lt;TrainingCenterEntity&gt; findAll() {
return this.manager.findAll();
}
@PUT
@Path(&quot;{id}&quot;)
@Consumes({MediaType.APPLICATION_JSON})
@Produces({MediaType.APPLICATION_JSON})
public TrainingCenterEntity update(@PathParam(&quot;id&quot;) String id, TrainingCenterEntity center) {
center.setProgramCode(id);
return this.manager.save(center);
}
@DELETE
@Path(&quot;{id}&quot;)
public void delete(@PathParam(&quot;id&quot;) String id) {
this.manager.delete(id);
}
}

PERSISTANCE MANAGER FOR ENTITY ONE

@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&lt;TrainingCenterEntity&gt; 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);
}
}
}

答案1

得分: 2

根据规范,您的管理器 EJB 查找所有实体并将它们加载到返回的 List 中,但是 JPA 默认将列表(例如实体中的 classifications)视为 惰性加载 字段。

当您的 findAll 方法返回时,就不再有事务,列表中的实体与 EntityManager 分离。因此,实体管理器无法加载每个 classifications 字段的内容以进行序列化。

您可以通过一些内部属性来更改实体管理器的行为,甚至将 classifications 字段定义为 eager fetched,但这可能会在您在不访问 classifications 字段的情况下使用 TrainingCenterEntity 时引起性能问题(每次获取中心时都会从数据库检索 classifications)。

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

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

JOIN FETCH 允许 JPA 主动提取惰性加载字段的内容。

请注意:

  • 任何 findAll 方法往往会暴露出太多数据;以及
  • 某些 JSON 序列化库的实现不足以检测到循环关系,因此您的 classification -> trainingcenter 关系可能会在序列化时引发堆栈溢出,除非在序列化时正确地标注为忽略(在 Jackson 中使用 @JsonIgnore)。

您的代码在使用 EclipseLink 时无问题,可能是因为您的实体在执行之前没有进行 静态织入。EclipseLink 的一些默认配置也允许在某些不同的情况下加载惰性字段,即使使用了静态织入的惰性加载定义。在 Hibernate 中,这种织入被称为 字节码增强,并且是自动完成的。

英文:

Per spec, your manager EJB finds all entities and loads then into the returned List<TrainingCenterEntity>, but JPA defaults lists - such as classifications in your entity - as lazy loaded fields.

When your findAll method returns, there is no more transaction and the entities inside the lists became detached from the EntityManager. As such, the entity manager can't to load the contents of each classifications field to allow serialization.

You may change the behavior of your entity manager using some internal properties or even define your classifications field as eager fetched, but this may induce performance problems when you use the TrainingCenterEntity without accessing the classifications field (the classifications will be retrieved from database every time you get a center).

Your best approach is changing your named query to use JOIN FETCH:

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

JOIN FETCH allows the JPA to eager fetch the contents of otherwise lazy loaded fields.

Please note that:

  • any findAll method tends to expose to much data; and
  • some implementations of JSON serialization libraries are not intelligent enough to detect circular relations, so your classification -> trainingcenter may cause a stack overflow if not properly annotated as ignored on serialization (@JsonIgnore in Jackson case).

Your code works without issues using EclipseLink probably because your entities weren't 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 and it's made automatically.

答案2

得分: 0

在返回集合的方法中添加 @JsonbTransient 注解。

英文:

Add @JsonbTransient Annotation in your method which returns a Collection.

huangapple
  • 本文由 发表于 2020年8月26日 23:52:48
  • 转载请务必保留本文链接:https://go.coder-hub.com/63601273.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定