Skip to Content
Technical Articles
Author's profile photo Morten Wittrock

Reflecting on the Message class

Updated June 26th, 2019: A lot has changed since this blog post was originally published. Message is now an interface, and JavaDoc API documentation is available. There is also a JAR file available (the so-called Script API), containing the Message interface. It can be downloaded from the SAP Development Tools site. Even though the technique described in the following is no longer needed, I’m leaving the blog post in place as a historical record 🙂

This great question by Malcolm Dingle inspired me to take a closer look at the methods of the com.sap.gateway.ip.core.customdev.util.Message class. An object of this class is passed to our script functions in SAP Cloud Platform Integration, and through it we get access to the payload, headers etc. Its methods are documented to some degree, but JavaDoc API documentation is not available, and neither is a JAR file containing the class.

We can still get a complete list of the class’s methods, though. How? Using Java’s reflection API. With reflection, we can inspect the members of a class, including its methods, at runtime. Given an object, we can get a Class object, representing the object’s class, by calling the getClass() method. Once we have the Class object, we can get that class’s public methods by calling the getMethods() method. To learn more about Java reflection, you can visit the Java tutorial.

Combine this with Groovy’s MarkupBuilder class (which I wrote about in this blog post), and we have the building blocks for a script, that creates an XML document containing every method of the Message class.

Without further ado, here is the script:

import com.sap.gateway.ip.core.customdev.util.Message
import groovy.xml.MarkupBuilder

def Message processData(Message message) {
   def sw = new StringWriter()
   def builder = new MarkupBuilder(sw)
   builder.methods {
      message.getClass().getMethods().each { m ->
         method(m.toString())
      }
   }
   message.setBody(sw.toString())
   return message
}

If you want to run the code, create an integration flow with a sender HTTPS channel, no receiver and the script as its only step. Then proceed to call the endpoint from Postman or a similar tool.

At the time of writing, the script generates the following XML output:

<methods>
  <method>public java.lang.Object com.sap.gateway.ip.core.customdev.util.Message.getBody(java.lang.Class) throws org.apache.camel.TypeConversionException</method>
  <method>public java.lang.Object com.sap.gateway.ip.core.customdev.util.Message.getBody()</method>
  <method>public void com.sap.gateway.ip.core.customdev.util.Message.setBody(java.lang.Object)</method>
  <method>public java.util.Map com.sap.gateway.ip.core.customdev.util.Message.getAttachments()</method>
  <method>public void com.sap.gateway.ip.core.customdev.util.Message.setAttachments(java.util.Map)</method>
  <method>public java.util.Map com.sap.gateway.ip.core.customdev.util.Message.getHeaders()</method>
  <method>public java.lang.Object com.sap.gateway.ip.core.customdev.util.Message.getHeader(java.lang.String,java.lang.Class) throws org.apache.camel.TypeConversionException</method>
  <method>public void com.sap.gateway.ip.core.customdev.util.Message.setHeaders(java.util.Map)</method>
  <method>public void com.sap.gateway.ip.core.customdev.util.Message.setHeader(java.lang.String,java.lang.Object)</method>
  <method>public java.util.Map com.sap.gateway.ip.core.customdev.util.Message.getProperties()</method>
  <method>public void com.sap.gateway.ip.core.customdev.util.Message.setProperties(java.util.Map)</method>
  <method>public void com.sap.gateway.ip.core.customdev.util.Message.setProperty(java.lang.String,java.lang.Object)</method>
  <method>public java.lang.Object com.sap.gateway.ip.core.customdev.util.Message.getProperty(java.lang.String)</method>
  <method>public long com.sap.gateway.ip.core.customdev.util.Message.getBodySize()</method>
  <method>public long com.sap.gateway.ip.core.customdev.util.Message.getAttachmentsSize()</method>
  <method>public void com.sap.gateway.ip.core.customdev.util.Message.addAttachmentHeader(java.lang.String,java.lang.String,com.sap.gateway.ip.core.customdev.util.AttachmentWrapper)</method>
  <method>public void com.sap.gateway.ip.core.customdev.util.Message.setAttachmentHeader(java.lang.String,java.lang.String,com.sap.gateway.ip.core.customdev.util.AttachmentWrapper)</method>
  <method>public java.lang.String com.sap.gateway.ip.core.customdev.util.Message.getAttachmentHeader(java.lang.String,com.sap.gateway.ip.core.customdev.util.AttachmentWrapper)</method>
  <method>public void com.sap.gateway.ip.core.customdev.util.Message.removeAttachmentHeader(java.lang.String,com.sap.gateway.ip.core.customdev.util.AttachmentWrapper)</method>
  <method>public java.util.Map com.sap.gateway.ip.core.customdev.util.Message.getAttachmentWrapperObjects()</method>
  <method>public void com.sap.gateway.ip.core.customdev.util.Message.setAttachmentWrapperObjects(java.util.Map)</method>
  <method>public void com.sap.gateway.ip.core.customdev.util.Message.addAttachmentObject(java.lang.String,com.sap.gateway.ip.core.customdev.util.AttachmentWrapper)</method>
  <method>public void com.sap.gateway.ip.core.customdev.util.Message.addAttachmentHeader(java.lang.String,java.lang.String,org.apache.camel.Attachment)</method>
  <method>public void com.sap.gateway.ip.core.customdev.util.Message.setAttachmentHeader(java.lang.String,java.lang.String,org.apache.camel.Attachment)</method>
  <method>public java.lang.String com.sap.gateway.ip.core.customdev.util.Message.getAttachmentHeader(java.lang.String,org.apache.camel.Attachment)</method>
  <method>public void com.sap.gateway.ip.core.customdev.util.Message.removeAttachmentHeader(java.lang.String,org.apache.camel.Attachment)</method>
  <method>public java.util.Map com.sap.gateway.ip.core.customdev.util.Message.getAttachmentObjects()</method>
  <method>public void com.sap.gateway.ip.core.customdev.util.Message.setAttachmentObjects(java.util.Map)</method>
  <method>public void com.sap.gateway.ip.core.customdev.util.Message.addAttachmentObject(java.lang.String,org.apache.camel.Attachment)</method>
  <method>public final native java.lang.Class java.lang.Object.getClass()</method>
  <method>public native int java.lang.Object.hashCode()</method>
  <method>public boolean java.lang.Object.equals(java.lang.Object)</method>
  <method>public java.lang.String java.lang.Object.toString()</method>
  <method>public final native void java.lang.Object.notify()</method>
  <method>public final native void java.lang.Object.notifyAll()</method>
  <method>public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException</method>
  <method>public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException</method>
  <method>public final void java.lang.Object.wait() throws java.lang.InterruptedException</method>
