使用 SAP APM 和 S/4HANA Cloud SDK 时 OData 导航 returns 异常
OData navigation returns exception when using SAP APM and S/4HANA Cloud SDK
我在 SAP Web IDE 全栈中创建了一个 APM 业务应用程序。
S/4HANA SDK 读取业务合作伙伴 S/4HANA API。自定义业务伙伴数据保存在 SAP Cloud Platform HDI 容器中。业务伙伴实体与自定义实体具有 0..1 关联。
当自定义数据存在时 OData 导航 属性 成功,但当自定义数据不存在时 return 出现空指针异常。 OData $expand 在这两种情况下都不成功,returning error while trying to invoke the method java.util.Map.size() of a null object loaded from local variable 'm'
。我可能错误地期望关联实体 return 键 属性 的值而不是其他属性的值。
以下是数据模型、服务、业务合作伙伴操作、错误和日志。
数据模型CDS
entity BusinessPartner {
Key BusinessPartner : String(10);
LastName : String(40);
FirstName : String(40);
status : Association to PartnerStatus;
}
entity PartnerStatus {
Key BusinessPartner : String(10);
StatusConfirmed : String(1);
}
服务 CDS
service BusinessPartnerService {
@cds.persistence.skip
entity BusinessPartner @readonly as projection on s4c.BusinessPartner;
entity PartnerStatus @readonly as projection on s4c.PartnerStatus;
}
业务合作伙伴@Query 和@Read
@Query(serviceName = "BusinessPartnerService", entity = "BusinessPartner")
public QueryResponse queryPartners(QueryRequest queryRequest) throws ServletException {
final List<BusinessPartner> businessPartners;
try {
businessPartners = new DefaultBusinessPartnerService()
.getAllBusinessPartner()
.top(5)
.execute();
} catch (ODataException e) {
throw new ServletException(e);
}
QueryResponse queryResponse = QueryResponse.setSuccess().setData(businessPartners).response();
return queryResponse;
}
@Read(serviceName = "BusinessPartnerService", entity = "BusinessPartner")
public ReadResponse readPartner(ReadRequest readRequest) throws ServletException {
String id = String.valueOf(readRequest.getKeys().get("BusinessPartner"));
final BusinessPartner businessPartner;
try {
businessPartner = new DefaultBusinessPartnerService()
.getBusinessPartnerByKey(id)
.execute();
} catch (ODataException e) {
throw new ServletException(e);
}
ReadResponse readResponse = ReadResponse.setSuccess().setData(businessPartner).response();
return readResponse;
}
错误
<error xmlns="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata">
<code>CDSRuntimeException.NO_ENTITY_FOUND</code>
<message xml:lang="en-US">No Entity found for the URL.</message>
</error>
日志
2018-11-06T11:02:50.53-0500 [APP/PROC/WEB/0] OUT { "written_at":"2018-11-06T16:02:50.538Z","written_ts":1056610886992277,"component_id":"df464a53-1905-4c4b-bcc5-ef59761d2218","component_name":"ge2qqww1rr7SxSEK-apm-s4c-srv","DCComponent":"","organization_name":"-","component_type":"application","space_name":"dev","component_instance":"0","organization_id":"-","correlation_id":"-","CSNComponent":"","space_id":"5e8e1eb0-f9ca-40d8-8ba9-1880ca345628","Application":"ge2qqww1rr7SxSEK-apm-s4c-srv","container_id":"10.0.137.3","type":"log","logger":"com.sap.cloud.sdk.service.prov.v2.rt.core.CloudSDKODataErrorCallback","thread":"http-nio-0.0.0.0-3000-exec-2","level":"ERROR","categories":[],"msg":"Request URL: https://ge2qqww1rr7sxsek-apm-s4c-srv.cfapps.us10.hana.ondemand.com/odata/v2/BusinessPartnerService/BusinessPartner?$expand=status\nStatusCode:500","stacktrace":["java.lang.NullPointerException: while trying to invoke the method java.util.Map.size() of a null object loaded from local variable 'm'","\tat java.util.HashMap.putMapEntries(HashMap.java:501)","\tat java.util.HashMap.putAll(HashMap.java:785)","\tat com.sap.gateway.core.api.provider.data.BaseDataProvider.getSingleNavigationPathResult(BaseDataProvider.java:837)","\tat com.sap.gateway.core.api.provider.data.BaseDataProvider.readExpandedEntitySet(BaseDataProvider.java:915)","\tat com.sap.cloud.sdk.service.prov.v2.data.provider.CXSDataProvider.readExpandedEntitySet(CXSDataProvider.java:724)","\tat com.sap.cloud.sdk.service.prov.v2.rt.data.provider.HybridDataProvider.readExpandedEntitySet(HybridDataProvider.java:298)","\tat com.sap.gateway.core.api.provider.data.GenericODataProcessor.readEntitySet(GenericODataProcessor.java:895)","\tat org.apache.olingo.odata2.core.Dispatcher.dispatch(Dispatcher.java:77)","\tat org.apache.olingo.odata2.core.ODataRequestHandler.handle(ODataRequestHandler.java:131)","\tat org.apache.olingo.odata2.core.servlet.ODataServlet.handleRequest(ODataServlet.java:216)","\tat org.apache.olingo.odata2.core.servlet.ODataServlet.handle(ODataServlet.java:115)","\tat org.apache.olingo.odata2.core.servlet.ODataServlet.service(ODataServlet.java:85)","\tat javax.servlet.http.HttpServlet.service(HttpServlet.java:742)","\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)","\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)","\tat org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)","\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)","\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)","\tat com.sap.cloud.sdk.cloudplatform.servlet.RequestContextServletFilter.lambda$doFilter[=16=](RequestContextServletFilter.java:171)","\tat com.sap.cloud.sdk.cloudplatform.servlet.RequestContextCallable.call(RequestContextCallable.java:95)","\tat com.sap.cloud.sdk.cloudplatform.servlet.RequestContextServletFilter.doFilter(RequestContextServletFilter.java:173)","\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)","\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)","\tat org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198)","\tat org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)","\tat org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:493)","\tat org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)","\tat com.sap.xs.java.valves.ErrorReportValve.invoke(ErrorReportValve.java:66)","\tat ch.qos.logback.access.tomcat.LogbackValve.invoke(LogbackValve.java:191)","\tat org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)","\tat com.sap.xs.jdbc.datasource.valve.JDBCValve.invoke(JDBCValve.java:62)","\tat com.sap.xs.security.UserInfoValve.invoke(UserInfoValve.java:19)","\tat com.sap.xs.statistics.tomcat.valve.RequestTracingValve.invoke(RequestTracingValve.java:43)","\tat com.sap.xs.logging.catalina.RuntimeInfoValve.invoke(RuntimeInfoValve.java:40)","\tat org.apache.catalina.valves.RemoteIpValve.invoke(RemoteIpValve.java:685)","\tat org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342)","\tat org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:800)","\tat org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)","\tat org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:800)","\tat org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1471)","\tat org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)","\tat java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)","\tat java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)","\tat org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)","\tat java.lang.Thread.run(Thread.java:836)"] }
远程实体和本地实体之间的连接不会自动发生。您必须使用关联实体 PartnerStatus 的读取操作手动实现此操作,该关联实体还指定导航 BusinessPartner 的源实体。
此方法如下所示(如您所见,在此示例中我总是返回虚拟数据):
@Read(serviceName = "BusinessPartnerService",
entity = "PartnerStatus",
sourceEntity = "BusinessPartner")
public ReadResponse readPartnerStatus(ReadRequest readRequest) throws ServletException {
return ReadResponse.setSuccess().setData(
ImmutableMap.of("BusinessPartner", "1003764", "StatusConfirmed", "X"))
.response();
}
documentation about the Read operation 包含有关此概念的更多详细信息。
您现在需要访问数据库,例如,在处理程序中使用 JPA(我还没有尝试过)。该文档有一节关于 Using JPA in Custom Handlers.
我使用 CDSDataSourceHandler 读取本地实体。
如果本地实体存在,则返回。如果本地实体不存在,则将密钥从源实体传递给实体。
private static Connection getConnection() {
Connection conn = null;
Context ctx;
try {
ctx = new InitialContext();
conn = ((DataSource) ctx.lookup("java:comp/env/jdbc/java-hdi-container")).getConnection();
} catch (Exception e) {
e.printStackTrace();
}
return conn;
}
@Read(serviceName = "BusinessPartnerService", entity = "PartnerStatus", sourceEntity = "BusinessPartner")
public ReadResponse readPartnerStatus(ReadRequest readRequest) {
CDSDataSourceHandler dsHandler = DataSourceHandlerFactory.getInstance().getCDSHandler(getConnection(), readRequest.getEntityMetadata().getNamespace());
EntityData ed = null;
try {
ed = dsHandler.executeRead(readRequest.getEntityMetadata().getName(), readRequest.getKeys(), readRequest.getEntityMetadata().getElementNames());
} catch (CDSException e) { }
if (ed != null) {
return ReadResponse.setSuccess().setData(ed).response();
} else {
Map<String, Object> keys = readRequest.getKeys();
Object keyObject = keys.get("BusinessPartner");
String id = (String)keyObject;
return ReadResponse.setSuccess().setData(ImmutableMap.of("BusinessPartner", id, "StatusConfirmed", "X")).response();
}
}
OData $expand 对实体和实体集都是成功的。
我在 SAP Web IDE 全栈中创建了一个 APM 业务应用程序。
S/4HANA SDK 读取业务合作伙伴 S/4HANA API。自定义业务伙伴数据保存在 SAP Cloud Platform HDI 容器中。业务伙伴实体与自定义实体具有 0..1 关联。
当自定义数据存在时 OData 导航 属性 成功,但当自定义数据不存在时 return 出现空指针异常。 OData $expand 在这两种情况下都不成功,returning error while trying to invoke the method java.util.Map.size() of a null object loaded from local variable 'm'
。我可能错误地期望关联实体 return 键 属性 的值而不是其他属性的值。
以下是数据模型、服务、业务合作伙伴操作、错误和日志。
数据模型CDS
entity BusinessPartner {
Key BusinessPartner : String(10);
LastName : String(40);
FirstName : String(40);
status : Association to PartnerStatus;
}
entity PartnerStatus {
Key BusinessPartner : String(10);
StatusConfirmed : String(1);
}
服务 CDS
service BusinessPartnerService {
@cds.persistence.skip
entity BusinessPartner @readonly as projection on s4c.BusinessPartner;
entity PartnerStatus @readonly as projection on s4c.PartnerStatus;
}
业务合作伙伴@Query 和@Read
@Query(serviceName = "BusinessPartnerService", entity = "BusinessPartner")
public QueryResponse queryPartners(QueryRequest queryRequest) throws ServletException {
final List<BusinessPartner> businessPartners;
try {
businessPartners = new DefaultBusinessPartnerService()
.getAllBusinessPartner()
.top(5)
.execute();
} catch (ODataException e) {
throw new ServletException(e);
}
QueryResponse queryResponse = QueryResponse.setSuccess().setData(businessPartners).response();
return queryResponse;
}
@Read(serviceName = "BusinessPartnerService", entity = "BusinessPartner")
public ReadResponse readPartner(ReadRequest readRequest) throws ServletException {
String id = String.valueOf(readRequest.getKeys().get("BusinessPartner"));
final BusinessPartner businessPartner;
try {
businessPartner = new DefaultBusinessPartnerService()
.getBusinessPartnerByKey(id)
.execute();
} catch (ODataException e) {
throw new ServletException(e);
}
ReadResponse readResponse = ReadResponse.setSuccess().setData(businessPartner).response();
return readResponse;
}
错误
<error xmlns="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata">
<code>CDSRuntimeException.NO_ENTITY_FOUND</code>
<message xml:lang="en-US">No Entity found for the URL.</message>
</error>
日志
2018-11-06T11:02:50.53-0500 [APP/PROC/WEB/0] OUT { "written_at":"2018-11-06T16:02:50.538Z","written_ts":1056610886992277,"component_id":"df464a53-1905-4c4b-bcc5-ef59761d2218","component_name":"ge2qqww1rr7SxSEK-apm-s4c-srv","DCComponent":"","organization_name":"-","component_type":"application","space_name":"dev","component_instance":"0","organization_id":"-","correlation_id":"-","CSNComponent":"","space_id":"5e8e1eb0-f9ca-40d8-8ba9-1880ca345628","Application":"ge2qqww1rr7SxSEK-apm-s4c-srv","container_id":"10.0.137.3","type":"log","logger":"com.sap.cloud.sdk.service.prov.v2.rt.core.CloudSDKODataErrorCallback","thread":"http-nio-0.0.0.0-3000-exec-2","level":"ERROR","categories":[],"msg":"Request URL: https://ge2qqww1rr7sxsek-apm-s4c-srv.cfapps.us10.hana.ondemand.com/odata/v2/BusinessPartnerService/BusinessPartner?$expand=status\nStatusCode:500","stacktrace":["java.lang.NullPointerException: while trying to invoke the method java.util.Map.size() of a null object loaded from local variable 'm'","\tat java.util.HashMap.putMapEntries(HashMap.java:501)","\tat java.util.HashMap.putAll(HashMap.java:785)","\tat com.sap.gateway.core.api.provider.data.BaseDataProvider.getSingleNavigationPathResult(BaseDataProvider.java:837)","\tat com.sap.gateway.core.api.provider.data.BaseDataProvider.readExpandedEntitySet(BaseDataProvider.java:915)","\tat com.sap.cloud.sdk.service.prov.v2.data.provider.CXSDataProvider.readExpandedEntitySet(CXSDataProvider.java:724)","\tat com.sap.cloud.sdk.service.prov.v2.rt.data.provider.HybridDataProvider.readExpandedEntitySet(HybridDataProvider.java:298)","\tat com.sap.gateway.core.api.provider.data.GenericODataProcessor.readEntitySet(GenericODataProcessor.java:895)","\tat org.apache.olingo.odata2.core.Dispatcher.dispatch(Dispatcher.java:77)","\tat org.apache.olingo.odata2.core.ODataRequestHandler.handle(ODataRequestHandler.java:131)","\tat org.apache.olingo.odata2.core.servlet.ODataServlet.handleRequest(ODataServlet.java:216)","\tat org.apache.olingo.odata2.core.servlet.ODataServlet.handle(ODataServlet.java:115)","\tat org.apache.olingo.odata2.core.servlet.ODataServlet.service(ODataServlet.java:85)","\tat javax.servlet.http.HttpServlet.service(HttpServlet.java:742)","\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)","\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)","\tat org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)","\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)","\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)","\tat com.sap.cloud.sdk.cloudplatform.servlet.RequestContextServletFilter.lambda$doFilter[=16=](RequestContextServletFilter.java:171)","\tat com.sap.cloud.sdk.cloudplatform.servlet.RequestContextCallable.call(RequestContextCallable.java:95)","\tat com.sap.cloud.sdk.cloudplatform.servlet.RequestContextServletFilter.doFilter(RequestContextServletFilter.java:173)","\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)","\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)","\tat org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198)","\tat org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)","\tat org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:493)","\tat org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)","\tat com.sap.xs.java.valves.ErrorReportValve.invoke(ErrorReportValve.java:66)","\tat ch.qos.logback.access.tomcat.LogbackValve.invoke(LogbackValve.java:191)","\tat org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)","\tat com.sap.xs.jdbc.datasource.valve.JDBCValve.invoke(JDBCValve.java:62)","\tat com.sap.xs.security.UserInfoValve.invoke(UserInfoValve.java:19)","\tat com.sap.xs.statistics.tomcat.valve.RequestTracingValve.invoke(RequestTracingValve.java:43)","\tat com.sap.xs.logging.catalina.RuntimeInfoValve.invoke(RuntimeInfoValve.java:40)","\tat org.apache.catalina.valves.RemoteIpValve.invoke(RemoteIpValve.java:685)","\tat org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342)","\tat org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:800)","\tat org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)","\tat org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:800)","\tat org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1471)","\tat org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)","\tat java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)","\tat java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)","\tat org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)","\tat java.lang.Thread.run(Thread.java:836)"] }
远程实体和本地实体之间的连接不会自动发生。您必须使用关联实体 PartnerStatus 的读取操作手动实现此操作,该关联实体还指定导航 BusinessPartner 的源实体。 此方法如下所示(如您所见,在此示例中我总是返回虚拟数据):
@Read(serviceName = "BusinessPartnerService",
entity = "PartnerStatus",
sourceEntity = "BusinessPartner")
public ReadResponse readPartnerStatus(ReadRequest readRequest) throws ServletException {
return ReadResponse.setSuccess().setData(
ImmutableMap.of("BusinessPartner", "1003764", "StatusConfirmed", "X"))
.response();
}
documentation about the Read operation 包含有关此概念的更多详细信息。
您现在需要访问数据库,例如,在处理程序中使用 JPA(我还没有尝试过)。该文档有一节关于 Using JPA in Custom Handlers.
我使用 CDSDataSourceHandler 读取本地实体。
如果本地实体存在,则返回。如果本地实体不存在,则将密钥从源实体传递给实体。
private static Connection getConnection() {
Connection conn = null;
Context ctx;
try {
ctx = new InitialContext();
conn = ((DataSource) ctx.lookup("java:comp/env/jdbc/java-hdi-container")).getConnection();
} catch (Exception e) {
e.printStackTrace();
}
return conn;
}
@Read(serviceName = "BusinessPartnerService", entity = "PartnerStatus", sourceEntity = "BusinessPartner")
public ReadResponse readPartnerStatus(ReadRequest readRequest) {
CDSDataSourceHandler dsHandler = DataSourceHandlerFactory.getInstance().getCDSHandler(getConnection(), readRequest.getEntityMetadata().getNamespace());
EntityData ed = null;
try {
ed = dsHandler.executeRead(readRequest.getEntityMetadata().getName(), readRequest.getKeys(), readRequest.getEntityMetadata().getElementNames());
} catch (CDSException e) { }
if (ed != null) {
return ReadResponse.setSuccess().setData(ed).response();
} else {
Map<String, Object> keys = readRequest.getKeys();
Object keyObject = keys.get("BusinessPartner");
String id = (String)keyObject;
return ReadResponse.setSuccess().setData(ImmutableMap.of("BusinessPartner", id, "StatusConfirmed", "X")).response();
}
}
OData $expand 对实体和实体集都是成功的。