griffon javafx-groovy and fxml? - groovy

I tried the samples given in github griffon-master, also I tried the samples of the guide.
I would like to use javafx and groovy.
I would like to use fxml - thought of a scenario as that: fxml to set the stage, and for changes, use the groovy (set adjustment)
It seems that is not possible. I can use ("make it run"): javafx-java, read an fxml (with loadFromFXML), and the bindings are working. If using javafx-groovy, I can read an fxml, but with the javafx-class Loader (load), and bindings are not working (or it seems so).
Is it not possible at this moment, to use javafx-groovy and read-in fxml (via loadfromfxml)?

Could you post some sample code? Here's one example that makes use of the fxml node form GroovyFX
package org.example
import griffon.core.artifact.GriffonView
import griffon.metadata.ArtifactProviderFor
import javafx.scene.control.Tab
import org.codehaus.griffon.runtime.javafx.artifact.AbstractJavaFXGriffonView
#ArtifactProviderFor(GriffonView)
class Tab4View extends AbstractJavaFXGriffonView {
FactoryBuilderSupport builder
SampleController controller
SampleModel model
private AppView parentView
void initUI() {
builder.with {
content = builder.fxml(resource('/org/example/tab4.fxml')) {
inputLabel.text = application.messageSource.getMessage('name.label')
bean(input, text: bind(model.inputProperty()))
bean(output, text: bind(model.outputProperty()))
}
}
connectActions(builder.content, controller)
Tab tab = new Tab('Hybrid')
tab.content = builder.content
parentView.tabPane.tabs.add(tab)
}
}

