【问题标题】:Generate VDM for SFSF using Java in SAP Cloud SDK: Generated URI is wrong在 SAP Cloud SDK 中使用 Java 为 SFSF 生成 VDM:生成的 URI 错误
【发布时间】:2020-02-24 09:30:50
【问题描述】:

我正在尝试构建一个从 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 中
  • 创建一个目标服务 (my-destination) 并在其中添加一个指向我的 SFSF 实例的目标,并使用基本身份验证(使用 user@companyId,连接为 200:OK)
  • 在 manifest.yml 中添加目标服务
  • 创建一个java类调用目的地并获取数据:
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>
  1. 我可以看到生成器正确选择了该路径:
[main] INFO com.sap.cloud.sdk.datamodel.odata.generator.DataModelGenerator -   Default base path:              /odata/v2/
  1. 但这是生成器处理的内容:
[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>
...

我找不到这个工作的方法。你能帮我在这里找到问题吗?

我正在使用:

  • Apache Maven 3.6.2
  • SAP 云 SDK 3.13.0

编辑: SFSF 元数据文件位于https://api.sap.com/ 我为这个应用程序使用的是 SFSF - Job Requisition,可在此处获得: https://api.sap.com/api/RCMJobRequisition/overview

您可以从那里下载 EDMX 规范。这些是“模拟”API,没有连接到真正的 SFSF 实例,但问题是一样的。

为此,我主要关注两个博客:

另外,我删除了最后一部分,因为我将打开一个单独的问题: SFSF OData call: Failed to convert response into ODataFeed: An 'EdmSimpleTypeException' occurred

谢谢,

保持对

【问题讨论】:

    标签: java sap-cloud-platform sap-cloud-sdk sap-successfactors sap-cloud-foundry


    【解决方案1】:

    我将从部分答案开始,如果需要,稍后会编辑更多信息。

    关于网址:

    您观察到的行为是故意的。请求的完整 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,我们可以在生成器中指定“服务路径”,然后生成器从 EDXM 本身中提取服务名称。

    这意味着您覆盖生成的基本路径的方法应该有效:

    final List<JobRequisition> jobReqs = new DefaultRCMJobRequisitionService()
                    .withServicePath("odata/v2/JobRequisition")
                    .getAllJobRequisition()
                    .execute(destination);
    

    问题最后的错误消息在我看来有点像解析问题。但为了进一步解决这一问题,我们需要完整的堆栈跟踪和 HTTP 日志输出。此外,如果我们可以访问元数据,我们只能重现问题。您提供的链接需要通过用户名/密码进行授权。

    由于您上面的问题已经非常全面,我建议您将这两个问题分开并创建一个新问题,如果这真的是一个独立的问题。这也将使这两个问题与其他问题更相关。

    【讨论】:

    • 我在问题的末尾添加了一些参考资料。您应该能够获得一个元数据文件,就像我在 api.sap.com 中使用的那样。我有兴趣访问 Job Requisition 下的几个实体:JobRequisition、JobRequisitionLocale 和 JobReqScreeningQuestion。
    • 我查看了元数据,我在回答中描述的内容仍然有效。使用我概述的 VDM 的方式应该可以准确地满足您的要求,至少在组装的 URI 方面。那么这里仍然存在的问题是什么?
    • 问题是它构建的URI不存在,调用目的地时需要更改服务路径。我知道这可能是 OData 提供者(在这种情况下为 SFSF)的问题?
    • 是的,但这不是 OData 提供者的“问题”。只是 EDMX 不遵循 namespace == service name 模式,这很好。服务不强制执行此操作。这只是意味着生成器使用的这种“启发式”不适用于此处,您必须以编程方式设置基本路径。
    猜你喜欢
    • 1970-01-01
    • 2020-03-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多