Technology Blogs by SAP
Learn how to extend and personalize SAP applications. Follow the SAP technology blog for insights into SAP BTP, ABAP, SAP Analytics Cloud, SAP HANA, and more.
cancel
Showing results for 
Search instead for 
Did you mean: 
JerryWang
Employee
Employee

In Horst's blog ABAP News for Release 7.50 – CORRESPONDING, again the usage of CL_ABAP_CORRESPONDING is introduced.
There is already a demo program in SAP help.


I write another simple one and I will keep using that scenario in Java and JavaScript as well.

CL_ABAP_CORRESPONDING


Suppose there are two developers Jerry and Tom who mainly focus on ABAP and Java. Their salary are stored in the internal table developer_list. Later they would like to work as presale for new challenge and the corresponding information should be moved to another internal table presale_list. The content of these two internal table should be equal, unfortunately the field name are slightly different. In this case it is show time for CL_ABAP_CORRESPONDING:


Report z.
TYPES: BEGIN OF developer,
focus_language TYPE string,
salary TYPE i,
name TYPE string,
END OF developer,

BEGIN OF presale,
focus_area TYPE string,
salary_plus_bonus TYPE i,
name TYPE string,
END OF presale.

DATA: developer_list TYPE TABLE OF developer WITH EMPTY KEY,
presale_list TYPE TABLE OF presale WITH EMPTY KEY.

developer_list = VALUE #(
( name = 'Jerry' focus_language = 'ABAP' salary = 2000 )
( name = 'Tom' focus_language = 'Java' salary = 2050 ) ).

presale_list = VALUE #( ( name = 'Jerry' ) ( name = 'Tom' ) ).

DATA(lo_mapping_executor) = cl_abap_corresponding=>create(
source = developer_list
destination = presale_list
mapping = VALUE cl_abap_corresponding=>mapping_table(
( level = 0 kind = 1 srcname = 'focus_language' dstname = 'focus_area' )
( level = 0 kind = 1 srcname = 'salary' dstname = 'salary_plus_bonus' ) ) ).

lo_mapping_executor->execute( EXPORTING source = developer_list
CHANGING destination = presale_list ).

The data transfer from developer internal table to presales internal table consists of two steps:

1. configure mapping information using CL_ABAP_CORRESPONDING=>CREATE, a mapping executor instance is returned.

2. call mapping executor's method execute to get mapped internal table.

The mapped result in this example looks as below:



CL_JAVA_CORRESPONDING


Still use the same scenario, here is my definition of Developer and Presale:


public class Developer {
private String focusLanguage;
private int salary;
private String name;
public Developer(String name, String language, int salary){
this.name = name;
this.focusLanguage = language;
this.salary = salary;
}
}
public class PreSales {
private String name;
private String focusArea;
private int salaryPlusBonus;

public PreSales(String name){
this.name = name;
}
public String toString(){
return "Presales: " + this.name + " focusArea: " + this.focusArea + " salaryPlusBonus: " +
this.salaryPlusBonus;
}
}

And let's do some enhancement on top of the scenario. Suppose after Jerry and Tom work as a Presale, they get their salary doubled ( this is just an example, not the real case in SAP of course ! ) It is expected such salary double could also be automatically performed during mapping execution.

This is my test code in Java:


List<Developer> developers = new ArrayList<Developer>();
developers.add(new Developer("Jerry", "ABAP", 2000));
developers.add(new Developer("Tom", "Java", 2050));

List<PreSales> preSales = new ArrayList<PreSales>();
preSales.add(new PreSales("Jerry"));
preSales.add(new PreSales("Tom"));
Above code just constructs a list for developer and a list for presales.

CL_MAPPING[] mapping = new CL_MAPPING[2];
mapping[0] = new CL_MAPPING("focusLanguage", "focusArea", null);

And above line defines the first mapping rule, to map field focusLanguage of developer to field focusArea of Presale.


Function<Integer, Integer> salaryDouble = e -> e * 2;
mapping[1] = new CL_MAPPING("salary", "salaryPlusBonus", salaryDouble);

Above line also defines a mapping rule using a Function instance salaryDouble. The implementation of this function is easy to understand: double the salary!

For comparison purpose I still stick to ABAP naming convention in this Java code, you see the consumption pattern for CL_JAVA_CORRESPONDING is exactly as what we have done in previous ABAP example: first configure mapping rule and get a mapping executor, and then call its execute method to perform the mapping.


