How to make a "StringWriterMarkupBuilder" - groovy

How can I make a type which is a MarkupBuilder but has default constructor which is initialized with a StringWriter and overrides toString() to call the toString() on the StringWriter?
The idea is like the following, but of course initializing instance variables before super constructor calls is not allowed:
class StringWriterMarkupBuilder extends MarkupBuilder {
final def sw = new StringWriter()
StringWriterMarkupBuilder() {
super(sw)
}
#Override String toString() {
sw.toString()
}
}

Sorry, I finally figured out a solution by digging into the Groovy source code for MarkupBuilder!:
class StringWriterMarkupBuilder extends MarkupBuilder {
StringWriterMarkupBuilder() {
//MarkupBuilder.this(new IndentPrinter(new PrintWriter(writer)))
super(new StringWriter())
}
#Override String toString() {
//IndentPrinter.PrintWriter.StringWriter
return super.getPrinter().out.out.toString()
}
}

You could also do this with the metaClass like so:
import groovy.xml.MarkupBuilder
MarkupBuilder createSWMB() {
new StringWriter().with { sw ->
new MarkupBuilder( sw ).with { mb ->
mb.metaClass.toString = { -> sw.toString() }
mb
}
}
}
MarkupBuilder mb = createSWMB()
mb.root {
names {
name( first:'tim', second:'yates' )
}
}
println mb.toString()

Related

How to Create Nested Builder Based DSLs on Groovy using FactoryBuilderSupport

I want to create a nested builder. Something like:
meta('JSON') {
// JSON content using JSON Builder in this case
}
content('HTML') {
// HTML content using MarkupTemplateEngine in this case
}
I don't want to have
JsonBuilder builder = new JsonBuilder()
builder.author {
}
or
def builder = new groovy.xml.MarkupBuilder()
builder.html {
}
How can initial builder and the nested builder be setup?
I have defined the DSL common elements as:
import groovy.transform.CompileStatic
import org.eclipse.collections.impl.map.mutable.UnifiedMap
#CompileStatic
abstract class DSLElement extends UnifiedMap {
DSLElement(Map attributes) {
putAll(attributes)
}
getAt(Object key) {
get(key)
}
putAt(Object key, Object value) {
put(key, value)
}
}
#CompileStatic
class BaseFactoryBuilder extends FactoryBuilderSupport {
BaseFactoryBuilder(boolean init = true) {
super(init)
}
}
#CompileStatic
class DSLFactoryBuilder
extends BaseFactoryBuilder
implements MetaRegistration,
ContentRegistration,
TemplateRegistration {
}
Individual elements I have defined as:
import groovy.transform.CompileStatic
import groovy.transform.InheritConstructors
import groovy.transform.SelfType
#CompileStatic
#InheritConstructors
class Meta extends DSLElement {}
#CompileStatic
class MetaFactory extends AbstractFactory {
boolean isLeaf() {
return false
}
Object newInstance(FactoryBuilderSupport builder, Object name, Object value, Map attributes)
throws InstantiationException, IllegalAccessException {
return new Meta(attributes)
}
}
#SelfType(DSLFactoryBuilder)
#CompileStatic
trait MetaRegistration {
registerMeta() {
registerFactory("meta", new MetaFactory())
}
}
and
import groovy.transform.CompileStatic
import groovy.transform.InheritConstructors
import groovy.transform.SelfType
#CompileStatic
#InheritConstructors
class Content extends DSLElement {
}
#CompileStatic
class ContentFactory extends AbstractFactory {
boolean isLeaf() {
return false
}
Object newInstance(FactoryBuilderSupport builder, Object name, Object value, Map attributes)
throws InstantiationException, IllegalAccessException {
return new Content(attributes)
}
}
#SelfType(DSLFactoryBuilder)
#CompileStatic
trait ContentRegistration {
registerMeta() {
registerFactory("content", new ContentFactory())
}
}
I have not figured you how to do the nesting another builder and the parameter 'JSON' or 'HTML'.
I am following the FactoryBuilderSupport example given in: Groovy for Domain-Specific Languages
maybe i did not fully understand the question - it's too long to read and code you provided not runnable (or not full)
i assume you want to achieve this:
def html = meta('HTML'){
person(name:'foo')
}
def json = meta('JSON'){
person(name:'bar')
}
if so, here is a code to implement it
String meta(String ctxName, Closure builderBody){
def builder = null
def writer = null
if(ctxName=='HTML'){
writer=new StringWriter()
builder=new groovy.xml.MarkupBuilder(writer)
}else if(ctxName=='JSON'){
builder=new groovy.json.JsonBuilder()
}
else throw new RuntimeException("unsupported meta=`$ctxName`")
def result = builder.with(builderBody)
if(ctxName=='HTML'){
return writer.toString()
}else if(ctxName=='JSON'){
return builder.toPrettyString()
}
}
println meta('HTML'){
person(name:'foo')
}
println meta('JSON'){
person(name:'bar')
}
result:
<person name='foo' />
{
"person": {
"name": "bar"
}
}

