How to add custom import statements in the generated java file in xtext using jvmmodelInferrer? - dsl

I have written a grammar for my domain specific language in xtext and I am using jvmmodelInferrer to generate java code. I can generate fields and custom methods but how can I add custom import statements like 'import java.util.*' in the generated java file without the user having to explicitly write the import statement?

you dont generate import strings. you just use rich strings in a proper way and everything happens automatically
def dispatch void infer(Model element, IJvmDeclaredTypeAcceptor acceptor, boolean isPreIndexingPhase) {
for (greeting : element.greetings) {
acceptor.accept(greeting.toClass("demo." + greeting.name)) [
members += greeting.toMethod("demo", Void.TYPE.typeRef) [
body = '''
«JFrame» f = null;
«"java.util.List".typeRef("java.lang.String".typeRef)» l = null;
return;
'''
]
]
}
}

Related

Create dynamic xml parametrized block with groovy

I have a comma-separated list/array as input to the groovy script. based on the number of elements in the array, I need to create parameterized XML block like below.
eg if the input is CAT,DOG
I need to create an XML block like below
<v2:values>
<v2:item>CAT</v2:item>
<v2:item>DOG</v2:item>
</v2:values>
if the input is CAT,DOG,ROSE
I need output as
<v2:values>
<v2:item>CAT</v2:item>
<v2:item>DOG</v2:item>
<v2:item>ROSE</v2:item>
</v2:values>
if Input is empty I need output block as empty
I wrote a groovy script like this
if(input.contains(","))
{
String[] param_array = input1[0].split(',')
res="<v2:values>"
for (parameter in param_array)
{
after that, I am not sure how do I iterate over the array and put values for other XML tags. Is there any way to do that?
You can use StreamingMarkupBuilder to generate the XML into a String
It won't be pretty-printed, but it will be valid XML as requested:
import groovy.xml.*
def input = 'cat,mouse,dog'
String xml = new StreamingMarkupBuilder().bind {
'v2:values' {
input.split(',').collect { item ->
'v2:item'(item)
}
}
}
println xml
If you need it pretty printed, you will need to know where the schema for v2 is, as XmlUtil.serialize needs the xml to validate
Edit
If you need it pretty printed, you can switch to MarkupBuilder
import groovy.xml.*
def input = 'cat,mouse,dog'
def writer = new StringWriter()
new MarkupBuilder(writer).'v2:values' {
input.split(',').collect { item ->
'v2:item'(item)
}
}
println writer.toString()

Groovy to validate if Node exists or not

I'm trying to validate in Groovy if a node came from an external system, if the external system has a value the node comes with a value, if the system dont have a value the node doesn't come in the payload.
Based on this i need to change/correct if its a NEW or UPDATE process for that record in an existing node.
Incoming XML is:
<urn:ExternalReqForApprovalImportRequest xmlns:urn="urn:Ariba:Buyer:vrealm_1" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xs="http://www.w3.org/2001/XMLSchema" partition="" variant="">
<urn:ExternalReqForApprovalInput_Item>
<urn:item>
<urn:Name>TEST</urn:Name>
<urn:Operation>XXXXXX</urn:Operation>
<urn:HeaderExtrinsics>
<Extrinsics>
<Extrinsic name="PRRefID">THIS IS THE NODE THAT MAY OR NOT MAY COME</Extrinsic>
<Extrinsic name="XXXXXXX">Value</Extrinsic>
<Extrinsic name="AnotherField">TValue</Extrinsic>
</Extrinsics>
</urn:HeaderExtrinsics>
</urn:item>
</urn:ExternalReqForApprovalInput_Item>
</urn:ExternalReqForApprovalImportRequest>
I created this groovy:
import com.sap.gateway.ip.core.customdev.util.Message;
import java.util.HashMap;
import java.lang.String;
def Message processData(Message message) {
map = message.getProperties();
value = map.get("PRRefID");
Reader reader = message.getBody(Reader)
def FG = new XmlParser().parse(reader)
if(value == null) {
FG.'urn:ExternalReqForApprovalInput_Item'.'urn:item'.'urn:HeaderExtrinsics'.Operation = "NEW"
} else {
FG.'urn:ExternalReqForApprovalInput_Item'.'urn:item'.'urn:HeaderExtrinsics'.Operation = "UPDATE"
}
message.setBody(FG);
return message;
}
What i want to achieve is validate if Extrinsic with name PRRefID comes in the xml, if it comes i need to update the Operation to UPDATE, if it doesnt come i need to set NEW as the value.
I tried to map the xpath as a Property (probably there is a cleaner way to map this from the direct xpath), but my issue right now is changing the value, since its a extrinsic with a specific name, apparently that is nor the right format for the assignation, so which should it be?
Thank you.
Just needs some syntax tweaks,
FG.'urn:ExternalReqForApprovalInput_Item'.'urn:item'.'urn:HeaderExtrinsics'.Extrinsics.Extrinsic[0].value = "NEW"
You have to specify the namespace wherever necessary
Note that when you parse, FG becomes root of the document so don't specify urn:ExternalReqForApprovalImportRequest again
I assumed you are trying to update the text node value
Note also that Extrinsic will be an array of nodes, so you have to refer to it by index
I finally solved it following your recommendation in the namespace!
import com.sap.gateway.ip.core.customdev.util.Message;
import java.util.HashMap;
import java.lang.String;
import groovy.util.XmlSlurper
import groovy.xml.XmlUtil
def Message processData(Message message) {
map = message.getProperties();
value = map.get("PRRefID");
Reader reader = message.getBody(Reader)
def root = new XmlParser().parse(reader)
if(value == "") {
root.'urn:ExternalReqForApprovalInput_Item'.'urn:item'.'urn:Operation'[0].value = "NEW"
}
message.setBody(XmlUtil.serialize(root))
return message;
}
Thank you.

Using 'eachWithindex' groovy instead of For loops to read in json data

I'm having trouble with converting an existing FOR loop to use the 'eachWithIndex' groovy function.
I'm not sure how to go about doing this successfully, examples I've seen are quite straightforward on tutorials but I'm not sure how to make them work with groovy json files.
The current solution uses a For loop which reads in data from 3 different groovy files
Add_Page1_data = data.get("json_Page1")
Add_Page2_data = data.get("json_Page2")
Add_Page3_data = data.get("json_Page3")
for (int i=0; i< Add_Page1_data.size(); i++) {
execute(w, Add_Page1_data[i],
Add_Page2_data[i],
Add_Page3_data[i])
}
I then use the following code to populate data inside windows by accessing the page objects of the file before :
def execute(w, data1) {
def page1 = new PO_Add_Page1(wrapper: w)
page1.typeInSomeText(data1.sometext)
}
PageObject file looks like this:
class PO_Add_Page1 {
def typeInSomeText(val) {
wrapper.findWithLabel("Some Text . .").rightEditable().type(val)
}
Json file used contains multiple records like this:
{
"json_Page1": [
{
"sometext": "text1"
},
{
"sometext": "text2"
},
The json is fed in as the "data" which maps to elements on the page using the page object groovy file.
I wanted to be able to repeat the same functionality in a more groovy idiomatic way.
Any help would be much appreciated.

How to traverse AST tree

I'm trying to create an static analysis for Groovy. As a POC for my superiors I'm just trying to parse simple code and detect SQL injections, which are the easiest kind to spot. I did it successfully on Python, which is my main language, but my company mostly uses Grails (on Groovy).
This is what I have so far:
import org.codehaus.groovy.ast.expr.*;
import org.codehaus.groovy.ast.stmt.*;
import org.codehaus.groovy.ast.*
import org.codehaus.groovy.control.CompilePhase
import org.codehaus.groovy.ast.CodeVisitorSupport
import org.codehaus.groovy.ast.builder.AstBuilder
public class SecurityCheck extends CodeVisitorSupport {
void visitBlockStatement(BlockStatement statement) {
println "NEW BLOCK STATEMENT:"
println statement.getText();
//keep walking...
statement.getStatements().each { ASTNode child ->
println "CHILD FOUND: "
println child.getText();
child.visit(this)
}
}
}
def code = new File('groovy_source.groovy').text // get the code from the source file
def AstBuilder astBuilder = new AstBuilder() // build an instance of the ast builder
def ast = astBuilder.buildFromString(CompilePhase.CONVERSION, code) // build from string when the compiler converts from tokens to AST
def SecurityCheck securityCheck = new SecurityCheck() // create an instance of our security check class
println ast
println ast[0]
ast[0].visit(securityCheck)
The groovy_source.groovy file is very simple, containing only a minimal file with a super easy to spot vulnerability:
def post(id) {
query = "SELECT * FROM table WHERE id = " + id;
result = sql.execute query
return result;
}
It is my understanding that, as I'm inheriting from CodeVisitorSupport, this would just visit a BlockStatement and then, for each statement inside that statement, it would visit it using the method from the supper class.
Nevertheless, when I print the text from the BlockStatement, it is an empty string, and the for each method never even gets called (which I assume must mean the AST found no children for my block statement, even when the function definitively has statements inside it.
[org.codehaus.groovy.ast.stmt.BlockStatement#363a52f[]] // println ast
org.codehaus.groovy.ast.stmt.BlockStatement#363a52f[] // println ast[0]
NEW BLOCK STATEMENT:
{ } // println statement.getText()
Any help here would be tremendously appreciated. Thanks!
I found the answer. I wasn't so hard in the end, but the horrible documentation doesn't make it easy. If you one to traverse the tree, you need to give the constructor the false boolean as a second argument, like this:
def ast = astBuilder.buildFromString(CompilePhase.CONVERSION, false, code)
Then you can use the visit* methods as you expect.

External Content with Groovy BuilderSupport

I've built a custom builder in Groovy by extending BuilderSupport. It works well when configured like nearly every builder code sample out there:
def builder = new MyBuilder()
builder.foo {
"Some Entry" (property1:value1, property2: value2)
}
This, of course, works perfectly. The problem is that I don't want the information I'm building to be in the code. I want to have this information in a file somewhere that is read in and built into objects by the builder. I cannot figure out how to do this.
I can't even make this work by moving the simple entry around in the code.
This works:
def textClosure = { "Some Entry" (property1:value1, property2: value2) }
builder.foo(textClosure)
because textClosure is a closure.
If I do this:
def text = '"Some Entry" (property1:value1, property2: value2)'
def textClosure = { text }
builder.foo(textClosure)
the builder only gets called for the "foo" node. I've tried many variants of this, including passing the text block directly into the builder without wrapping it in a closure. They all yield the same result.
Is there some way I take a piece of arbitrary text and pass it into my builder so that it will be able to correctly parse and build it?
Your problem is that a String is not Groovy code. The way ConfigSlurper handles this is to compile the text into an instance of Script using GroovyClassLoader#parseClass. e.g.,
// create a Binding subclass that delegates to the builder
class MyBinding extends Binding {
def builder
Object getVariable(String name) {
return { Object... args -> builder.invokeMethod(name,args) }
}
}
// parse the script and run it against the builder
new File("foo.groovy").withInputStream { input ->
Script s = new GroovyClassLoader().parseClass(input).newInstance()
s.binding = new MyBinding(builder:builder)
s.run()
}
The subclass of Binding simply returns a closure for all variables that delegates the call to the builder. So assuming foo.groovy contains:
foo {
"Some Entry" (property1:value1, property2: value2)
}
It would be equivalent to your code above.
I think the problem you described is better solved with a slurper or parser.
See:
http://groovy.codehaus.org/Reading+XML+using+Groovy%27s+XmlSlurper
http://groovy.codehaus.org/Reading+XML+using+Groovy%27s+XmlParser
for XML based examples.
In your case. Given the XML file:
<foo>
<entry name='Some Entry' property1="value1" property2="value2"/>
</foo>
You could slurp it with:
def text = new File("test.xml").text
def foo = new XmlSlurper().parseText(text)
def allEntries = foo.entry
allEntries.each {
println it.#name
println it.#property1
println it.#property2
}
Originally, I wanted to be able to specify
"Some Entry" (property1:value1, property2: value2)
in an external file. I'm specifically trying to avoid XML and XML-like syntax to make these files easier for regular users to create and modify. My current solution uses ConfigSlurper and the file now looks like:
"Some Entry"
{
property1 = value1
property2 = value2
}
ConfigSlurper gives me a map like this:
["Some Entry":[property1:value1,property2:value2]]
It's pretty simple to use these values to create my objects, especially since I can just pass the property/value map into the constructor.

Resources