I have a groovy script that may have some undefined properties:
// a new file say: test.groovy
import Comp;
if (a == null) { // a is a missing property
return new obj();
}
def objComp = new Comp(name: 'tim')
return objComp
I want to execute test.groovy and extract the JSON format of objComp using
new JsonBuilder(objComp).toPrettyString()
which can print something like
{
name: 'tim'
}
However I keep getting groovy.lang.MissingPropertyException because of the missing property a. I tried to use a separate class that extends Expando, but I get the same Exception:
class MyClass extends Expando {
def myMethod() {
def sharedData = new Binding()
def shell = new GroovyShell(sharedData)
result = shell.evaluate 'def test() { "eval test" }; return test()' // works fine
String fileContent = new File("/path/to/test.groovy").text
result = shell.evaluate(fileContent) // leads to MissingPropertyException
}
}
I was hoping using Expando would fix the MissingPropertyException, but it doesn't.
Related
I am creating a class that is responsible for validating a configuration. This class calls other classes that validate said config by creating new instances in the form of a chain. At first glance, the code structure looks horrible, but It works. Anyway, I think it's not the best way to handle this logic.
I leave here a simplified version of the code in TypeScript, but I also leave it in Python and Java for reference only:
class Validator {
private _notValidatedConfig: NotValidatedConfig
constructor(notValidatedConfig: NotValidatedConfig) {
this._notValidatedConfig = notValidatedConfig
}
validateConfig(): ValidatedConfig {
return (
new Phase4Validation(
new Phase3Validation(
new Phase2Validation(
new Phase1Validation(
this._notValidatedConfig
).validate()
).validate()
).validate()
).validate()
)
}
// Alternative
validateConfig2(): ValidatedConfig {
const validatedPhase1Config: ValidatedPhase1Config = new Phase1Validation(this._notValidatedConfig).validate()
const validatedPhase2Config: ValidatedPhase2Config = new Phase2Validation(validatedPhase1Config).validate()
const validatedPhase3Config: ValidatedPhase3Config = new Phase3Validation(validatedPhase2Config).validate()
const validatedPhase4Config: ValidatedPhase4Config = new Phase4Validation(validatedPhase3Config).validate()
return validatedPhase4Config;
}
}
Python
Java Disclaimer: I don't have any experience with Java, so maybe there are some syntax errors.
The "alternative" is the same code, but not directly chained, instead, for every validation, it's creating a new variable.
I think the "alternative" is more readable but performs worse.
What do you think about this code? what did you change? How would you face this problem or with what design pattern or framework? (programming language doesn't matter for these question)
I would create a base class Validation and just create derived classes from it if it is necessary to add new validation:
public abstract class Validation
{
public Validation(string config)
{
}
public abstract string Validate();
}
and its concrete implementations:
public class Phase1Validation : Validation
{
public Phase1Validation(string config) : base(config)
{}
public override string Validate()
{
if (true)
return null;
return "There are some errors Phase1Validation";
}
}
public class Phase2Validation : Validation
{
public Phase2Validation(string config) : base(config)
{
}
public override string Validate()
{
if (true)
return null;
return "There are some errors in Phase2Validation";
}
}
and then just create a list of validators and iterate through them to find errors:
public string Validate()
{
List<Validation> validations = new List<Validation>()
{
new Phase1Validation("config 1"),
new Phase2Validation("config 2")
};
foreach (Validation validation in validations)
{
string error = validation.Validate();
if (!string.IsNullOrEmpty(error))
return error;
}
return null; // it means that there are no errors
}
UPDATE:
I've little bit edited my classes to fit your new question requirements:
validations should be ordered. Added Order property
get config from previous validation and send it to the next validation
It can be seen that this approach allows to avoid to write nested classes like this:
new Phase4Validation(
new Phase3Validation(
new Phase2Validation(...).validate()
).validate()
).validate()
So you can add new classes without editing validation classes and it helps to keep Open CLosed Principle of SOLID principles.
So the code looks like this:
Abstractions:
public abstract class Validation
{
// Order to handle your validations
public int Order { get; set; }
// Your config file
public string Config { get; set; }
public Validation(int order)
{
Order = order;
}
// "virtual" means that method can be overriden
public virtual string Validate(string config)
{
Config = config;
if (true)
return null;
return "There are some errors Phase1Validation";
}
}
And its concrete implementations:
public class Phase1Validation : Validation
{
public Phase1Validation(int order) : base(order)
{
}
}
public class Phase2Validation : Validation
{
public Phase2Validation(int order) : base(order)
{
}
}
And method to validate:
string Validate()
{
List<Validation> validations = new List<Validation>()
{
new Phase1Validation(1),
new Phase2Validation(2)
};
validations = validations.OrderBy(v => v.Order).ToList();
string config = "";
foreach (Validation validation in validations)
{
string error = validation.Validate(config);
config = validation.Config;
if (!string.IsNullOrEmpty(error))
return error;
}
return null; // it means that there are no errors
}
I leave here my own answer, but I'm not going to select it as correct because I think there exist better answers (besides the fact that I am not very convinced of this implementation).
A kind of Decorator design pattern allowed me to do chain validation with greater use of the dependency injection approach.
I leave here the code but only for Python (I have reduced the number of phases from 4 to 2 to simplify the example).
from __future__ import annotations
import abc
from typing import cast
from typing import Any
from typing import TypedDict
NotValidatedConfig = dict
ValidatedConfig = TypedDict("ValidatedConfig", {"foo": Any, "bar": Any})
class InvalidConfig(Exception):
...
# This class is abstract.
class ValidationHandler(abc.ABC):
_handler: ValidationHandler | None
def __init__(self, handler: ValidationHandler = None):
self._handler = handler
# This method is abstract.
#abc.abstractmethod
def _validate(self, not_validated_config: NotValidatedConfig):
...
def _chain_validation(self, not_validated_config: NotValidatedConfig):
if self._handler:
self._handler._chain_validation(not_validated_config)
self._validate(not_validated_config)
def get_validated_config(self, not_validated_config: NotValidatedConfig) -> ValidatedConfig:
self._chain_validation(not_validated_config)
# Here we convert (in a forced way) the type `NotValidatedConfig` to
# `ValidatedConfig`.
# We do this because we already run all the validations chain.
# Force a type is not a good way to deal with a problem, and this is
# the main downside of this implementation (but it works anyway).
return cast(ValidatedConfig, not_validated_config)
class Phase1Validation(ValidationHandler):
def _validate(self, not_validated_config: NotValidatedConfig):
if "foo" not in not_validated_config:
raise InvalidConfig('Config miss "foo" attr')
class Phase2Validation(ValidationHandler):
def _validate(self, not_validated_config: NotValidatedConfig):
if not isinstance(not_validated_config["foo"], str):
raise InvalidConfig('"foo" must be an string')
class Validator:
_validation_handler: ValidationHandler
def __init__(self, validation_handler: ValidationHandler):
self._validation_handler = validation_handler
def validate_config(self, not_validated_config: NotValidatedConfig) -> ValidatedConfig:
return self._validation_handler.get_validated_config(not_validated_config)
if __name__ == "__main__":
# "Pure Dependency Injection"
validator = Validator((Phase2Validation(Phase1Validation())))
validator.validate_config({"foo": 1, "bar": 1})
What is the problem with this approach?: the lightweight way in which the types are concatenated. In the original example, the Phase1Validation generates a ValidatedPhase1Config, which is safely used by the Phase2Validation. With this implementation, each decorator receives the same data type to validate, and this creates safety issues (in terms of typing). The Phase1Validation gets NotValidatedConfig, but the Phase2Validation can't use that type to do the validation, they need the Phase1Validation.
I want to set a Map of attributes to my plugin extension. So basically I want to write something like
settings {
envVars = {
a = "abc"
b = "dec"
...
n = "sdf"
}
}
When I use an attribute in my Extension class
private Map<?,?> envVars;
Gradle tells me that it can not set the property settings. So what I would like to achieve is to set a map of values in my extension class.
What I did achieve is to get the closure when i write the following:
settings {
envVars {
a = "abc"
b = "dec"
...
n = "sdf"
}
}
public class extension {
....
public envVars(Closure c){}
}
But then I have no clue what to do with the closure and how to access what is inside, so I would rather have a Map instead of the closure
Regards
Mathias
Ok, you just have to write the map properly :/
envVars = [test: 'test']
and everything is fine
I am using the following to read a map of values from build.gradle
reference: https://github.com/liquibase/liquibase-gradle-plugin
Container class:
class Database {
def name
def arguments = [logLevel: 'info']
Database(String name) {
this.name = name
}
Extension Class:
class MyExtension {
final NamedDomainObjectContainer<Database> databases
def databases(Closure closure){
databases.configure(closure)
}
def methodMissing(String name, args) {
arguments[name] = args[0]
}
}
Load Extensions
def databases = project.container(Database) { name ->
new Database(name)
}
project.configure(project) {
extensions.create("extensionName", MyExtension, databases)
}
Sample build.gradle:
dbDiff{
databases{
db1{
url 'testUrl'
}
}
}
I'd like to use the args4j Java library in my Scala v2.10 application. However, I am running into some trouble. As an example, I have a class to store my arguments in Java as follows.
public class MyArgs {
#Option(name = "-i", usage = "file input", required = true)
private String input;
public String getInput() { return input; }
}
I then have a Scala program like the following.
object TestArgs {
def main(args: Array[String]): Unit = {
val myArgs = new MyArgs()
val cmdLineParser = new CmdLineParser()
try {
cmdLineParser.parseArgument(java.util.Arrays.asList(args: _*))
} catch {
case e: Exception => {
System.err.println(e.getMessage)
}
}
}
}
In IntelliJ, I pass in something like -i some/path/to/file.txt, but i keep getting the following message.
"-i" is not a valid option
Any ideas on what's going on?
You can use the args4j Java library directly; however, might I suggest this wrapper library.
Scala helper using args4j
This implementation works for me using Scala 2.10, Spark 1.6
// import the Java args4j
import org.kohsuke.args4j.Option
// import the scala wrapper
import OptionsHelper.optionsOrExit
object SparkScalaTest {
def main(args: scala.Array[String]) {
// setupt the options
class MyOptions extends OptionsWithHelp {
#Option(name="--foo", aliases=Array("-f"), usage="foo bar", required=false)
var update: Boolean = false // this is the default value, since it is not required
}
//Parse arguments
val options = optionsOrExit(args, new MyOptions)
sc.stop
}
}
I want to allow users to run their Groovy scripts in my Java server app, but I also want disallow them to use #Grab for adding any random dependencies.
Yes, I can simply cut off all #Grab annotations by search & replace in source code, but it will be better to do this in more elegant way, e.g. allow approved dependencies only.
And yes, I know that the best solution of this prob is JVM's SecurityManager.
There are various approaches, such as the Groovy Sandbox, which may work better than what you're about to see.
import groovy.grape.Grape
Grape.metaClass.static.grab = {String endorsed ->
throw new SecurityException("Oh no you didn't! Grabbing is forbidden.")
}
Grape.metaClass.static.grab = {Map dependency ->
throw new SecurityException("Oh no you didn't! Grabbing is forbidden.")
}
Grape.metaClass.static.grab = {Map args, Map dependency ->
throw new SecurityException("Oh no you didn't! Grabbing is forbidden.")
}
def source1 = '''
println('This is a nice safe Groovy script.')
'''
def source2 = '''
#Grab('commons-validator:commons-validator:1.4.1')
import org.apache.commons.validator.routines.EmailValidator
def emailValidator = EmailValidator.getInstance();
assert emailValidator.isValid('what.a.shame#us.elections.gov')
assert !emailValidator.isValid('an_invalid_emai_address')
println 'You should not see this message!'
'''
def script
def shell = new GroovyShell()
try {
script = shell.parse(source1)
script.run()
} catch (Exception e) {
assert false, "Oh, oh. That wasn't supposed to happen :("
}
try {
script = shell.parse(source2)
assert false, "Oh, oh. That wasn't supposed to happen :("
} catch (ExceptionInInitializerError e) {
println 'Naughty script was blocked when parsed.'
}
The example above demonstrates how to block #Grab. It does this not by blocking the annotation, but by overriding the method call added by the annotation: groovy.grape.Grape.grab().
Grape.metaClass.static.grab = {String endorsed ->
throw new SecurityException("Oh no you didn't! Grabbing is forbidden.")
}
Grape.metaClass.static.grab = {Map dependency ->
throw new SecurityException("Oh no you didn't! Grabbing is forbidden.")
}
Grape.metaClass.static.grab = {Map args, Map dependency ->
throw new SecurityException("Oh no you didn't! Grabbing is forbidden.")
}
Here's the naughty script dissected by the Groovy Console AST viewer:
#groovy.lang.Grab(module = 'commons-validator', group = 'commons-validator', version = '1.4.1')
import org.apache.commons.validator.routines.EmailValidator as EmailValidator
public class script1440223706571 extends groovy.lang.Script {
private static org.codehaus.groovy.reflection.ClassInfo $staticClassInfo
public static transient boolean __$stMC
public script1440223706571() {
}
public script1440223706571(groovy.lang.Binding context) {
super(context)
}
public static void main(java.lang.String[] args) {
org.codehaus.groovy.runtime.InvokerHelper.runScript(script1440223706571, args)
}
public java.lang.Object run() {
java.lang.Object emailValidator = org.apache.commons.validator.routines.EmailValidator.getInstance()
assert emailValidator.isValid('what.a.shame#us.elections.gov') : null
assert !(emailValidator.isValid('an_invalid_emai_address')) : null
return null
}
static {
groovy.grape.Grape.grab([:], ['group': 'commons-validator', 'module': 'commons-validator', 'version': '1.4.1'])
}
protected groovy.lang.MetaClass $getStaticMetaClass() {
}
}
Here you can see the call to Grape.grab() in the static initializer. To add fine-grained filtering of dependencies, you can introspect the dependency and endorsed parameters.
dependency
['group': 'commons-validator', 'module': 'commons-validator', 'version': '1.4.1']
endorsed
commons-validator:commons-validator:1.4.1
Revised Implementation
This new implementation uses an Interceptor to block/allow Grape grabs.
import groovy.grape.GrapeIvy
def source1 = '''
println('This is a nice safe Groovy script.')
'''
def source2 = '''
#Grab('commons-validator:commons-validator:1.4.1')
import org.apache.commons.validator.routines.EmailValidator
def emailValidator = EmailValidator.getInstance();
assert emailValidator.isValid('what.a.shame#us.elections.gov')
assert !emailValidator.isValid('an_invalid_emai_address')
println 'You should not see this message!'
'''
def script
def shell = new GroovyShell()
def proxy = ProxyMetaClass.getInstance(GrapeIvy)
proxy.interceptor = new GrapeInterceptor({group, module, version ->
if(group == 'commons-validator' && module == 'commons-validator') false
else true
})
proxy.use {
shell.parse(source1).run()
try {
shell.parse(source2).run()
} catch (org.codehaus.groovy.control.MultipleCompilationErrorsException e) {
assert e.message.contains('unable to resolve class')
}
}
#groovy.transform.TupleConstructor
class GrapeInterceptor implements Interceptor {
private boolean invokeMethod = true
Closure authorizer
def afterInvoke(Object object, String methodName, Object[] arguments, Object result) {
invokeMethod = true
return result
}
def beforeInvoke(Object object, String methodName, Object[] arguments) {
if(methodName == 'createGrabRecord') {
def dependencies = arguments[0]
invokeMethod = authorizer(dependencies.group, dependencies.module, dependencies.version)
} else {
invokeMethod = true
}
return null
}
boolean doInvoke() { invokeMethod }
}
The GrapeInterceptor constructor takes a Closure as its only argument. With this Closure you can easily decide whether to allow the Grab to occur or not :)
For example, if the Grab looks like this: #Grab('commons-validator:commons-validator:1.4.1')
The Closure's arguments would be assigned as follows:
group: commons-validator
module: commons-validator
version: 1.4.1
To allow the Grab, the Closure must return true. Return false to block it.
It has been a couple of days since I started with Groovy. But with all the reading and surfing, I haven't quite been able to figure out how to accomplish what I have in mind. So, please excuse me as a beginner. Would be much grateful for your help, as always.
What I want to achieve is this: I have a Java class, say ServiceClass that has some methods (getMethod(), postMethod() etc) to make some REST GET/POST requests (on its own, it works fine). Now, I want to expose a DSL so that the end-user may just say something like: callService ServiceClass method getMethod and I have the execution of ServiceClass.getMethod()
What I have been trying so far is this: I got a userCommand file placed somewhere, that for now just reads: callService ServiceClass
I have a sample.groovy that just does this now:
class Sample {
def srvc
def callService(srvc) {
this.srvc = srvc
"Calling $srvc"
}
}
I got an integrator.groovy file that has:
//necessary imports
class Integrator{
def sample = new Sample()
def binding = new Binding([
sample:sample,
ServiceClass: new ServiceClass(),
callService:sample.&callService ])
def shell = new GroovyShell(binding)
def runIt() {
shell.evaluate("userCommand")
}
}
And then to run it from my Java application, I am doing:
public static void main(String[] args) {
Integator i = new Integrator()
i.runIt();
}
But this is just not working. With the above syntax it says:
Exception in thread "main" java.lang.NullPointerException: Cannot invoke method setVariable() on null object....
Could anyone please tell me how do I pass around parameters and create object instances?
Update: Consider the following userCommand file:
File userCommand:
callService ServiceClass getMethod
Which will be parsed by groovy as callService(ServiceClass).getGetMethod(). So you need a getProperty method which reroute the call to the correct method:
File Dsl.groovy:
class Dsl {
static void main(args) {
new Integrator().runIt()
}
}
class DslDelegate {
def service
def callService(service) {
this.service = service
this
}
def getProperty(String prop) {
if (prop == "getMethod") { service.getMethod() }
else { throw new RuntimeException("Unrecognized property '$prop'") }
}
}
class ServiceClass {
def getMethod() { "serviceClass getMethod" }
}
class Integrator{
def dslDelegate = new DslDelegate()
def binding = new Binding([
ServiceClass: new ServiceClass(),
callService:dslDelegate.&callService ])
def shell = new GroovyShell(binding)
def runIt() {
assert shell.evaluate(new File("userCommand")) ==
"serviceClass getMethod"
}
}
Note I renamed the Sample class, so it becomes a delegator to ServiceClass. Now it separates DSL/Service responsibilities.
You can do callService ServiceClass method getMethod too, but it requires more code.