This can be done. The trick is to make your Controller actions adhere to a stringent set of rules. The tldr is to make sure they return void.
Good:
def void save() {
Bad:
def save() {
The reason is found in the reflective analysis the Griffon framework uses to create its list of action targets. This list is generated in DefaultGriffonControllerClass.getActionNames(), which requires that:
Actions are subject to the following rules in order to be considered as such:
must have public (Java) or default (Groovy) visibility modifier.
name does not match an event handler, i.e, it does not begin with on.
must pass {code GriffonClassUtils.isPlainMethod()} if it's a method.
must have void as return type if it's a method.
value must be a closure (including curried method pointers) if it's a property.
The criteria defined in GriffonClassUtils.isPlainMethod() are as follows:
isInstanceMethod(method)
! isBasicMethod(method)
! isGroovyInjectedMethod(method)
! isThreadingMethod(method)
! isArtifactMethod(method)
! isMvcMethod(method)
! isServiceMethod(method)
! isEventPublisherMethod(method)
! isObservableMethod(method)
! isResourceHandlerMethod(method)
! isGetterMethod(method)
! isSetterMethod(method)
! isContributionMethod(method)
The list of action target names is subsequently used by AbstractActionManager:
#Nullable
private static Method findActionAsMethod(#Nonnull GriffonController controller, #Nonnull String actionName) {
for (Method method : controller.getClass().getMethods()) {
if (actionName.equals(method.getName()) &&
isPublic(method.getModifiers()) &&
!isStatic(method.getModifiers()) &&
method.getReturnType() == Void.TYPE) {
return method;
}
}
return null;
}

Related

How to decorate the final class DocumentGenerator

I am having problems to decorate the final class "DocumentGenerator" (in vendor/shopware/core/Checkout/Document/Service/DocumentGenerator.php) and overwrite the "generate" function inside of it.
I tried to decorate it the usual way, but an error is thrown because the "DocumentController" class excepts the original class and not my decorated one?
Argument 2 passed to Shopware\Core\Checkout\Document\DocumentGeneratorController::__construct() must be an instance of Shopware\Core\Checkout\Document\Service\DocumentGenerator
Its also not possible to extend from the class in my decorated class, because the "DocumentGenerator" is a final class.
My goal is to execute additional code, after an order document is generated. Previously I successfully used to decorate the "DocumentService" Class, but its marked as deprecated and shouldnt be used anymore. Also the "DocumentGenerator" class is used for the new "bulkedit" function for documents as of Version 6.4.14.0
I'm grateful for every tip.
As #j_elfering already wrote it's by design that you should not extend that class and therefore also shouldn't decorate it.
To offer a potential alternative:
Depending on what you want to do after a document has been generated it might be enough to add a subscriber to listen to document.written, check if it was a new document created and then work with the data from the payload for fetching/persisting data depending on that.
public static function getSubscribedEvents()
{
return [
'document.written' => 'onDocumentWritten',
];
}
public function onDocumentWritten(EntityWrittenEvent $event): void
{
foreach ($event->getWriteResults() as $result) {
if ($result->getOperation() !== EntityWriteResult::OPERATION_INSERT) {
// skip if the it's not a new document created
continue;
}
$payload = $result->getPayload();
// do something with the payload
}
}
Probably not what you want to hear but: The service is final in purpose as it is not intended to be decorated.
So the simple answer is you can't. Depending on your use case there may be other ways that don't rely on decoration.

What is the use of a static initialization block in Groovy?

What is the use of the static initialization block in Groovy. Why does Geb use it? If the use of it is the same as in Java, then how can you initialize non-declared fields in a situtation like this?
class ManualsMenuModule extends Module {
static content = {
toggle { $("div.menu a.manuals") }
linksContainer { $("#manuals-menu") }
links { linksContainer.find("a") }
}
void open() {
toggle.click()
waitFor { !linksContainer.hasClass("animating") }
}
}
Some answers to your questions are provided in the section about the content DSL of the Geb manual.
The DSL is implemented using Groovy's methodMissing() mechanism and modification of the delegate of the closure assigned to the static content field. If you are interested in digging deeper then you can always look at the implementation in PageContentTemplateBuilder.
I'm not expert on Geb, I can only explain the groovy meaning of the code.
1st off, it's not the static initialization block like in java. In those lines static content = {...} you are assigning to a static variable a Closure instance which is evaluated and executed LATER (hence, lazy).
The closure represents a (part of) a Geb's Groovy Builder which is called by Geb framework to register/perform some tasks.
There's no Java counterpart to achieve the same, and that's the reason why groovy-based frameworks are so nice to use for testing purposes and they follow the general rule of thumb:
test code should be more abstract then the code under test
UPDATE:
This line:
toggle { $("div.menu a.manuals") }
can be rewritten like
toggle( { $("div.menu a.manuals") } )
or
def a = { $("div.menu a.manuals") }
toggle a
so it's a method invocation and not an assignment. In groovy you can omit the brackets in some cases.

Dynamic type inferring, or custom VariableScope. How is it done correctly?

I have a scripting system where depending on where the script is executed you have access to different variables. I also want to have inferred types for a type of Auto-Completion for the script editor.
But when the types are inferred during the compile phase, I have no way of giving a Binding which explains to the compilation phase what types those dynamic variables have.
I have currently solved this by:
Not compiling the code with either #TypeChecked nor #CompileStatic but later manually running a subclassed StaticCompilationVisitor on the dynamically typed codebase and manually filling in the StaticTypesMarker.INFERRED_TYPE inside visitVariableExpression() for the dynamic variables that I know exists.
However, this seems like the wrong way to go about it, and I would actually like to work with the VariableScope instead. But it seems to be under rough lockdown inside the VariableScopeVisitor, so it's difficult to pop in a CustomVariableScope that dynamically does the lookups. I have managed to do this with reflection, replacing the VariableScopeVisitor inside CompilationUnit and currentScope and such inside VaribleScopeVisitor. It works, but I don't like working against hard-coded private field names.
This might be a long-winded way of asking: Is there an official way of handling a situation of static typing with dynamic variables? I cannot do this by setting scriptBaseClass for reasons too complex to explain here.
If the question is unclear, please tell me and I'll try to edit in better explanations.
The answer was to add a GroovyTypeCheckingExtensionSupport to a StaticTypeCheckingVisitor and then use visitClass on the first ClassNode of the CompilationUnit.
final ClassNode classNode = this.compilationUnit.getFirstClassNode();
final StaticCompilationVisitor visitor = new StaticCompilationVisitor(this.sourceUnit, classNode);
visitor.addTypeCheckingExtension(new MyGroovyTypeCheckingExtensionSupport(visitor, this.compilationUnit));
visitor.visitClass(classNode);
visitor.performSecondPass();
And create something like the class below:
private static class MyGroovyTypeCheckingExtensionSupport extends GroovyTypeCheckingExtensionSupport {
private static final ClassNode CLASSNODE_OBJECT = ClassHelper.make(Object.class);
public MyGroovyTypeCheckingExtensionSupport(StaticTypeCheckingVisitor typeCheckingVisitor, CompilationUnit compilationUnit) {
super(typeCheckingVisitor, "", compilationUnit);
}
#Override
public boolean handleUnresolvedVariableExpression(VariableExpression vexp) {
final ClassNode type = this.getType(vexp);
if (type == null || type.equals(CLASSNODE_OBJECT)) {
if (vextp.getName().equals("something")) {
this.storeType(vexp, ClassHelper.make(SomeClass.class));
return true;
}
}
return false;
}
}

Grails: How to make everything I create Upper Case?

I am currently using CSS to change everything I write to upperCase when I create an entry, but that is not enough. When I save things, the text shown in the text fields is upper case, but the real value that Grails stores stays in lower case.
I am assuming I'd need to change something in the controller or anything.
Maybe transforming the $fieldValue CSS could work??
Any ideas would help!
Thnks!
You could just write setters for your domain object?
class Domain {
String aField
void setAField( String s ){
aField = s?.toUpperCase()
}
}
I think you are asking how to change values on your domain objects to uppercase. If this is not the case please clarify the question.
You have a bunch of options. I would recommend
1) In a service method, before you save, using String.toUpperCase() to modify the appropriate values on the domain object.
or
2) You can use the underlying Hibernate interceptors by defining a beforeInsert method on your domain object, and doing the toUpperCase there. (see 5.5.1 of the grails documentation)
or
3) You could do this client side. However, if it is a "business requirement" that the values are stored as upper, then I recommend doing the translation server side. It is easier to wrap tests around that code....
Using annotations is cleanest approach
import org.grails.databinding.BindingFormat
class Person {
#BindingFormat('UPPERCASE')
String someUpperCaseString
#BindingFormat('LOWERCASE')
String someLowerCaseString
}
Here is link for it: Grails doc for data binding
You can use Groovy metaprogramming to change the setter for all domain class String-typed properties without actually writing a custom setter for each property.
To do this, add something like the following to the init closure of Bootstrap.groovy
def init = { servletContext ->
for (dc in grailsApplication.domainClasses) {
dc.class.metaClass.setProperty = { String name, value ->
def metaProperty = delegate.class.metaClass.getMetaProperty(name)
if (metaProperty) {
// change the property value to uppercase if it's a String property
if (value && metaProperty.type == String) {
value = value.toUpperCase()
}
metaProperty.setProperty(delegate, value)
} else {
throw new MissingPropertyException(name, delegate.class)
}
}
}
}