</methods>

To make this a bit more readable, I’ve removed the methods inherited from java.lang.Object and cleaned up the package names. The final list of methods looks like this:

  • public Object getBody(Class) throws TypeConversionException
  • public Object getBody()
  • public void setBody(Object)
  • public Map getAttachments()
  • public void setAttachments(Map)
  • public Map getHeaders()
  • public Object getHeader(String, Class) throws TypeConversionException
  • public void setHeaders(Map)
  • public void setHeader(String, Object)
  • public Map getProperties()
  • public void setProperties(Map)
  • public void setProperty(String, Object)
  • public Object getProperty(String)
  • public long getBodySize()
  • public long getAttachmentsSize()
  • public void addAttachmentHeader(String, String, AttachmentWrapper)
  • public void setAttachmentHeader(String, String, AttachmentWrapper)
  • public String getAttachmentHeader(String, AttachmentWrapper)
  • public void removeAttachmentHeader(String, AttachmentWrapper)
  • public Map getAttachmentWrapperObjects()
  • public void setAttachmentWrapperObjects(Map)
  • public void addAttachmentObject(String, AttachmentWrapper)
  • public void addAttachmentHeader(String, String, Attachment)
  • public void setAttachmentHeader(String, String, Attachment)
  • public String getAttachmentHeader(String, Attachment)
  • public void removeAttachmentHeader(String, Attachment)
  • public Map getAttachmentObjects()
  • public void setAttachmentObjects(Map)
  • public void addAttachmentObject(String, Attachment)

Here are the fully qualified class names of the classes not in java.lang and java.util:

Class Fully qualified class name
AttachmentWrapper com.sap.gateway.ip.core.customdev.util.AttachmentWrapper
Attachment org.apache.camel.Attachment
TypeConversionException org.apache.camel.TypeConversionException

Assigned Tags

      4 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Former Member
      Former Member

      Great article.  One neat thing to think about, is creating stub java classes for the basic Message,MessageLogFactory and others.

      Then, once you create a stub class with some basic functionality, you have the ability to test your groovy scripts outside of HCI.

      Author's profile photo Jay Malla
      Jay Malla

      Nice article Morten.  Is there any way to be able to run the Groovy script developed during the HCI development just in Eclipse without running the flow in HCI?  We have a complex map that we have developed and if we could run this just from Eclipse, that would be nice - but I am not sure if we can get the SAP HCI jars that are needed for the import statements from the Groovy script.  Have you tried to do this?

      Thanks,

      Jay

      Author's profile photo Eng Swee Yeoh
      Eng Swee Yeoh

      https://people.sap.com/jay.malla3, if you haven't found an answer to your question, here it is:-

      https://blogs.sap.com/2017/10/06/how-do-you-test-your-groovy-scripts/

       

      Regards

      Eng Swee

       

      Author's profile photo Jay Malla
      Jay Malla

      Hi Eng - Thanks for the information.  This is really helpful.  It will make debugging the Groovy script from HCI so much easier.

      Cheers,

      Jay