
Further disclaimer: This blog post is only applicable for the SAP Cloud SDK version of at most 2.19.2. It has not been updated to version 3.0.0. Feel free to check out
our other Tutorials on the SAP Cloud SDK.
final ErpEndpoint endpoint = new ErpEndpoint();
final List<CostCenterDetails> costCenters = ODataQueryBuilder
.withEntity("/sap/opu/odata/sap/FCO_PI_COST_CENTER", "CostCenterCollection")
.select("CostCenterID", "Status", "CompanyCode", "Category", "CostCenterDescription")
.build()
.execute(endpoint)
.asList(CostCenterDetails.class);
.withEntity("/sap/opu/odata/sap/FCO_PI_COST_CENTER", "CostCenterCollection")
you already need to know three things: the OData endpoints service path (/sap/opu/odata/sap), the endpoints name (FCO_PI_COST_CENTER) and the name of the entity collection (CostCenterCollection) as defined in the endpoints metadata.select()
function, you need to know how these fields are called. But since they are only represented as strings in this code, you need to look at the metadata to find out how they're called. The same also applies for functions like order()
and filter()
. And of course using strings as parameters is prone to spelling errors that your IDE most likely won't be able to catch for you.import static com.sap.cloud.sdk.s4hana.datamodel.odata.namespaces.ReadCostCenterDataNamespace.CostCenter;
final List<CostCenter> costCenters =
new DefaultReadCostCenterDataService().getAllCostCenter()
.select(
CostCenter.COMPANY_CODE,
CostCenter.COST_CENTER_ID,
CostCenter.STATUS,
CostCenter.CATEGORY,
CostCenter.COST_CENTER_DESCRIPTION)
.execute(erpConfigContext);
DefaultReadCostCenterDataService
(default implementation of the interface ReadCostCenterDataService
). So now there's no more need to know the endpoint's service path, service name or entity collection name. We can call this service's getAllCostCenter()
function to retrieve a list of all the cost centers from the system.select()
function. Instead of passing strings that represent the field of the entity, we can simply use the static fields provided by the CostCenter class. So not only have we eliminated the risk of spelling errors, we also made it type-safe! Again, the same applies for filter()
and orderBy()
. For example, filtering to a specific company code becomes as easy as .filter(CostCenter.COMPANY_CODE.eq(companyCode))
.com.sap.cloud.sdk.s4hana.datamodel.odata.services
, instantiate the default implementation of the service you need (class name prefixed with Default
), and then look for the methods of the service class that represent the different available operations. Based on this, you can choose the fields to select and filters to apply using the fields of the return type.ReadCostCenterDataService
. The SDK provides a default, complete implementation of each service interface. The corresponding implementation is available in a class whose name is the name of the interface prefixed with Default
, for example, DefaultReadCostCenterDataService
. You can either simply instantiate that class, or use dependency injection with a corresponding Java framework (we may cover dependency injection in a future blog post). The benefit of the interfaces is better testing and extensibility support.filter()
, select()
, orderBy()
, top()
and skip()
. You can also resolve navigation properties on demand and use function imports. Future releases will bring even more enhancements to its functionality.package com.sap.cloud.sdk.tutorial;
import org.slf4j.Logger;
import java.util.List;
import java.util.Collections;
import com.netflix.hystrix.HystrixThreadPoolProperties;
import com.sap.cloud.sdk.cloudplatform.logging.CloudLoggerFactory;
import com.sap.cloud.sdk.frameworks.hystrix.HystrixUtil;
import com.sap.cloud.sdk.odatav2.connectivity.ODataQueryBuilder;
import com.sap.cloud.sdk.s4hana.connectivity.ErpCommand;
import com.sap.cloud.sdk.s4hana.connectivity.ErpConfigContext;
public class GetCostCentersCommand extends ErpCommand<List<CostCenterDetails>>
{
private static final Logger logger = CloudLoggerFactory.getLogger(GetCostCentersCommand.class);
protected GetCostCentersCommand( final ErpConfigContext configContext )
{
super(
HystrixUtil
.getDefaultErpCommandSetter(
GetCostCentersCommand.class,
HystrixUtil.getDefaultErpCommandProperties().withExecutionTimeoutInMilliseconds(5000))
.andThreadPoolPropertiesDefaults(HystrixThreadPoolProperties.Setter().withCoreSize(20)),
configContext);
}
@Override
protected List<CostCenterDetails> run()
throws Exception
{
final List<CostCenterDetails> costCenters =
ODataQueryBuilder
.withEntity("/sap/opu/odata/sap/FCO_PI_COST_CENTER", "CostCenterCollection")
.select("CostCenterID", "Status", "CompanyCode", "Category", "CostCenterDescription")
.build()
.execute(getConfigContext())
.asList(CostCenterDetails.class);
return costCenters;
}
@Override
protected List<CostCenterDetails> getFallback() {
return Collections.emptyList();
}
}
package com.sap.cloud.sdk.tutorial;
import org.slf4j.Logger;
import java.util.Collections;
import java.util.List;
import com.netflix.hystrix.HystrixThreadPoolProperties;
import com.sap.cloud.sdk.cloudplatform.logging.CloudLoggerFactory;
import com.sap.cloud.sdk.frameworks.hystrix.HystrixUtil;
import com.sap.cloud.sdk.s4hana.connectivity.ErpCommand;
import com.sap.cloud.sdk.s4hana.connectivity.ErpConfigContext;
import com.sap.cloud.sdk.s4hana.datamodel.odata.namespaces.readcostcenterdata.CostCenter;
import com.sap.cloud.sdk.s4hana.datamodel.odata.services.DefaultReadCostCenterDataService;
import com.sap.cloud.sdk.s4hana.datamodel.odata.services.ReadCostCenterDataService;
public class GetCostCentersCommand extends ErpCommand<List<CostCenter>>
{
private static final Logger logger = CloudLoggerFactory.getLogger(GetCostCentersCommand.class);
protected GetCostCentersCommand( final ErpConfigContext configContext )
{
super(
HystrixUtil
.getDefaultErpCommandSetter(
GetCostCentersCommand.class,
HystrixUtil.getDefaultErpCommandProperties().withExecutionTimeoutInMilliseconds(5000))
.andThreadPoolPropertiesDefaults(HystrixThreadPoolProperties.Setter().withCoreSize(20)),
configContext);
}
@Override
protected List<CostCenter> run()
throws Exception
{
final List<CostCenter> costCenters = new DefaultReadCostCenterDataService().getAllCostCenter()
.select(CostCenter.COST_CENTER_ID,
CostCenter.STATUS,
CostCenter.COMPANY_CODE,
CostCenter.CATEGORY,
CostCenter.COST_CENTER_DESCRIPTION)
.execute(getConfigContext());
return costCenters;
}
@Override
protected List<CostCenter> getFallback() {
return Collections.emptyList();
}
}
package com.sap.cloud.sdk.tutorial;
import com.google.gson.Gson;
import org.slf4j.Logger;
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.logging.CloudLoggerFactory;
import com.sap.cloud.sdk.s4hana.connectivity.ErpConfigContext;
import com.sap.cloud.sdk.s4hana.datamodel.odata.namespaces.readcostcenterdata.CostCenter;
@WebServlet("/costcenters")
public class CostCenterServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
private static final Logger logger = CloudLoggerFactory.getLogger(CostCenterServlet.class);
@Override
protected void doGet( final HttpServletRequest request, final HttpServletResponse response )
throws ServletException,
IOException
{
final ErpConfigContext configContext = new ErpConfigContext();
final List<CostCenter> result = new GetCachedCostCentersCommand(configContext).execute();
response.setContentType("application/json");
response.getWriter().write(new Gson().toJson(result));
}
}
getCostCenters
to List<CostCenter>
and import com.sap.cloud.sdk.s4hana.datamodel.odata.namespaces.readcostcenterdata.CostCenter
. integration-tests/src/test/resources/costcenters-schema.json
, change the property required to "required": ["costCenterID", "companyCode"]
.mvn clean install
cf push
cf set-env firstapp destinations '[{name: "ErpQueryEndpoint", url: "https://URL", username: "USER", password: "PASSWORD"}]'
cf set-env firstapp ALLOW_MOCKED_AUTH_HEADER true
/costcenters
API now uses a type-safe approach to access SAP S/4HANA. Adding additional functionality to this integration is much easier thanks to the easily discoverable Virtual Data Model - try it yourself and for example add a filter to the cost center query or implement a second API for business partners.You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
User | Count |
---|---|
16 | |
14 | |
13 | |
9 | |
9 | |
9 | |
8 | |
7 | |
7 | |
7 |