2023 has been the year of AI and of generative AI in particular. AI is not a new topic, of course. In fact it’s quite old. But since OpenAI launched ChatGPT in November of 2022, the pace of innovation in AI has gone through the roof with no sign of slowing down any time soon.
So it probably didn’t come as a huge surprise, when Jürgen Müller announced in his SAP TechEd 2023 keynote, that SAP is embedding generative AI into SAP Integration Suite.
(I’m going to refer to generative AI as GenAI in the rest of this blog post.)
One of the areas where GenAI is making a huge impact is coding assistants. That is, an AI copilot that assists developers by generating code, documentation etc. We don’t yet know the details of how SAP intends to embed GenAI into SAP Integration Suite, but an AI copilot for creating integration flows seems a pretty safe bet.
GenAI excels at creating text, so generating scripts in SAP Cloud Integration is another area where an AI copilot would make a lot of sense. And script generation is something we can experiment with already now, without having to wait for SAP’s AI copilot to launch.
Creating Groovy scripts with GenAI is an area I’d been wanting to look into for a while, so when OpenAI launched their custom GPT feature, I decided to give it a go.
Custom GPTs were announced at OpenAI’s DevDay conference in San Francisco in November, 2023. You can check out the announcement here. Custom GPTs are a way to specialise ChatGPT in a particular field or topic. They are built on the GPT-4 foundation model, OpenAI’s most powerful model so far. The model is specialised via prompting and so-called knowledge files; there is no coding or complex (and costly) fine-tuning involved in the process. This made a custom GPT a perfect fit for my project.
Custom GPTs can be shared, but at the moment, they are only available to ChatGPT Plus members (a paid subscription) and OpenAI enterprise customers. OpenAI plans to launch a store for custom GPTs at a later date.
An AI assistant needs a proper name, of course, and I named mine GroovyScriptinator. My approach to training was iterative: Try a prompt, identify anything that needs tweaking in the response, update the instructions accordingly and repeat.
Out of the box, GPT-4 is already very capable of generating Groovy code. For that reason, I focused my training efforts on the following three more specific areas:
Here are some examples of instructions from the first category:
processData
or the Script step must be configured with the non-default function nameHere are some examples of instructions from the second category:
Reader
object to XmlSlurper
and JsonSlurper
Here are some examples of instructions from the third category:
def
and a type when declaring a variableAt the moment, my instructions for GroovyScriptinator come in at around 1800 words, but that number will likely keep growing. 1800 words is roughly the length of this blog post without the code listings.
While working on my custom GPT, I’ve been using a number of prompts for testing its performance. I’ve chosen four examples for this blog post to demonstrate what’s possible. For each example I’ve linked to the conversation, so you can see the full response for yourself.
The first example is based on this question from the SAP Community. I edited out the part about an existing script, because I wanted GroovyScriptinator to come up with a full solution to the problem. This is the script it generated in response:
import com.sap.gateway.ip.core.customdev.util.Message
import groovy.json.JsonSlurper
import groovy.json.JsonOutput
def Message processData(Message message) {
// Parse the JSON payload
def jsonPayload = new JsonSlurper().parseText(message.getBody(String))
// Remove the 'shippingPackages' object
jsonPayload.remove('shippingPackages')
// Set the modified JSON back to the message body
message.setBody(JsonOutput.toJson(jsonPayload))
return message
}
This script works and generates the requested output. It’s nicely formatted and even has decent comments. It’s actually pretty similar to my own answer to the same question.
The two scripts differ in one respect, though: The payload should really be passed to JsonSlurper
as a Reader
object instead of a String
object (that way a large payload is not read needlessly into memory). This best practice is actually part of my GroovyScriptinator instructions, but it seems to have temporarily forgotten that (more on that below).
I asked it to correct this and received the following script in response:
import com.sap.gateway.ip.core.customdev.util.Message
import groovy.json.JsonSlurper
import groovy.json.JsonOutput
def Message processData(Message message) {
// Access the JSON payload as a Reader
def payloadReader = message.getBody(Reader)
// Parse the JSON payload
def jsonPayload = new JsonSlurper().parse(payloadReader)
// Remove the 'shippingPackages' object
jsonPayload.remove('shippingPackages')
// Set the modified JSON back to the message body
message.setBody(JsonOutput.toJson(jsonPayload))
return message
}
This script also generates the requested output and correctly accesses the payload via the more efficient Reader
. You can view the full conversation here.
My second example is based on this SAP Community question (JSON is a popular Groovy scripting topic). I once again edited out the part about an existing script to see GroovyScriptinator’s own solution to the problem. This is the script it generated for me:
import com.sap.gateway.ip.core.customdev.util.Message
import groovy.json.JsonSlurper
import groovy.json.JsonOutput
def Message processData(Message message) {
// Parse the JSON payload
def jsonParser = new JsonSlurper()
def jsonPayload = message.getBody(Reader)
def parsedJson = jsonParser.parse(jsonPayload)
// Add the new root node
def modifiedJson = [data: parsedJson]
// Convert the modified JSON back to String
String jsonString = JsonOutput.toJson(modifiedJson)
// Set the modified JSON as the new payload
message.setBody(jsonString)
return message
}
The script works correctly and this time around, GroovyScriptinator correctly used a Reader
to access the payload. It even pointed out that the provided input JSON is, in fact, not valid and that the script only works, when the input is valid.
The only thing I’d point out is that it’s a little odd to declare all variables with def
except jsonString
, which is declared with its type (String
). It’s a tiny detail, though. You can view the full conversation here.
My third example is a script that I needed for myself. This is the prompt I used:
“I need a script that creates a plain text payload containing the names of all environment variables and their values. I would like the output formatted as “NAME = VALUE”, one name/value pair on each line.”
This is the script I received in response:
import com.sap.gateway.ip.core.customdev.util.Message
def Message processData(Message message) {
// StringBuilder for constructing the output
def output = new StringBuilder()
// Iterate over all environment variables and append them to the output
System.env.each { key, value ->
output << key << " = " << value << '\n'
}
// Set the generated string as the message payload
message.setBody(output.toString())
return message
}
This script works and it’s a very decent solution to my problem. Short, sweet and to the point. It uses a StringBuilder
to compose the payload efficiently and even uses the Groovy way of appending to the StringBuilder
with the <<
operator. The only thing I’d point out is that the appended string with the equals sign really should be in single quotes, but that’s a very minor gripe. You can view the full conversation here.
The last example is a requirement I made up specifically for testing GroovyScriptinator. I used the following prompt:
“I need a script that turns a fixed-length format text payload into a comma-separated text payload.
The payload contains a number of lines. The columns in the file has the following lengths: 3, 6, 3, 5, 2
Trailing spaces should be removed from the fourth column (but only from the fourth column).
Here is an example input line:
xyz123456abcdef 99
Here is the corresponding output line:
xyz,123456,abc,def,99
You can assume that each line has the same length, and this length is the sum of the column lengths.”
Here’s the script that GroovyScriptinator responded with:
import com.sap.gateway.ip.core.customdev.util.Message
def Message processData(Message message) {
// Define column lengths
def columnLengths = [3, 6, 3, 5, 2]
// Get the payload as a string
def payload = message.getBody(String)
def lines = payload.split('\n')
def newLines = []
lines.each { line ->
def start = 0
def columns = columnLengths.collect { length ->
def column = line.substring(start, start + length)
start += length
column
}
// Trim trailing spaces from the fourth column
columns[3] = columns[3].trim()
// Join columns with commas
newLines << columns.join(',')
}
// Set the modified payload back into the message
message.setBody(newLines.join('\n'))
return message
}
This script solves the problem as stated and is really quite nice. I basically don’t have any notes. It kept the column lengths in an appropriate data structure, rather than hardcoding them into the script. It even got it right that the fourth column has index 3. You can view the full conversation here.
The above examples are not staged and have not been doctored in any way. They are representative of the standard of the code created by the custom GPT. It does make mistakes (see the below FAQ), but in general the quality of the responses is very high. Many of the generated scripts are so good that they can be added to your integration flow as is or with minimal modifications. I’d like you to pause for a moment and think about how powerful that is!
So my conclusion is rather obvious: An AI copilot is a perfect fit for Groovy scripting in SAP Cloud Integration and there is no question whatsoever about feasibility. I have no doubt that GenAI will be part of your daily work as an SAP Cloud Integration developer. And it will likely happen sooner rather than later.
You probably have a lot of questions! I’ve tried to answer some of them in the following FAQ, but please feel free to ask questions in the comments as well. If I missed any obvious ones I’ll add them to the FAQ.
No. You can do SAP Cloud Integration development without knowing Groovy, but if you want to add Groovy scripting to your toolbox (and I definitely think you should!), then you need to learn the language.
You could, of course. But what happens after the script has been generated? First off, you won’t know if it actually works. And even if it seems to work, you won’t know why or under which circumstances. If you then throw caution to the wind, deploy the script in production and it breaks, it will be your responsibility to fix it, but you’ll have no idea how to fix it.
This is the reason why it’s generally a really, really bad idea to add code that you do not understand to your integration solution. It will come back to bite you in the haunt you later on.
Yes. If you have used ChatGPT or similar GenAI chatbots before, you have very likely experienced this yourself as well.
I’m really impressed with the quality of the code generated by my custom GPT. That doesn’t mean it’s foolproof, though! It will still sometimes gladly and confidently present you with code that has syntax errors or code that is syntactically correct but just doesn’t work. It also sometimes forgets parts of its instructions.
Absolutely not. It really just emphasizes the copilot role of GenAI coding assistants. A human in the pilot’s seat is still needed and with GenAI that person has a powerful productivity tool available to them.
If you ignore GenAI right now, you do so at your peril. This is not another technology fad that can be waited out with a bit of patience. Love it or hate it, you need to understand what GenAI is, what it can and cannot do and how it can be applied in your context.
If there’s interest, I might at some point. I’d like to tinker with it some more first, though.