CL_JAVA_CORRESPONDING mappingExecutor = CL_JAVA_CORRESPONDING.CREATE(developers, preSales, mapping);
List<PreSales> mappedPresales = (List<PreSales>) mappingExecutor.execute();
mappedPresales.forEach(System.out::println);

Mapping result, the salary for both guy are doubled 🙂



Below is the core method for mapping logic done in Java.

The idea is simple, get the value of source field via Java reflection, and set to the corresponding field of target object as well.

The complete implementation and test code of CL_JAVA_CORRESPONDING could be found from my github.



CL_JS_CORRESPONDING


Due to the dynamic programming trait of JavaScript, it is pretty easier to implement the same logic in JavaScript.

Again the definition of Developer and Presale:


function Developer(name, language, salary){
this.name = name;
this.focusLanguage = language;
this.salary = salary;
}

function Presales(name){
this.name = name;
}

And implementation of CL_JS_CORRESPONDING ( I use ABAP naming convention once again here )


var CL_JS_CORRESPONDING = function() {  
function MappingExecutor(src, target, mapping){
this.src = src;
this.target = target;
this.mapping = mapping;
function _map(source, target, mapping){
for( var i = 0; i < source.length; i++){
_mapEach(source[i], target[i], mapping);
}
}
function _mapEach(source, target, mapping){
target[mapping.target] = source[mapping.source];
if( mapping.function){
target[mapping.target] = mapping.function.call(null, target[mapping.target]);
}
}
MappingExecutor.prototype.execute = function(){
for( var i = 0; i < this.mapping.length; i++){
_map(this.src, this.target, this.mapping[i]);
}
return this.target;
}
};
return {
CREATE:function(src,target,mapping){
if( !Array.isArray(src) || !Array.isArray(target)){
return target;
}
if( src.length != target.length){
return target;
}
if( src.length == 0){
return target;
}
return new MappingExecutor(src, target, mapping);
}
}}();

Consumer code below. Here I use the arrow function to define the salary double rule:


var developerList = [ new Developer("Jerry", "ABAP", 2000),
new Developer("Tom", "Java", 2050)];
var preSalesList = [ new Presales("Jerry"),
new Presales("Tom")];
var mapping = [
{
source:"focusLanguage",
target:"focusArea"
},
{
source:"salary",
target:"salaryPlusBonous",
function: x => { return x * 2 }
}
];
var mappingExecutor = CL_JS_CORRESPONDING.CREATE(developerList, preSalesList, mapping);
var mappedPreSales = mappingExecutor.execute();

Execution result: salary doubled, again!



All source code of JavaScript version could be found from my github here.


Rewrite Javascript implementation using functional programming style


According to David 's comment since in JavaScript the functional programming is possible, why not try it?

Then I rewrite the Javascript implementation using map provided for Array. Here below is the source code:
var CL_JS_CORRESPONDING = function() { 

function MappingExecutor(src, target, mapping){
this.src = src;
this.target = target;
this.mapping = mapping;

MappingExecutor.prototype.execute = function(){
var mapCurrentTarget = function(currentTarget, currentSource, mapping){
mapping.map(function(currentMapping){
this.currentTarget[currentMapping.target] = this.currentSource[currentMapping.source];
if( currentMapping.function) {
this.currentTarget[currentMapping.target] = currentMapping.function.call(null, this.currentTarget[currentMapping.target]);
}
}, {
currentTarget: currentTarget,
currentSource: currentSource
});
return currentTarget;
}
var mappingFunctor = function (currentTarget, index){
return mapCurrentTarget(currentTarget, this.src[index], this.mapping);
};
return this.target.map(mappingFunctor, this);
}
};
return {
CREATE:function(src,target,mapping){
if( !Array.isArray(src) || !Array.isArray(target)){
return target;
}
if( src.length != target.length){
return target;
}
if( src.length == 0){
return target;
}
return new MappingExecutor(src, target, mapping);
}
}}();

This version has 40 lines of source code, you can compare it with the old style implementation using for loop, which has 37 lines of code.

Meanwhile in ABAP we can also simulate "Functional Programming" a little bit. See this blog Functional Programming – Try Reduce in JavaScript and in ABAP for detail.




Further reading


I have written a series of blogs which compare the language feature among ABAP, JavaScript and Java. You can find a list of them below:

















5 Comments