在 SAP Cloud SDK 中使用 Java 为 SFSF 生成 VDM:生成的 URI 错误
Generate VDM for SFSF using Java in SAP Cloud SDK: Generated URI is wrong
我正在尝试构建一个从 SFSF 读取信息的应用程序。为此,我使用带有 SFSF OData 元数据的虚拟数据模型生成器工具(maven 插件)来访问系统。我正在执行以下步骤:
- 通过原型获取项目(使用 powershell):
mvn archetype:generate "-DarchetypeGroupId=com.sap.cloud.sdk.archetypes" "-DarchetypeArtifactId=scp-cf-tomee" "-DarchetypeVersion=RELEASE"
- 将以下内容添加到 application\pom。xml
在依赖项中:
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
在插件中:
<plugin>
<groupId>com.sap.cloud.sdk.datamodel</groupId>
<artifactId>odata-generator-maven-plugin</artifactId>
<version>3.13.0</version>
<executions>
<execution>
<id>generate-consumption</id>
<phase>generate-sources</phase>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<inputDirectory>${project.basedir}/edmx</inputDirectory>
<outputDirectory>${project.build.directory}/vdm</outputDirectory>
<defaultBasePath>/odata/v2</defaultBasePath>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>add-source</goal>
</goals>
<configuration>
<sources>
<source>${project.basedir}/vdm</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
- 从 https://apisalesdemo2.successfactors.eu/odata/v2/JobRequisition/$metadata 获取 OData 元数据文件并将其放入 ./application/edmx
- 创建目标服务(我的目标)并在其中添加一个目标,指向我的具有基本身份验证的 SFSF 实例(使用 user@companyId,连接是 200:OK)
- 在manifest.yml
中添加目标服务
- 创建一个java class来调用目的地并获取数据:
package com.sap.sdk;
import com.google.gson.Gson;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
import com.sap.cloud.sdk.cloudplatform.connectivity.DestinationAccessor;
import com.sap.cloud.sdk.odatav2.connectivity.ODataException;
import com.sap.cloud.sdk.s4hana.connectivity.DefaultErpHttpDestination;
import com.sap.cloud.sdk.s4hana.connectivity.ErpHttpDestination;
import com.sap.cloud.sdk.s4hana.datamodel.odata.namespaces.rcmjobrequisition.JobRequisition;
import com.sap.cloud.sdk.s4hana.datamodel.odata.services.DefaultRCMJobRequisitionService;
@WebServlet("/req")
public class JobReqServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
private static final Logger logger = LoggerFactory.getLogger(JobReqServlet.class);
private final ErpHttpDestination destination = DestinationAccessor.getDestination("sfsf-sdk-dest").asHttp()
.decorate(DefaultErpHttpDestination::new);
@Override
protected void doGet(final HttpServletRequest request, final HttpServletResponse response)
throws ServletException, IOException {
try {
final List<JobRequisition> jobReqs = new DefaultRCMJobRequisitionService()
.getAllJobRequisition()
.execute(destination);
response.setContentType("application/json");
response.getWriter().write(new Gson().toJson(jobReqs));
} catch (final ODataException e) {
logger.error(e.getMessage(), e);
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
response.getWriter().write(e.getMessage());
}
}
}
有了这一切(我想我没有遗漏任何东西),我做到了:
mvn clean install
和:
cf push
一切正常,hello world servlet 正常,但是当我尝试访问 /req 时,我得到:
无法执行元数据请求。
但是,我可以看到该应用正在访问 SFSF,因为如果我使用服务的基本路径(在 pom.xml 中),我会收到来自 SFSF 的 404。
检查所有内容,当 VDM 生成器为 运行 时我看到了这个:
1. 这是我在 pom 中给出的基本路径:
<defaultBasePath>/odata/v2</defaultBasePath>
- 我可以看到生成器正确选择了该路径:
[main] INFO com.sap.cloud.sdk.datamodel.odata.generator.DataModelGenerator - Default base path: /odata/v2/
- 但这就是生成器处理的内容:
[main] INFO com.sap.cloud.sdk.datamodel.odata.generator.ODataToVdmGenerator - Title: RCMJobRequisition
[main] INFO com.sap.cloud.sdk.datamodel.odata.generator.ODataToVdmGenerator - Raw URL: /odata/v2/SFODataSet
[main] INFO com.sap.cloud.sdk.datamodel.odata.generator.ODataToVdmGenerator - Java Package Name: rcmjobrequisition
[main] INFO com.sap.cloud.sdk.datamodel.odata.generator.ODataToVdmGenerator - Java Class Name: RCMJobRequisition
显然,URL 中的 SFODataSet 是不正确的。当应用程序运行时,它试图从 .../odata/v2/SFODataSet/$metadata 获取元数据,这就是它找不到它的原因。
SFODataSet 来自 SFSF 元数据:
<Schema Namespace="SFODataSet" xmlns="http://schemas.microsoft.com/ado/2008/09/edm" xmlns:sf="http://www.successfactors.com/edm/sf" xmlns:sap="http://www.sap.com/Protocols/SAPData">
<EntityContainer Name="EntityContainer" m:IsDefaultEntityContainer="true">
<EntitySet Name="JobOfferTemplate_Standard_Offer_Details" EntityType="SFOData.JobOfferTemplate_Standard_Offer_Details" sap:label="JobOfferTemplate_Standard_Offer_Details" sap:creatable="false" sap:updatable="false" sap:upsertable="false" sap:deletable="false">
<Documentation>
<Summary>Job Requisition Template</Summary>
<LongDescription>These entities represent the job requisition template as defined in provisioning.</LongDescription>
<sap:tagcollection>
<sap:tag>Recruiting (RCM)</sap:tag>
<sap:tag>RCM - Job Requisition</sap:tag>
</sap:tagcollection>
</Documentation>
</EntitySet>
<EntitySet Name="JobRequisitionLocale" EntityType="SFOData.JobRequisitionLocale" sap:label="JobRequisitionLocale" sap:creatable="false" sap:updatable="false" sap:upsertable="false" sap:deletable="false">
<Documentation>
...
我找不到让它工作的方法。你能帮我找到这里的问题吗?
我正在使用:
- 阿帕奇行家 3.6.2
- SAP 云 SDK 3.13.0
编辑:
SFSF 元数据文件在 https://api.sap.com/ 中可用
我在这个应用程序中使用的是 SFSF - Job Requisition,可在此处获取:
https://api.sap.com/api/RCMJobRequisition/overview
从那里,您可以下载 EDMX 规范。这些是 "mock" API 的,没有连接到真正的 SFSF 实例,但问题是一样的。
为此,我主要关注两个博客:
- https://blogs.sap.com/2018/04/30/deep-dive-10-with-sap-s4hana-cloud-sdk-generating-java-vdm-for-s4hana-custom-odata-service/
- https://blogs.sap.com/2019/05/06/create-an-application-with-sap-cloud-sdk-to-integrate-with-sap-successfactors/
此外,我删除了最后一部分,因为我将打开一个单独的问题:
谢谢,
配对
我将从部分答案开始,如果需要,稍后会编辑更多信息。
关于 URL:
您观察到的行为是故意的。请求的完整 URL 将组合如下:目标 URL + 服务路径 + 服务名称 + 实体 + '?' + 查询参数。所以在你的情况下可能是:
https://my.host.domain/odata/v2/JobRequisitions/MyEntity
Destination: https://my.host.domain
Service Path: /odata/v2
Service name: JobRequisitions
Entity: MyEntity
生成器从 service path + service name
组装默认基本路径。 service name
实际上是从 EDMX 的命名空间中提取的。这就是为什么您的服务 URL 会按原样生成的原因。
原因很简单:人们可能希望同时为多个服务生成一个 VDM。除服务名称本身外,所有这些服务都在同一个端点下公开。为了使用一种配置生成所有 VDM,我们可以在生成器中指定 "service path",然后生成器从 EDXM 本身中提取服务名称。
这意味着您覆盖生成的基本路径的方法应该有效:
final List<JobRequisition> jobReqs = new DefaultRCMJobRequisitionService()
.withServicePath("odata/v2/JobRequisition")
.getAllJobRequisition()
.execute(destination);
你问题最后的错误信息对我来说有点像解析问题。但是为了进一步解决这个问题,我们需要完整的堆栈跟踪和 HTTP 日志输出。此外,如果我们可以访问元数据,我们只能重现问题。您提供的 link 需要通过 username/password 授权。
由于你上面的问题已经很全面了,如果这真的是一个独立的问题,我建议你将这两个问题分开并创建一个新问题。这也将使这两个问题与其他问题更相关。
我正在尝试构建一个从 SFSF 读取信息的应用程序。为此,我使用带有 SFSF OData 元数据的虚拟数据模型生成器工具(maven 插件)来访问系统。我正在执行以下步骤:
- 通过原型获取项目(使用 powershell):
mvn archetype:generate "-DarchetypeGroupId=com.sap.cloud.sdk.archetypes" "-DarchetypeArtifactId=scp-cf-tomee" "-DarchetypeVersion=RELEASE"
- 将以下内容添加到 application\pom。xml 在依赖项中:
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
在插件中:
<plugin>
<groupId>com.sap.cloud.sdk.datamodel</groupId>
<artifactId>odata-generator-maven-plugin</artifactId>
<version>3.13.0</version>
<executions>
<execution>
<id>generate-consumption</id>
<phase>generate-sources</phase>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<inputDirectory>${project.basedir}/edmx</inputDirectory>
<outputDirectory>${project.build.directory}/vdm</outputDirectory>
<defaultBasePath>/odata/v2</defaultBasePath>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>add-source</goal>
</goals>
<configuration>
<sources>
<source>${project.basedir}/vdm</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
- 从 https://apisalesdemo2.successfactors.eu/odata/v2/JobRequisition/$metadata 获取 OData 元数据文件并将其放入 ./application/edmx
- 创建目标服务(我的目标)并在其中添加一个目标,指向我的具有基本身份验证的 SFSF 实例(使用 user@companyId,连接是 200:OK)
- 在manifest.yml 中添加目标服务
- 创建一个java class来调用目的地并获取数据:
package com.sap.sdk;
import com.google.gson.Gson;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
import com.sap.cloud.sdk.cloudplatform.connectivity.DestinationAccessor;
import com.sap.cloud.sdk.odatav2.connectivity.ODataException;
import com.sap.cloud.sdk.s4hana.connectivity.DefaultErpHttpDestination;
import com.sap.cloud.sdk.s4hana.connectivity.ErpHttpDestination;
import com.sap.cloud.sdk.s4hana.datamodel.odata.namespaces.rcmjobrequisition.JobRequisition;
import com.sap.cloud.sdk.s4hana.datamodel.odata.services.DefaultRCMJobRequisitionService;
@WebServlet("/req")
public class JobReqServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
private static final Logger logger = LoggerFactory.getLogger(JobReqServlet.class);
private final ErpHttpDestination destination = DestinationAccessor.getDestination("sfsf-sdk-dest").asHttp()
.decorate(DefaultErpHttpDestination::new);
@Override
protected void doGet(final HttpServletRequest request, final HttpServletResponse response)
throws ServletException, IOException {
try {
final List<JobRequisition> jobReqs = new DefaultRCMJobRequisitionService()
.getAllJobRequisition()
.execute(destination);
response.setContentType("application/json");
response.getWriter().write(new Gson().toJson(jobReqs));
} catch (final ODataException e) {
logger.error(e.getMessage(), e);
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
response.getWriter().write(e.getMessage());
}
}
}
有了这一切(我想我没有遗漏任何东西),我做到了:
mvn clean install
和:
cf push
一切正常,hello world servlet 正常,但是当我尝试访问 /req 时,我得到: 无法执行元数据请求。
但是,我可以看到该应用正在访问 SFSF,因为如果我使用服务的基本路径(在 pom.xml 中),我会收到来自 SFSF 的 404。
检查所有内容,当 VDM 生成器为 运行 时我看到了这个: 1. 这是我在 pom 中给出的基本路径:
<defaultBasePath>/odata/v2</defaultBasePath>
- 我可以看到生成器正确选择了该路径:
[main] INFO com.sap.cloud.sdk.datamodel.odata.generator.DataModelGenerator - Default base path: /odata/v2/
- 但这就是生成器处理的内容:
[main] INFO com.sap.cloud.sdk.datamodel.odata.generator.ODataToVdmGenerator - Title: RCMJobRequisition
[main] INFO com.sap.cloud.sdk.datamodel.odata.generator.ODataToVdmGenerator - Raw URL: /odata/v2/SFODataSet
[main] INFO com.sap.cloud.sdk.datamodel.odata.generator.ODataToVdmGenerator - Java Package Name: rcmjobrequisition
[main] INFO com.sap.cloud.sdk.datamodel.odata.generator.ODataToVdmGenerator - Java Class Name: RCMJobRequisition
显然,URL 中的 SFODataSet 是不正确的。当应用程序运行时,它试图从 .../odata/v2/SFODataSet/$metadata 获取元数据,这就是它找不到它的原因。 SFODataSet 来自 SFSF 元数据:
<Schema Namespace="SFODataSet" xmlns="http://schemas.microsoft.com/ado/2008/09/edm" xmlns:sf="http://www.successfactors.com/edm/sf" xmlns:sap="http://www.sap.com/Protocols/SAPData">
<EntityContainer Name="EntityContainer" m:IsDefaultEntityContainer="true">
<EntitySet Name="JobOfferTemplate_Standard_Offer_Details" EntityType="SFOData.JobOfferTemplate_Standard_Offer_Details" sap:label="JobOfferTemplate_Standard_Offer_Details" sap:creatable="false" sap:updatable="false" sap:upsertable="false" sap:deletable="false">
<Documentation>
<Summary>Job Requisition Template</Summary>
<LongDescription>These entities represent the job requisition template as defined in provisioning.</LongDescription>
<sap:tagcollection>
<sap:tag>Recruiting (RCM)</sap:tag>
<sap:tag>RCM - Job Requisition</sap:tag>
</sap:tagcollection>
</Documentation>
</EntitySet>
<EntitySet Name="JobRequisitionLocale" EntityType="SFOData.JobRequisitionLocale" sap:label="JobRequisitionLocale" sap:creatable="false" sap:updatable="false" sap:upsertable="false" sap:deletable="false">
<Documentation>
...
我找不到让它工作的方法。你能帮我找到这里的问题吗?
我正在使用:
- 阿帕奇行家 3.6.2
- SAP 云 SDK 3.13.0
编辑: SFSF 元数据文件在 https://api.sap.com/ 中可用 我在这个应用程序中使用的是 SFSF - Job Requisition,可在此处获取: https://api.sap.com/api/RCMJobRequisition/overview
从那里,您可以下载 EDMX 规范。这些是 "mock" API 的,没有连接到真正的 SFSF 实例,但问题是一样的。
为此,我主要关注两个博客:
- https://blogs.sap.com/2018/04/30/deep-dive-10-with-sap-s4hana-cloud-sdk-generating-java-vdm-for-s4hana-custom-odata-service/
- https://blogs.sap.com/2019/05/06/create-an-application-with-sap-cloud-sdk-to-integrate-with-sap-successfactors/
此外,我删除了最后一部分,因为我将打开一个单独的问题:
谢谢,
配对
我将从部分答案开始,如果需要,稍后会编辑更多信息。
关于 URL:
您观察到的行为是故意的。请求的完整 URL 将组合如下:目标 URL + 服务路径 + 服务名称 + 实体 + '?' + 查询参数。所以在你的情况下可能是:
https://my.host.domain/odata/v2/JobRequisitions/MyEntity
Destination: https://my.host.domain
Service Path: /odata/v2
Service name: JobRequisitions
Entity: MyEntity
生成器从 service path + service name
组装默认基本路径。 service name
实际上是从 EDMX 的命名空间中提取的。这就是为什么您的服务 URL 会按原样生成的原因。
原因很简单:人们可能希望同时为多个服务生成一个 VDM。除服务名称本身外,所有这些服务都在同一个端点下公开。为了使用一种配置生成所有 VDM,我们可以在生成器中指定 "service path",然后生成器从 EDXM 本身中提取服务名称。
这意味着您覆盖生成的基本路径的方法应该有效:
final List<JobRequisition> jobReqs = new DefaultRCMJobRequisitionService()
.withServicePath("odata/v2/JobRequisition")
.getAllJobRequisition()
.execute(destination);
你问题最后的错误信息对我来说有点像解析问题。但是为了进一步解决这个问题,我们需要完整的堆栈跟踪和 HTTP 日志输出。此外,如果我们可以访问元数据,我们只能重现问题。您提供的 link 需要通过 username/password 授权。
由于你上面的问题已经很全面了,如果这真的是一个独立的问题,我建议你将这两个问题分开并创建一个新问题。这也将使这两个问题与其他问题更相关。