How to override Groovy variable and method using anonymous class?

I have the following code. I have an abstract JobParams, a class extending that abstract GradleJobParams, and a gjp variable with value using anonymous class declaration.
I want to test the overriding behavior of groovy. I can override the method setupRoot() but not the property testVar, why is that?
Tested on: https://groovyconsole.appspot.com/script/5146436232544256
abstract class JobParams {
int root
def testVar=1
def setupRoot () {
println("The root");
}
def printTestVar () {
println("The testVar:" + testVar);
}
}
class GradleJobParams extends JobParams {
}
def gjp = [
testVar:3,
setupRoot:{
println("Override root");
}
] as GradleJobParams;
println("Starting");
gjp.printTestVar();
gjp.setupRoot();
The result is:
Starting
The testVar:1
Override root
Java (and thus Groovy) does not support overriding fields from the parent class with subclassing. Instead, it uses a mechanism called hiding fields:
Hiding Fields
Within a class, a field that has the same name as a field in the superclass hides the superclass's field, even if their types are different. Within the subclass, the field in the superclass cannot be referenced by its simple name. Instead, the field must be accessed through super, which is covered in the next section. Generally speaking, we don't recommend hiding fields as it makes code difficult to read.
Source: https://docs.oracle.com/javase/tutorial/java/IandI/hidevariables.html
It can be simply illustrated with the following example in Java:
final class SubclassHiddingFieldExample {
static abstract class A {
int value = 10;
void printValue1() {
System.out.println(value);
}
void printValue2() {
System.out.println(this.value);
}
void printValue3() {
System.out.println(((B)this).value);
}
}
static class B extends A {
int value = 12;
}
public static void main(String[] args) {
final B b = new B();
b.printValue1();
b.printValue2();
b.printValue3();
}
}
Output:
10
10
12
As you can see, only printValue3 prints out 3, because it cast this explicitly to B class.
Now, if you look at the decompiled bytecode of your JobParams class, you can see that the printTestVar method code is an equivalent of the following Java code:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
import groovy.lang.GroovyObject;
import groovy.lang.MetaClass;
import org.codehaus.groovy.runtime.callsite.CallSite;
public abstract class JobParams implements GroovyObject {
private int root;
private Object testVar;
public JobParams() {
CallSite[] var1 = $getCallSiteArray();
byte var2 = 1;
this.testVar = Integer.valueOf(var2);
MetaClass var3 = this.$getStaticMetaClass();
this.metaClass = var3;
}
public Object setupRoot() {
CallSite[] var1 = $getCallSiteArray();
return var1[0].callCurrent(this, "The root");
}
public Object printTestVar() {
CallSite[] var1 = $getCallSiteArray();
return var1[1].callCurrent(this, var1[2].call("The testVar:", this.testVar));
}
public MetaClass getMetaClass() {
MetaClass var10000 = this.metaClass;
if (var10000 != null) {
return var10000;
} else {
this.metaClass = this.$getStaticMetaClass();
return this.metaClass;
}
}
public void setMetaClass(MetaClass var1) {
this.metaClass = var1;
}
public Object invokeMethod(String var1, Object var2) {
return this.getMetaClass().invokeMethod(this, var1, var2);
}
public Object getProperty(String var1) {
return this.getMetaClass().getProperty(this, var1);
}
public void setProperty(String var1, Object var2) {
this.getMetaClass().setProperty(this, var1, var2);
}
public int getRoot() {
return this.root;
}
public void setRoot(int var1) {
this.root = var1;
}
public Object getTestVar() {
return this.testVar;
}
public void setTestVar(Object var1) {
this.testVar = var1;
}
}
You can see that the line that prints out the value of the testVar field is represented by:
return var1[1].callCurrent(this, var1[2].call("The testVar:", this.testVar));
It means that no matter what value of testVar your subclass defines, the printTestVar method uses testVar field defined in the JobParams class. Period.
Using Groovy auto getter methods
There is one way you to implement the expected behavior. Every class field in Groovy has a getter method associated with that field compiled by Groovy for you. It means that you can access testVar by calling the getTestVar() method generated by the Groovy compiler. You can use it to override the value returned by a getter method for any field from the subclass. Consider the following example:
abstract class JobParams {
int root
def testVar=1
def setupRoot () {
println("The root");
}
def printTestVar () {
println("The testVar:" + getTestVar()); // <-- using a getTestVar() method instead a testVar field
}
}
class GradleJobParams extends JobParams {
}
def gjp = [
getTestVar: 3, // <-- stubbing getTestVar() method to return a different value
setupRoot:{
println("Override root");
}
] as GradleJobParams;
println("Starting");
gjp.printTestVar();
gjp.setupRoot();
Output:
Starting
The testVar:3
Override root

