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.
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 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.
I am using hazelcast in my project and I want to unit test some function but i do not want it to connect to real hazelcast and perform test on it for that i created a custom mock class which simply uses scala map because in hazelcast maps also there
here is my code
trait UserRepository {
def getUserObj(id: String):Option[User]
def addToUserRepo(user: User)
}
class UserRepo extends UserRepository{
def getUserObj(id: String):Option[User] = {
val userMap = hcastClient.getMap[String, User]("UserMap")
val userObj = userMap.get(id)
Option(userObj)
}
def addToUserRepo(user: User) = {
val directUserMap: IMap[String, User] = hcastClient.getMap[String,User]("UserMap")
directUserMap.set(user.uuid, user)
}
and here i created a simple customized mocked version class where the functionality is same just; replaced it with scala map:
class UserRepoMock extends UserRepository {
val map:Map[String,User]=Map[String,User]()
def getUserMap:Map[String,User] = {
map
}
def getUserObj(id: String):User = {
val userMap = getUserMap
val userObj = userMap.get(id)
userObj
}
def addToUserRepo(user: User) = {
val userMap = getUserMap
userMap.put(user.uuid, user)
}
class UserUtil(userRepo:UserRepo) {
def addUser(user:User):Boolean={
try{
userRepo.addToUserRepo(user)
true
}
catch {
case e:Exception=>false
}
def getUser(id:String):User={
val user=userRepo.getUserObj(id)
user
}
Mow i want to unit test methods addUser and getUserof UserUtil class
by doing like this:
class UserUtilTest extends funSpec {
val userUtil=new UserUtil(new UserRepoMock)
userUtil.addUser //perform unit test on it
userUtil.getUser //perform unit test on it
// instead of doing this val userUtil=new UserUtil(new UserRepo)
}
but the compiler not allowing me to do that,there is something which i am missing, Please help me how can i achieve the desired functionality
This is the compiler error:
type mismatch; found : testhcastrepo.UserRepoMock required: com.repositories.UserRepo
Well: your utils class says:
class UserUtil(userRepo:UserRepo)
So it needs an instance of UserRepo.
But then your are passing an instance of UserRepoMock. A UserRepoMock is a UserRepository, as UserRepo is; but a UserRepoMock is not a UserRepo!
Probably it is as simple as changing the utils to
class UserUtil(userRepo:UserRepository)
to indicate that you don't want to specify a specific class. Instead you simply say: anything that has the trait will do!
Beyond that: the real answer might be: have a look at your naming habits. You see, those two names UserRepositor and UserRepo; they are pretty "close" to each other; and it is not at all clear, what the difference between the two is. If the names would be more distinct, like UserRepositoryTrait and HCastUserRepository you probably would not have made this mistake in the first place (not sure my suggestions are "good" names according to scala conventions; but they are just meant to give you an idea).
I am new to Scala and I need to have a scala wrapper for my Java API
I have three Java Interfaces
public interface Client<T> {
<T> Future<T> execute(App<T> app);
}
public interface App<T> extends Serializable{
T process(AppContext context) throws Exception;
}
public interface AppContext {
File getDirectory();
void deleteDirectory();
File createDirectory(String path);
}
Following is the Java code to create an App
public class RandomApp extends App<String> {
#Override
public String process(AppContext context) {
// Inorder to access the methods in AppContext I need to access
// it by the following way
appContext.createDirectory("some path");
return "random";
}
}
I want to have a Scala Wrapper for the Client Interface which in turn call the Java API. But I have some modifications for the new Scala API
object ScalaConverter {
implicit class ScalaWrapper(client: Client) {
def scalaClient = new ScalaClient(client)
}
}
class ScalaClient(client: Client) {
def execute[T](appContext: AppContext => T): Future[T] = {
// I am passing appContext as closure instead of passing in
// App because I want to take the advantage of Closures in Scala
// I basically want to create an App with this appContext and
// pass it to the execute method
// For example - but this is not working
var app = // Need to create this app with appContext
Future {
client.execute(app)
}
}
}
If I'm not mistaken, you just want to be able to create App objects from a function that takes a AppContext as parameter and returns a any object (let's say T).
As it's not really interesting to try to mirror the whole java API, just use it as it is, but add some extensions. And to do this you should use implicits.
To do this, I see two possibilities: either add an implicit class on the Client interface to add some functions to it, or add an implicit conversion from (AppContext => T) to App objects.
Let's got with the first solution, you have to embed the implicit class in an object (this can be a package object if you need automatic imports).
object ScalaConverter {
class ScalaApp[T](val block: AppContext => T) extends App[T] {
def process(context: AppContext): T = block(context)
}
implicit class ScalaClient(client: Client) extends AnyVal{
def execute[T](block: AppContext => T): Future[T] = {
client.execute(new ScalaApp(block))
}
}
}
Then, you just have to use your existing java Client object:
import ScalaConverter._
myJavaClient.execute { context =>
???
}
You should get the principle, I maybe made a mistake (did not tried to compile this)
I'm using Play Framework 2.0.3 and would like to add a filter that will internally re-route certain requests (that is, without a 301/302) to a URL in the app that is determined dynamically. That is, the endpoint that I'll need to forward to depends on the request, so I don't know at compile time which controller/action it'll be, and can't just call them directly.
For example, if I get a request for GET /foo?redirectTo=/bar, how could I make Play internally route/process it as if it was actually a POST /bar?
This gist is my best guess so far, but it has some limitations: https://gist.github.com/brikis98/5582159
Just call the corresponding controller method.
Java version:
public static Result foo() {
return bar();
}
public static Result bar() {
return ok();
}
Am I missing something?
So you need to transform your Request from a GET request into a POST.
I'm not aware of any automatic way of doing that, but it should be fairly easy.
Could you explain a bit more why you need that ?
Julien.
Alright, here is a solution that seems to work:
object RedirectFilter extends Filter {
def apply(next: RequestHeader => Result)(request: RequestHeader): Result = {
getRedirectParams(request).flatMap { case (newRequest, body) =>
route(newRequest).map { iteratee =>
AsyncResult(Enumerator(body).run(iteratee))
}
} getOrElse {
next(request)
}
}
private def getRedirectParams(request: RequestHeader): Option[(RequestHeader, Array[Byte])] = {
if (someCondition) {
Some(toPostRequest(request), "Some new body data".getBytes("UTF-8"))
} else {
None
}
}
private def toPostRequest(originalRequest: RequestHeader): RequestHeader = {
originalRequest.copy(
uri = "/some/new/uri",
path = "/some/new/uri",
method = "POST"
)
}
private def route(request: RequestHeader): Option[Iteratee[Array[Byte], Result]] = {
Play.global.onRouteRequest(request).collect {
case action: EssentialAction => Play.global.doFilter(action)(request)
}
}
}
Check out this gist for some other useful comments.