Best groovy closure idiom replacing java inner classes?

As new to groovy...
I'm trying to replace the java idiom for event listeners, filters, etc.
My working code in groovy is the following:
def find() {
ODB odb = ODBFactory.open(files.nodupes); // data nucleus object database
Objects<Prospect> src = odb.getObjects(new QProspect());
src.each { println it };
odb.close();
}
class QProspect extends SimpleNativeQuery {
public boolean match(Prospect p) {
if (p.url) {
return p.url.endsWith(".biz");
}
return false;
}
}
Now, this is far from what I'm used to in java, where the implementation of the Query interface is done right inside the odb.getObjects() method. If I where to code "java" I'd probably do something like the following, yet it's not working:
Objects<Prospect> src = odb.getObjects( {
boolean match(p) {
if (p.url) {
return p.url.endsWith(".biz");
}
return false;
}
} as SimpleNativeQuery);
Or better, I'd like it to be like this:
Objects<Prospect> src = odb.getObjects(
{ it.url.endsWith(".biz") } as SimpleNativeQuery
);
However, what groovy does it to associate the "match" method with the outer script context and fail me.
I find groovy... groovy anyways so I'll stick to learning more about it. Thanks.
What I should've asked was how do we do the "anonymous" class in groovy. Here's the java idiom:
void defReadAFile() {
File[] files = new File(".").listFiles(new FileFilter() {
public boolean accept(File file) {
return file.getPath().endsWith(".biz");
}
});
}
Can groovy be as concise with no additional class declaration?
I think it would have helped you to get answers if you'd abstracted the problem so that it didn't rely on the Neodatis DB interface -- that threw me for a loop, as I've never used it. What I've written below about it is based on a very cursory analysis.
For that matter, I've never used Groovy either, though I like what I've seen of it. But seeing as no one else has answered yet, you're stuck with me :-)
I think the problem (or at least part of it) may be that you're expecting too much of the SimpleNativeQuery class from Neodatis. It doesn't look like it even tries to filter the objects before it adds them to the returned collection. I think instead you want to use org.neodatis.odb.impl.core.query.criteria.CriteriaQuery. (Note the "impl" in the package path. This has me a bit nervous, as I don't know for sure if this class is meant to be used by callers. But I don't see any other classes in Neodatis that allow for query criteria to be specified.)
But instead of using CriteriaQuery directly, I think you'd rather wrap it inside of a Groovy class so that you can use it with closures. So, I think a Groovy version of your code with closures might look something like this:
// Create a class that wraps CriteriaQuery and allows you
// to pass closures. This is wordy too, but at least it's
// reusable.
import org.neodatis.odb.impl.core.query.criteria;
class GroovyCriteriaQuery extends CriteriaQuery {
private final c;
QProspect(theClosure) {
// I prefer to check for null here, instead of in match()
if (theClosure == null) {
throw new InvalidArgumentException("theClosure can't be null!");
}
c = theClosure;
}
public boolean match(AbstractObjectInfo aoi){
//!! I'm assuming here that 'aoi' can be used as the actual
//!! object instance (or at least as proxy for it.)
//!! (You may have to extract the actual object from aoi before calling c.)
return c(aoi);
}
}
// Now use the query class in some random code.
Objects<Prospect> src = odb.getObjects(
new GroovyCriteriaQuery(
{ it.url.endsWith(".biz") }
)
)
I hope this helps!
I believe your real question is "Can I use closures instead of anonymous classes when calling Java APIs that do not use closures". And the answer is a definite "yes". This:
Objects<Prospect> src = odb.getObjects(
{ it.url.endsWith(".biz") } as SimpleNativeQuery
);
should work. You write "However, what groovy does it to associate the "match" method with the outer script context and fail me". How exactly does it fail? It seems to me like you're having a simple technical problem to get the solution that is both "the groovy way" and exactly what you desire to work.
Yep, thanks y'all, it works.
I also found out why SimpleNativeQuery does not work (per Dan Breslau).
I tried the following and it worked wonderfully. So the idiom does work as expected.
new File("c:\\temp").listFiles({ it.path.endsWith(".html") } as FileFilter);
This next one does not work because of the neodatis interface. The interface does not enforce a match() method! It only mentions it in the documentation yet it's not present in the class file:
public class SimpleNativeQuery extends AbstactQuery{
}
Objects<Prospect> src = odb.getObjects(
{ it.url.endsWith(".biz") } as SimpleNativeQuery
);
In the above, as the SimpleNativeQuery does not have a match() method, it makes it impossible for the groovy compiler to identify which method in the SimpleNativeQuery should the closure be attached to; it then defaults to the outer groovy script.
It's my third day with groovy and I'm loving it.
Both books are great:
- Groovy Recipes (Scott Davis)
- Programming Groovy (Venkat Subramaniam)

Resources