<EntityType Name="Supplier">
<Key>
<PropertyRef Name="SupplierIdentifier" />
</Key>
<Property Name="SupplierIdentifier" Type="Edm.String" />
<Property Name="SupplierCompanyName" Type="Edm.String" />
<Property Name="SupplierCity" Type="Edm.String" />
<Property Name="SupplierCountry" Type="Edm.String" />
<Property Name="ContactFirstName" Type="Edm.String" />
<Property Name="ContactLastName" Type="Edm.String" />
<Property Name="ContactGuid" Type="Edm.Guid" />
<Property Name="ContactBirth" Type="Edm.Date" />
<Property Name="ProductsToSupply" Type="Edm.String" />
<Property Name="ProductsTotalAmout" Type="Edm.Int16" />
<Property Name="ProductsContainAds" Type="Edm.Boolean" />
<Property Name="ProductsTotalValue" Type="Edm.Decimal" Scale="2" Precision="8" />
</EntityType>
Our v4 entity | Our v4 property name | Backend v2 entity | Backend v2 property name |
Supplier | BusinessPartner | ||
SupplierIdentifier | BusinessPartnerID | ||
- | BusinessPartnerRole (used for $select and $filter) | ||
SupplierCompanyName | CompanyName | ||
SupplierCity | Address/City | ||
SupplierCountry | Address/Country | ||
- | Address/AddressType | ||
- | CreatedAt (used for $select and $filter) | ||
Contact | |||
ContactFirstName | FirstName | ||
ContactLastName | LastName | ||
ContactGuid (data type: Edm.String) | ContactGuid (data type: Edm.Guid) | ||
ContactBirth (data type: Edm.Date) | DateOfBirth (data type: Edm.DateTime) | ||
Product | |||
ProductsToSupply (calculated) | - (ProductID is used for calculation) | ||
ProductsTotalAmout (calculated) | - | ||
ProductsContainAds (calculated) | - (TypeCode is used for calculation) | ||
ProductsTotalValue | - (Price is used for calculation) |
ODataQueryResult result = ODataQueryBuilder
.withEntity("/sap/opu/odata/IWBEP/GWSAMPLE_BASIC", "BusinessPartnerSet")
.expand("ToContacts", "ToProducts")
https://sapes5.sapdevcenter.com/sap/opu/odata/IWBEP/GWSAMPLE_BASIC/BusinessPartnerSet?$expand=ToProd...
.select("BusinessPartnerID", "CompanyName", "Address",
"ToProducts/ProductID", "ToProducts/Price","ToProducts/TypeCode",
"ToContacts/FirstName", "ToContacts/LastName", "ToContacts/ContactGuid", "ToContacts/DateOfBirth")
.filter(ODataProperty.field("BusinessPartnerRole").eq(ODataType.of("02")))
<Property Name="ContactBirth" Type="Edm.Date" />
<Property Name="DateOfBirth" Type="Edm.DateTime"
supplierEntity.put("ContactBirth", contactsMap.get("DateOfBirth"));
<d:DateOfBirth>1970-01-03T00:00:00</d:DateOfBirth>
@Query(serviceName = "DemoService", entity = "Suppliers")
public QueryResponse getSuppliers(QueryRequest queryRequest) {
String[] select = { "BusinessPartnerID", "CompanyName", "Address",
"ToProducts/ProductID", "ToProducts/Price", "ToProducts/TypeCode",
"ToContacts/FirstName", "ToContacts/LastName", "ToContacts/ContactGuid", "ToContacts/DateOfBirth" };
try {
List<Map<String, Object>> v2BusinessPartnerList = ODataQueryBuilder
.withEntity("/sap/opu/odata/IWBEP/GWSAMPLE_BASIC", "BusinessPartnerSet")
.select(select)
.expand("ToContacts", "ToProducts")
.filter(ODataProperty.field("BusinessPartnerRole").eq(ODataType.of("02")))
.build()
.execute("ES5")
.asListOfMaps();
// convert the v2 map to v4 map, including all the modifications
List<Map<String, Object>> v4SupplierList = convertV2BusinessPartnersToV4Suppliers(v2BusinessPartnerList);
return QueryResponse.setSuccess()
.setDataAsMap(v4SupplierList)
.response();
} catch (ODataException e) {
return QueryResponse.setError(ErrorResponse.getBuilder()
.setMessage("Error occurred while calling OData V2 data source.")
.setStatusCode(HttpStatus.SC_INTERNAL_SERVER_ERROR)
.setCause(e)
.response());
}
}
---
applications:
- name: DemoProject
memory: 512M
buildpack: sap_java_buildpack
path: target/DemoProject-0.0.1-SNAPSHOT.war
services:
- demoxsuaa
- demodestination
env:
ALLOW_MOCKED_AUTH_HEADER: 'true'
<?xml version="1.0" encoding="utf-8"?>
<edmx:Edmx Version="4.0" xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx">
<edmx:DataServices>
<Schema Namespace="demo" xmlns="http://docs.oasis-open.org/odata/ns/edm">
<EntityType Name="Supplier">
<Key>
<PropertyRef Name="SupplierIdentifier"/>
</Key>
<Property Name="SupplierIdentifier" Type="Edm.String"/>
<Property Name="SupplierCompanyName" Type="Edm.String" />
<Property Name="SupplierCity" Type="Edm.String"/>
<Property Name="SupplierCountry" Type="Edm.String"/>
<Property Name="ContactFirstName" Type="Edm.String"/>
<Property Name="ContactLastName" Type="Edm.String"/>
<Property Name="ContactGuid" Type="Edm.Guid"/>
<Property Name="ContactBirth" Type="Edm.Date" />
<Property Name="ProductsToSupply" Type="Edm.String"/>
<Property Name="ProductsTotalAmout" Type="Edm.Int16"/>
<Property Name="ProductsContainAds" Type="Edm.Boolean"/>
<Property Name="ProductsTotalValue" Type="Edm.Decimal" Scale="2" Precision="8"/>
</EntityType>
<EntityContainer Name="EntityContainer">
<EntitySet Name="Suppliers" EntityType="demo.Supplier"/>
</EntityContainer>
</Schema>
</edmx:DataServices>
</edmx:Edmx>
package com.example.odata.DemoProject;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.apache.http.HttpStatus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.sap.cloud.sdk.odatav2.connectivity.ODataException;
import com.sap.cloud.sdk.odatav2.connectivity.ODataProperty;
import com.sap.cloud.sdk.odatav2.connectivity.ODataQueryBuilder;
import com.sap.cloud.sdk.odatav2.connectivity.ODataType;
import com.sap.cloud.sdk.service.prov.api.operations.Query;
import com.sap.cloud.sdk.service.prov.api.request.QueryRequest;
import com.sap.cloud.sdk.service.prov.api.response.ErrorResponse;
import com.sap.cloud.sdk.service.prov.api.response.QueryResponse;
public class ServiceImplementation {
Logger logger = LoggerFactory.getLogger(ServiceImplementation.class);
@Query(serviceName = "DemoService", entity = "Suppliers")
public QueryResponse getSuppliers(QueryRequest queryRequest) {
// compose $select statement
String[] select = { "BusinessPartnerID", "CompanyName", "Address",
"ToProducts/ProductID", "ToProducts/Price", "ToProducts/TypeCode",
"ToContacts/FirstName", "ToContacts/LastName", "ToContacts/ContactGuid", "ToContacts/DateOfBirth" };
try {
// call the backend v2 service
List<Map<String, Object>> v2BusinessPartnerList = ODataQueryBuilder
.withEntity("/sap/opu/odata/IWBEP/GWSAMPLE_BASIC", "BusinessPartnerSet")
.select(select)
.expand("ToContacts", "ToProducts")
.filter(ODataProperty.field("BusinessPartnerRole").eq(ODataType.of("02")))
.build()
.execute("ES5")
.asListOfMaps();
// convert the result (v2) map to v4 map, including all the modifications
List<Map<String, Object>> v4SupplierList = convertV2BusinessPartnersToV4Suppliers(v2BusinessPartnerList);
return QueryResponse.setSuccess()
.setDataAsMap(v4SupplierList)
.response();
} catch (ODataException e) {
return QueryResponse.setError(ErrorResponse
.getBuilder().setMessage("Error occurred while calling OData V2 data source. "
+ e.getODataExceptionType() + " - " + e.getMessage())
.setStatusCode(HttpStatus.SC_INTERNAL_SERVER_ERROR)
.setCause(e)
.response());
}
}
// HELPER
private List<Map<String, Object>> convertV2BusinessPartnersToV4Suppliers(List<Map<String, Object>> v2BusinessPartnerListExpanded){
List<Map<String, Object>> v4supplierList = new ArrayList<Map<String, Object>>();
if (v2BusinessPartnerListExpanded != null && v2BusinessPartnerListExpanded.size() > 0) {
for (Map<String, Object> businessPartnerExpanded : v2BusinessPartnerListExpanded) {
Map<String, Object> supplierEntity = convertV2BusinessPartnerToV4Supplier(businessPartnerExpanded);
v4supplierList.add(supplierEntity);
}
}
return v4supplierList;
}
@SuppressWarnings("unchecked")
private Map<String, Object> convertV2BusinessPartnerToV4Supplier(Map<String, Object> v2BusinessPartnerExpanded) {
Map<String, Object> supplierEntity = new HashMap<String, Object>();
supplierEntity.put("SupplierIdentifier", v2BusinessPartnerExpanded.get("BusinessPartnerID"));
supplierEntity.put("SupplierCompanyName", v2BusinessPartnerExpanded.get("CompanyName"));
// Address property is a ComplexType, non-nullable
Map<String, Object> v2BusinessPartnerAddress = (Map<String, Object>)v2BusinessPartnerExpanded.get("Address");
supplierEntity.put("SupplierCity", v2BusinessPartnerAddress.get("City"));
supplierEntity.put("SupplierCountry", v2BusinessPartnerAddress.get("Country"));
// ToContacts is an expanded navigation property, here we flatten it into the supplier
List<Map<String, Object>> contactsMapList = (List<Map<String, Object>>)v2BusinessPartnerExpanded.get("ToContacts");
if(contactsMapList!= null && ! contactsMapList.isEmpty()) {
//in v2 backend, one BusinessPartner can have many contacts. Here, for simplification, we take only the first
Map<String, Object> contactsMap = contactsMapList.get(0);
supplierEntity.put("ContactGuid", contactsMap.get("ContactGuid"));
supplierEntity.put("ContactFirstName", contactsMap.get("FirstName"));
supplierEntity.put("ContactLastName", contactsMap.get("LastName"));
supplierEntity.put("ContactBirth", contactsMap.get("DateOfBirth"));
}
// ToProducts is an expanded navigation property, here we use it to calculate new fields
List<Map<String, Object>> productsList = (List<Map<String, Object>>)v2BusinessPartnerExpanded.get("ToProducts");
if(productsList!= null && ! productsList.isEmpty()) {
supplierEntity.put("ProductsToSupply", calculateProductsAsString(productsList));
supplierEntity.put("ProductsTotalAmout", calculateProductsCount(productsList));
supplierEntity.put("ProductsContainAds", calculateProductsContainAds(productsList));
supplierEntity.put("ProductsTotalValue", calculateProductsValue(productsList));
}
return supplierEntity;
}
/** @return the number of product entries */
private int calculateProductsCount(List<Map<String, Object>> productsList) {
return productsList.size();
}
/** @return true if among the given product list there's an entry of type Advertisement */
private boolean calculateProductsContainAds(List<Map<String, Object>> productsList) {
return productsList.stream()
.<String>map(map->(String)map.get("TypeCode"))
.collect(Collectors.toList())
.contains("AD");
}
/** @return all product IDs concatenated as one string */
private String calculateProductsAsString(List<Map<String, Object>> productsList) {
return productsList.stream()
.<String>map(map->(String)map.get("ProductID"))
.collect(Collectors.joining(", ")); // need <String> to compile fine
}
/** @return the sum of all products in the given list */
private BigDecimal calculateProductsValue(List<Map<String, Object>> productsList) {
return productsList.stream()
.<BigDecimal>map(m->(BigDecimal)m.get("Price"))
.reduce(BigDecimal.ZERO, (lhs, rhs) -> lhs.add(rhs), BigDecimal::add);
}
}
{
"DateOfBirth": "\/Date(990316800000)\/"
}
{
"DateOfBirth": "1988-12-22T21:33:11"
}
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
User | Count |
---|---|
12 | |
10 | |
10 | |
7 | |
7 | |
7 | |
6 | |
6 | |
5 | |
4 |