How to properly call GroovyScriptEngine?

I'm testing Groovy but I can't figure out how to properly call GroovyScriptEngine. It keeps producing an error below.
org.codehaus.groovy.runtime.metaclass.MissingMethodExceptionNoStack
Song.Groovy
class Song {
def args;
{
println "Song has been called." + args;
}
String getArtist(){
return "sdfsdf";
}
public String toString(){
return "Hey!";
}
}
Java Main ->
String[] paths = { "C:\\Users\\User\\workspace\\GroovyTest\\src\\groovy" };
GroovyScriptEngine gse = new GroovyScriptEngine(paths);
Binding binding = new Binding();
Object s = "Default...";
binding.setVariable("args", s);
gse.run("Song.groovy", binding);
the args variable also produce null..
What to do ?
You are loading a class!
If you want to test your class, try something like this in the end of your Song.groovy:
// Instantiate an object of your class and use some methods!
def song = new Song()
println song.getArtist();
When you run
gse.run("Song.groovy", binding);
You are basically loading your class, but you are not doing anything with it.
See this example here
(Posted on behalf of the OP):
Working code:
Test1.java
import groovy.lang.Binding;
import groovy.util.GroovyScriptEngine;
public class Test1 {
public static void main(String[] args) throws Exception {
String[] paths = { "C:\\Users\\User\\workspace\\GroovyTest\\src\\groovy" };
GroovyScriptEngine gse = new GroovyScriptEngine(paths);
Binding binding = new Binding();
binding.setVariable("args", "Test Data");
String result = (String) gse.run("File1.groovy", binding);
System.out.println("Groovy Result: " + result);
}
}
File1.groovy
package groovy;
class Greeter {
String sayHello(String data) {
def greet = data;
return greet
}
}
static void main(String[] args) {
def greeter = new Greeter()
return greeter.sayHello(args);
}

How do I get multiple MockFor working in Groovy?

