I want to create GStringExpression that will represent this text line
"Exception: $all"
Its constructor can either have verbatimText or verbatimText, strings[], values[]
GStringExpression
How my text should be represented for GStringExpression?
For example this code
new GStringExpression("Exception:", [], [ new ConstantExpression("all") ])
results in "Exception:".
When I try to use $all inside verbatimText I am unable to compile it due to missing all
It seems it is using verbatim because the generated code looks like this,
while my catchStatement implementation looks like this
Parameter parameter =
new Parameter(ClassHelper.make(Exception.class), "all")
ExpressionStatement returnStatement = new ExpressionStatement (
new MethodCallExpression(
new VariableExpression("this"),
new ConstantExpression("println"),
new ArgumentListExpression([
new GStringExpression(null,
[
new ConstantExpression("Exception:")
],
[ new VariableExpression("all") ]
)
])
)
)
new CatchStatement(parameter, returnStatement)
The verbatimText is not used in the code generated from a GStringExpression. It's only here to have errors messages, or to "pretty dump" an AST.
The parameters strings and values are exactly the same as the parameters of the GStringImpl constructor. The code generated only push these properties into the stack, and call the constructor.
You can't transform a GString into an GStringExpression easily. In Groovy, this parsing is done with the antlr parser in the context of a script (and not only a GString). There is no methods with take a GString and create a GroovyExpression.
In your case, if the GString you want to create is "hello ${name}", then you have to pass as the strings parameters an array with a ConstantExpression with the value "hello ", and as the values parameters an array with a VariableExpression or a FieldExpression.
If what you want to do is only parsing a GString (and you are not creating an AST transformation) then you should probably use a TemplateEngine.
Related
I'm perplexed by Groovy's behavior here. I've run through the debugger some to try to determine where in the dynamic mixins these code paths may be getting crossed but wondered if anyone could set me straight here.
Basically, in setting a system property with a GString for a value, depending on how I set the property, the property is not always readable back via certain methods.
I have seen Why Map does not work for GString in Groovy? and Why groovy does not see some values in dictionary? but my question specifically applies to map values so not sure those apply or not?
Snippet :
def tdollar='dollar'
System.setProperty('key1', 'value1')
System.setProperty('key2', "value2$tdollar")
// Replace the below with any property setting method other than
// the above with the same results
System.properties['key4']='value4'
System.properties['key5']="value5$tdollar"
println System.hasProperty('key1')
println System.hasProperty('key2')
println System.hasProperty('key4')
println System.hasProperty('key5')
println
println System.getProperty('key1')
println System.getProperty('key2')
println System.getProperty('key4')
println System.getProperty('key5')
println
println System.properties.keySet()
println
println System.properties['key1']
println System.properties['key2']
println System.properties['key4']
println System.properties['key5']
Output:
null
null
null
null
value1
value2dollar
value4
null
[java.runtime.name, sun.boot.library.path, java.vm.version, gopherProxySet, java.vm.vendor, java.vendor.url, path.separator, java.vm.name, file.encoding.pkg, user.country, sun.java.launcher, sun.os.patch.level, program.name, key5, key4, java.vm.specification.name, user.dir, key2, java.runtime.version, key1, java.awt.graphicsenv, java.endorsed.dirs, os.arch, java.io.tmpdir, line.separator, java.vm.specification.vendor, os.name, tools.jar, sun.jnu.encoding, script.name, java.library.path, java.specification.name, java.class.version, sun.management.compiler, os.version, user.home, user.timezone, java.awt.printerjob, file.encoding, java.specification.version, java.class.path, user.name, java.vm.specification.version, sun.java.command, java.home, sun.arch.data.model, user.language, java.specification.vendor, awt.toolkit, java.vm.info, java.version, java.ext.dirs, sun.boot.class.path, java.vendor, file.separator, java.vendor.url.bug, sun.io.unicode.encoding, sun.cpu.endian, groovy.starter.conf, groovy.home, sun.cpu.isalist]
value1
value2dollar
value4
value5dollar
Why, if I don't use System.setProperty(key, value) syntax, is the property not readable via System.getProperty(key), but is still readable via any other method?
Given this behavior, is there a best practice documented regarding System properties in Groovy.
Writing this, I wonder if this is just a general map question. Will test.
System.setProperty('key2', "value2$tdollar")
When you operate using this above method, the second argument is implicitly cast to a String from a GString
System.properties['key5']="value5$tdollar"
this use the underlying setProperties method in the System class (not setProperty), and hence gets resolved differently, causing issues. The GString might not be getting cast correctly or not getting converted to a string before being sent to the underlying java class. If you change the value from a GString to a string like this:
System.properties['key5']="value5" + tdollar
the issue disappears
so I have been stuck with this problem for quite some time now.
I'm working with some data provided as JSON and retrieved via WSLITE using groovy.
So far handling the json structur and finding data was no problem since the webservice response provided by WSLITE
is retuned as an instance of JsonSlurper.
I now came across some cases where the structure that json response varies depending on what I query for.
Structure looks like this:
{
"result":[
...
"someId": [...]
"somethingElse": [...]
...
"variants":{
"0123":{
"description": "somethingsomething",
...,
...,
"subVariant":{
"1234001":{
name: "somename",
...
}
}
},
"4567":{
"description": "somethingsomething",
...,
...,
"subVariant":{
"4567001":{
name: "somename"
...
...
}
}
}
}
]
}
As you can see, the variants node is an object holding another nested object which holds even more nested objects.
The problem here is that the variants node sometimes holds more than one OBJECT but always at least one. Same vor the subVariant node.
Furthermore I do not now the name of the (numeric) nodes in advance. hence i have to build the path dinamically.
Since Json is handled as maps, lists and arrays in groovy I thought I was able to do this:
def js = JsonSlurper().parseText(jsonReponse)
println js.result.variants[0].subVariant[0].name //js.result.variants.getClass() prints class java.util.ArrayList
but that returns null
while accessing the data statically like this:
println "js.result.variants."0123".subVariant."1234001".name
works just fine.
Just pinting the variants like this
println js.result.variants
also works fine. it prints the first (and only) content of the whole variants tree.
My question is: Why is that?
It kind of seems like i can not address nexted objects by index... am i right? how else would i got about that?
thanks in advance.
Well the reason you cant access it using [0] is simply because "variants": { ... isnt an array, that would look like this: "variants" :[ ...
So your variants is an object with a variable number of attributes, which is basically a named map.
However, if you dont know the entry names, you can iterate through these using .each, so you could do something like js.result.variants.each{key, val -> println val.description}
And something similar for the subvariant
I have a DSL that looks like this:
aMethod {
"a name"
"another name"
"and a third name"
}
My Problem is that I'm unable to access the three string, because calling the closure only returns the last statement. I tried to override the constructor of String(char[] value) which is called when an anonymous String-statement occurs:
def original
// primitive way to get the String(char[])-constructor
String.class.constructors.each {
if(it.toString() == "public java.lang.String(char[])") {
original = it
}
}
// overriding the constructor
String.metaClass.constructor = { char[] value ->
def instance = original.newInstance(value)
// ... do some further stuff with the instance ...
println "Created ${instance}"
instance
}
// teststring to call String(char[] value)
"teststring"
Unfortunately it didn't work and I thought anyway that it is quite complicated.
Thank you for the comments. Actually it would be great to define everything without quotes. But: After having a dsl that can be translated to java objects I'd loved to have additional annotations in my language at development time. I want to annotate duplicate names and so on. The IDE's I know better, Intellij and Eclipse handle Strings "a name" as one PSI-Elements. Splitting these elements can be very inconvinient ... I guess. I think statements in a closure like aMethod {a name} would result in an interpretation like aMethod {a.name}. That would mean that instead of having a StringLiteral Psi "a name", I would have an Object-Psi and a MethodCall-Psi or something like that. I don't know, and my next goal is just "parsing/creating" my java objects. Are you sure that it is impossible to override the String-Constructor?
Is any constructor called when you have a groovy script with this content:
"hello World"
I try to create a GArray but I have always the same error :
const GLib = imports.gi.GLib;
var garray = new GLib.Array(true, true, 1); // Unable to construct
boxed type Array since it has no zero-args , can only
wrap an existing one
var garray = new GLib.Array(); // Unable to construct boxed type Array
since it has no zero-args , can only wrap an existing one
I need a GArray to use it in the GnomeKeyring.item_create_sync method :
GnomeKeyring.item_create_sync(
"login",
4,
"name",
new GLib.Array(true, true, 1)
"pass",
true);
I tried other type of array instead of GArray, here are the errors
[] -> Object 0xb5d120d0 is not a subclass of (null), it's a Array
new Array() -> Object 0xb5e12138 is not a subclass of (null), it's a Array
{} -> Object 0xb5d0b1b0 is not a subclass of (null), it's a Object
5 -> Unhandled GType GArray unpacking GArgument from Number
"5" -> Expected type interface for Argument 'attributes' but got type 'string'
If anyone has a solution for GArray or for GnomeKeyring.item_create_sync
Read /usr/share/gir-1.0/GnomeKeyring-1.0.gir and search for function name="item_create_sync". You have all required parameters there and it seems to me that you need a plain list. GnomeObjectIntrospection will translate it to the GArray when needed.
The GNOME Shell's retrospection will convert between JS and GNOME types on its own accord where possible and required. If you create an array in the JS space and pass it to a function that requires a GArray, the Shell will convert if you pass the array as argument.
The only objects that aren't converted are those whose classes exist in one space, but not the other. Like the GNOME File Objects, as JS has no native filehandlers.
You can use the .toString() method on filestreams to get their contents as a string, or call the reading methods to get the binary values as an array of integers.
I'm getting a text which contains ${somethingElse} inside, but it's just a normal String.
I've got a class:
class Whatever {
def somethingElse = 5
void action(String sth) {
def test = []
test.testing = sth
assert test.testing == 5
}
}
Is it possible with groovy?
EDIT:
my scenario is: load xml file, which contains nodes with values pointing to some other values in my application. So let's say I've got shell.setVariable("current", myClass). And now, in my xml I want to be able to put ${current.someField} as a value.
The trouble is, that the value from xml is a string and I can't evaluate it easily.
I can't predict how these "values" will be created by user, I just give them ability to use few classes.
I cannot convert it when the xml file is loaded, it has to be "on demand", since I use it in specific cases and I want them to be able to use values at that moment in time, and not when xml file is loaded.
Any tips?
One thing you could do is:
class Whatever {
def somethingElse = 5
void action( String sth ) {
def result = new groovy.text.GStringTemplateEngine().with {
createTemplate( sth ).make( this.properties ).toString()
}
assert result == "Number 5"
}
}
// Pass it a String
new Whatever().action( 'Number ${somethingElse}' )
At first, what we did, was used this format in xml:
normalText#codeToExecuteOrEvaluate#normalText
and used replace closure to regexp and groovyShell.evaluate() the code.
Insane. It took a lot of time and a lot of memory.
In the end we changed the format to the original one and crated scripts for each string we wanted to be able to evaluate:
Script script = shell.parse("\""+stringToParse+"\"")
where
stringToParse = "Hello world # ${System.currentTimeMillis()}!!"
Then we were able to call script.run() as many times as we wanted and everything performed well.
It actually still does.