Technical Articles
JAXB in SAP PI Java Mapping
There were few blogs on this topic written before year 2013. Whereas after the IDE eclipse has been updated with many new versions and SAP PI platform has updated, the user interfaces have changed accordingly. Newcomers may find it a bit hard to follow the process by using the old blogs.
Let’s refresh the memory. Good technology is worth to be updated. Here are the steps in the new updated platforms.
1 Setup Eclipse for JAXB
To do so select Help -> Install New Software… from the eclipse main menu bar
For my version, access is
Neon – http://download.eclipse.org/releases/neon
After install the add-ons, restart the NWDS
These extra options can be viewed in the start wizard
2 Start PI JAVA mapping
2.1 Get source and target XSD
of course, you can create/use whatever message types you want according to the requirement. here in my example, the message structures are:
source:
Target:
2.2 Create JAXB class in NWDS
2.3 Create packages
Create one source package, one target package and one main package
Import the xsd file into the package respectively
2.4 Generate message class
Right click on the XSD file and choose newàotheràJAXBàJAXB classes from schema
Click Next button
Information in the Console tab showing some java classes have been generated.
Follow the same steps to generate classes for target schema. When both schemas have been processed the project explorer is like this
2.5 Develop Java Mapping
Add SAP java library to the project and create the mapping class
Here is the source code of the class together with the unit test. please be notified that part of the namespace has been replaced by <dummy>. please replaced it by using any hostname making sense.
package au.com.<dummy>.jaxb.test02;
import com.sap.aii.mapping.api.AbstractTransformation;
import com.sap.aii.mapping.api.StreamTransformationException;
import com.sap.aii.mapping.api.TransformationInput;
import com.sap.aii.mapping.api.TransformationOutput;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.transform.stream.StreamSource;
import au.com.<dummy>.jaxb.test02.CRM_CustomerInformation_to_ERP_UserCollection;
import au.com.<dummy>.jaxb.test02.source.CustomerInformation;
import au.com.<dummy>.jaxb.test02.target.ExtraInfo;
import au.com.<dummy>.jaxb.test02.target.UserCollectionMessage;
import au.com.<dummy>.jaxb.test02.target.UserRecord;
import au.com.<dummy>.jaxb.test02.source.CustomerInformation.Customer;
import au.com.<dummy>.jaxb.test02.target.ObjectFactory;
public class CRM_CustomerInformation_to_ERP_UserCollection extends AbstractTransformation {
@Override
public void transform(TransformationInput in, TransformationOutput out) throws StreamTransformationException {
// TODO Auto-generated method stub
getTrace().addInfo("JAVA Mapping JAXB_Mapping is Initiated");
this.execute(in.getInputPayload().getInputStream(), out.getOutputPayload().getOutputStream());
}
public void execute(InputStream in, OutputStream out) throws StreamTransformationException {
try {
InputStream is = in;
JAXBContext jaxbContext = JAXBContext.newInstance(CustomerInformation.class);
Unmarshaller unMarshaller = jaxbContext.createUnmarshaller();
JAXBElement<CustomerInformation> customerInforamtion = (JAXBElement<CustomerInformation>) unMarshaller.unmarshal(new StreamSource(is), CustomerInformation.class);
getTrace().addInfo("Unmarshall Successful");
/*————- Marshal the Target—————-*/
ObjectFactory objectFactory = new ObjectFactory();
UserCollectionMessage userCollectionMessage = objectFactory.createUserCollectionMessage();
JAXBElement<UserCollectionMessage> target = objectFactory.createUserCollection(userCollectionMessage);
for (int i = 0; i < customerInforamtion.getValue().getCustomer().size(); i++){
UserRecord user = objectFactory.createUserRecord();
Customer customer = customerInforamtion.getValue().getCustomer().get(i);
user.setFirstname(customer.getGivenname());
user.setLastname(customer.getSurname());
user.setFullname(customer.getGivenname()+" "+customer.getSurname());
user.setUsername(customer.getGivenname()+"_"+customer.getSurname());
ExtraInfo extraInfo = objectFactory.createExtraInfo();
extraInfo.setAddressLine1(customer.getAddress().getLine1());
extraInfo.setAddressLine2(customer.getAddress().getLine2());
extraInfo.setAddressLine3(customer.getAddress().getLine3());
extraInfo.setCity(customer.getAddress().getState());
extraInfo.setPostCode(customer.getAddress().getPostcode());
extraInfo.setDateOfBirth(customer.getDOB());
extraInfo.setEmailAddress(customer.getContact().getEmail());
extraInfo.setMobile(customer.getContact().getMobile());
user.setExtraInfo(extraInfo);
userCollectionMessage.getUser().add(user);
}
JAXBContext contextTarget = JAXBContext.newInstance(UserCollectionMessage.class);
Marshaller marshallerTarget = contextTarget.createMarshaller();
marshallerTarget.marshal(target, out);
}catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
String srcMsgFileName = "src/source.xml";
String tgtMsgFileName = "src/target.xml";
try {
InputStream in = new FileInputStream(new File(srcMsgFileName));
OutputStream out = new FileOutputStream(new File(tgtMsgFileName));
CRM_CustomerInformation_to_ERP_UserCollection myMapping = new CRM_CustomerInformation_to_ERP_UserCollection();
myMapping.execute(in, out);
System.out.println("Mapping test completed successfully");
} catch (Exception e) {
System.err.println("Mapping test failed");
e.printStackTrace();
}
}
}
By using the generated message classes, the syntax is easy to be read and its logic is straightforward comparing with DOM or SAX.
2.6 Export the program into JAR and import it to SAP PI
Since the source java files are coming from three different packages, these packages all should be selected and exported to avoid syntax error in SAP PI
After imported, the classes list in the imported archive is like this
3 Unit Test
This is the test conducted in the operation mapping
Check the target message. The mapping program handled namespace by itself.
4 Reference
https://rocksolutions.blog/2010/08/04/sample-on-jaxb-using-eclipse/
https://blogs.sap.com/2012/02/07/forget-sax-and-dom-java-mapping-just-got-cooler-with-jaxb-part-2/
Thank you for the great guide.
When executing my java mapping in the PI during the execution of:
JAXBContext jaxbContext = JAXBContext.newInstance([class_name].class);
the program throws an error containing only "null"
When attempting to use class'es context path instead:
JAXBContext jaxbContext = JAXBContext.newInstance([class_name].class.getPackage().getName(););
The PI asks for a jaxb.properties file
Do you have any idea?
Hi Roy
have you import class_name to your program?
for instance, when the following statement has been written
The class CustomerInformation has to be generated by JAXB from the XSD and imported to the program
On the other hand, if your xsd does contain any referenced types, please check the tutorial below to be parsed via a catalog file. Make sure your eclipse has internet connection.
http://blog.bdoughan.com/2011/10/jaxb-xjc-imported-schemas-and-xml.html