I am trying to get multiple mocks working in groovy. The only way I have managed to get this working is to create my own kind of mock - adding a meta method.
I have tried using nested use statements and also tried one use and one proxy with verify, neither of which worked. Both of these returned a failure - "junit.framework.AssertionFailedError: No more calls to 'pop' expected at this point. End of demands."
import groovy.mock.interceptor.MockFor
import org.junit.Test
class MockTest {
// results in No more calls to 'pop' expected at this point. End of demands.
#Test
public void testMock() {
MockFor pupilMock = new MockFor(Pupil)
MockFor bubbleMock = new MockFor(SomeService)
GroovyObject bubbleProxy = bubbleMock.proxyInstance()
pupilMock.demand.blowBubble { String colour ->
return bubbleProxy
}
bubbleMock.demand.pop {}
pupilMock.use {
bubbleMock.use {
Teacher teacher = new Teacher()
teacher.lesson("red")
}
}
}
// results in No more calls to 'pop' expected at this point. End of demands.
#Test
public void testProxy() {
MockFor pupilMock = new MockFor(Pupil)
MockFor bubbleMock = new MockFor(SomeService)
GroovyObject bubbleProxy = bubbleMock.proxyInstance()
pupilMock.demand.blowBubble { String colour ->
return bubbleProxy
}
bubbleMock.demand.pop {}
pupilMock.use {
Teacher teacher = new Teacher()
teacher.lesson("red")
}
bubbleMock.verify(bubbleProxy)
}
// only using a single mock so works
#Test
public void testMetaclass() {
MockFor pupilMock = new MockFor(Pupil)
SomeService.metaClass.pop = { println "pop was called" }
SomeService metaBubble = new SomeService("red")
pupilMock.demand.blowBubble { String colour ->
return metaBubble
}
pupilMock.use {
Teacher teacher = new Teacher()
teacher.lesson("red")
}
}
}
class Teacher {
public void lesson(String colour) {
Pupil pupil = new Pupil()
SomeService bubble = pupil.blowBubble(colour)
bubble.pop()
}
}
class Pupil {
SomeService blowBubble(String colour) {
SomeService child = new SomeService(colour)
return child
}
}
class SomeService {
String colour
SomeService(String colour) {
this.colour = colour
}
void pop() {
println "popped ${colour}"
}
}
EDIT: Re comment about mocking something constructed and returned from a method, this is how I do it...
#Test
public void testMockReturned() {
MockFor bubbleMock = new MockFor(SomeService)
bubbleMock.demand.pop {}
bubbleMock.use {
Pupil pupil = new Pupil()
SomeService service = pupil.blowBubble("red")
service.pop()
}
}
In this case, Pupil should be a stub since you're only using it to inject bubbleProxy to you can perform verification against it. Like this,
import groovy.mock.interceptor.*
import org.junit.Test
class MockTest {
#Test
public void testMock() {
StubFor pupilMock = new StubFor(Pupil)
MockFor bubbleMock = new MockFor(SomeService)
GroovyObject bubbleProxy = bubbleMock.proxyInstance()
pupilMock.demand.blowBubble { String colour ->
return bubbleProxy
}
bubbleMock.demand.pop {}
bubbleMock.use {
Teacher teacher = new Teacher()
teacher.lesson("red")
}
}
}
Also, I believe the demands are copied onto the proxy when proxyInstance() is called, so you need to have your demands configured before instantiating the proxy.
However, I don't think there's a problem with multiple mocks, I think you just can't mix instance and class mocks (which you are doing with SomeService). The smallest example I could think of that demonstrates this was
import groovy.mock.interceptor.MockFor
// this works
missyMock = new MockFor(Missy)
missyMock.demand.saySomethingNice {}
missy = missyMock.proxyInstance()
missy.saySomethingNice()
missyMock.verify(missy)
// as does this
missyMock = new MockFor(Missy)
missyMock.demand.saySomethingNice {}
missyMock.use {
new Missy().saySomethingNice()
}
// this don't
missyMock = new MockFor(Missy)
missyMock.demand.saySomethingNice {}
missy = missyMock.proxyInstance()
missyMock.use { // fails here in use()'s built-in verify()
missy.saySomethingNice()
}
missyMock.verify(missy)
class Missy {
void saySomethingNice() {}
}
To demonstrate that the multiple mocks with nested use closures works, look at this contrived example
import groovy.mock.interceptor.MockFor
import org.junit.Test
class MockTest {
#Test
public void testMock() {
MockFor lessonMock = new MockFor(Lesson)
MockFor pupilMock = new MockFor(Pupil)
lessonMock.demand.getLessonPlan {}
pupilMock.demand.getName {}
pupilMock.use {
lessonMock.use {
Teacher teacher = new Teacher()
Pupil pupil = new Pupil()
Lesson lesson = new Lesson()
teacher.teach(pupil, lesson)
}
}
}
}
class Teacher {
void teach(Pupil pupil, Lesson lesson) {
println "Taught ${pupil.getName()} $lesson by ${lesson.getLessonPlan()}"
}
}
class Pupil {
String name
}
class Lesson {
LessonPlan lessonPlan
static class LessonPlan {}
}

Groovy Inner Classes wont work with Apache Wicket

Im trying to write simple things with Apache Wicket (6.15.0) and Groovy (2.2.2 or 2.3.1). And Im having trouble with inner classes.
class CreatePaymentPanel extends Panel {
public CreatePaymentPanel(String id) {
super(id)
add(new PaymentSelectFragment('currentPanel').setOutputMarkupId(true))
}
public class PaymentSelectFragment extends Fragment {
public PaymentSelectFragment(String id) {
super(id, 'selectFragment', CreatePaymentPanel.this) // problem here
add(new AjaxLink('cardButton') {
#Override
void onClick(AjaxRequestTarget target) {
... CreatePaymentPanel.this // not accessible here
}
})
add(new AjaxLink('terminalButton') {
#Override
void onClick(AjaxRequestTarget target) {
... CreatePaymentPanel.this // not accessible here
}
});
}
} // end of PaymentSelectFragment class
} // end of CreatePaymentPanel class
Groovy tries to find a property "this" in CreatePaymentPanel class.. How to workaround this? It is a valid java code, but not groovy.
However,
Test.groovy:
class Test {
static void main(String[] args) {
def a = new A()
}
static class A {
A() {
def c = new C()
}
public void sayA() { println 'saying A' }
class B {
public B(A instance) {
A.this.sayA()
instance.sayA()
}
}
/**
* The problem occurs here
*/
class C extends B {
public C() {
super(A.this) // groovy tries to find property "this" in A class
sayA()
}
}
}
}
Above code wont work, the same error occurs, like in Wicket's case.
And TestJava.java, the same and working:
public class TestJava {
public static void main(String[] args) {
A a = new A();
}
static class A {
A() {
C c = new C();
}
public void sayA() {
System.out.println("saying A");
}
class B {
public B(A instance) {
instance.sayA();
}
}
/**
* This works fine
*/
class C extends B {
public C() {
super(A.this);
sayA();
}
}
}
}
What I am missing?
You can't refer to a CreatePaymentPanel.this inside of PaymentSelectFragment because there is no instance of CreatePamentPanel that would be accessible there. What would you expect that to evaluate to if it were allowed?

Resources