hoping to use groovy to write a groovy.text.Template for Asciidoctor markup. So far :
//-----------------------------------
public class AsciidocTemplate implements groovy.text.Template
{
boolean includeHeaderFooter = true;
Asciidoctor asciidoctor = create();
org.asciidoctor.Options asciidoctorJOptions=["backend": "html","header_footer":includeHeaderFooter]
def payload="";
Map binding = [:]
public AsciidocTemplate()
{
} // end of constructor
public AsciidocTemplate(def payload)
{
this.payload = payload;
} // end of constructor
// use doctor to transform the template
public Writable process()
{
def output = asciidoctor.render(this.payload, asciidoctorJOptions);
Writer ou = output;
return ou;
} // end of make
Writable make()
{
return process(); //output as Writable;
} // end of make
// -----------------------------------
The render() returns a string, how do we convert that string into an object that implements the Writable interface, i just dont get it. Also can't see how to use/read/store the returned 'Writable' object either :-P
You can use the asWritable method on a Closure to get a Writable returned, ie:
Writable process()
{
def output = asciidoctor.render(this.payload, asciidoctorJOptions);
{ w -> w.println output }.asWritable()
}
Related
I have two simple interfaces called Processor and SeedPreProcessor and they are defined like:
Processor:
public interface Processor<I, O> {
Mono<O> process(I input);
}
SeedPreProcessor:
public interface SeedPreProcessor<D> extends Processor<D, D> {
/**
* Specify the location of this processor in the pipeline.
*
* #return the order
*/
Integer order();
String name();
}
and a PipeLine defined like:
public class PipeLine {
private final List<SeedPreProcessor<PreProcessorDocument>> allProcessors;
public PipeLine(List<SeedPreProcessor<PreProcessorDocument>> allProcessors) {
this.allProcessors = new ArrayList<>(allProcessors);
this.allProcessors.sort(comparingInt(SeedPreProcessor::order));
}
public Mono<PreProcessorDocument> execute(String url) {
log.info("Start processing URL = {}", url);
var initial = new PreProcessorDocument(url);
return Flux
.fromIterable(allProcessors)
.map(proc -> proc.process(initial).t) // my problem is here
}
}
I want to for a inital PreProcessorDocument to execute all the SeedPreProcessor in the
list allProcessors one by one.
How can I achieve this?
Simple foreach loop and flatMap operator will do the trick :
public Mono<PreProcessorDocument> execute(String url) {
var initial = new PreProcessorDocument(url);
Mono<PreProcessorDocument> m = Mono.just(initial);
for (SeedPreProcessor<PreProcessorDocument> p : allProcessors) {
m = m.flatMap(p::process);
}
return m;
}
In our codebase, we use a specific class map which stores the results for authorization requests including whether or not someone has the auth to get in.
Currently writing some unit tests (a thing I have little practice on) that contains this, a modified version of our code for you to look at:
public class TestResultMap extends HashMap<String, TestResult> {
private static final long serial = -1234567890L;
public boolean isAuthorized(String resource) {
TestResult result = get(resource);
if (result == null) {
throw new RunExcept("Authorization not calculated");
}
return result.isAuthorized();
}
}
When testing the isAuthorized() in the groovy file I had made, I've noticed that no matter how I have it arranged, I can not get it to instantiate TestResult result = get(resource) to be anything other than null. isAuthorized() calls upon an enum method in another class that contains the possibilities, but otherwise just returns a boolean.
That's tangential to the point, though. Is there an efficient way to mock this or force get(resource) to output something not null? Alternatively, can I directly set result to a particular value?
Thanks for any help. Incredibly new to this whole process and documentation has been tricky.
I am showing you
how to stub the result of TestResult.isAuthorized to always return true or false,
how to use a spy on a real TestResultMap instance in order to stub the result of get(_) with the rest of the class behaving normally (partial mocking),
how to test your class without using any mocks, because if the methods used in the test are not doing anything expensive, mocking might not be necessary at all. Or maybe you want to also have an integration test in addition to the unit test with mocked dependencies.
Classes under test:
package de.scrum_master.stackoverflow.q70149644;
public class TestResult {
private String result;
public TestResult(String result) {
this.result = result;
}
public boolean isAuthorized() {
return !result.toLowerCase().matches(".*(forbidden|blocked|unauthorized|denied).*");
}
#Override
public String toString() {
return "TestResult(result='" + result + "')";
}
}
package de.scrum_master.stackoverflow.q70149644;
import java.util.HashMap;
public class TestResultMap extends HashMap<String, TestResult> {
private static final long serial = -1234567890L;
public boolean isAuthorized(String resource) {
TestResult result = get(resource);
if (result == null) {
throw new RuntimeException("Authorization not calculated");
}
return result.isAuthorized();
}
}
Spock specification:
package de.scrum_master.stackoverflow.q70149644
import spock.lang.Specification
class TestResultMapTest extends Specification {
def "resource is authorized"() {
given:
TestResultMap map = new TestResultMap()
TestResult testResult = Stub() {
isAuthorized() >> true
}
map.put("resource", testResult)
expect:
map.isAuthorized("resource")
}
def "resource is unauthorized"() {
given:
TestResultMap map = new TestResultMap()
TestResult testResult = Stub() {
isAuthorized() >> false
}
map.put("resource", testResult)
expect:
!map.isAuthorized("resource")
}
def "resource not found"() {
given:
TestResultMap map = Spy() {
get(_) >> null
}
when:
map.isAuthorized("resource")
then:
def rte = thrown RuntimeException
rte.message == "Authorization not calculated"
}
def "test without mocks"() {
given:
TestResultMap map = new TestResultMap()
map.put("OK", new TestResult("Hello world"))
map.put("not OK", new TestResult("Access denied"))
expect:
map.isAuthorized("OK")
!map.isAuthorized("not OK")
when:
map.isAuthorized("foo")
then:
def rte = thrown RuntimeException
rte.message == "Authorization not calculated"
}
}
I'm wondering how does lambdas external references work. Let me explain:
Suppose i have this supplier implementation and this model class :
public class TestSupplierImpl implements Supplier<Boolean> {
public Predicate<Integer> predicate;
public TestSupplierModel model;
public TestSupplierImpl() {
this.predicate = i -> model.something.equals(i);
}
#Override
public Boolean get() {
return predicate.test(3);
}
}
class TestSupplierModel {
public Integer something;
public TestSupplierModel(Integer something) {
this.something = something;
}
}
Then i execute the following code:
TestSupplierImpl test = new TestSupplierImpl(); // line 1
test.model = new TestSupplierModel(3); // line 2
Boolean resultado = test.get(); // line 3
Line 1: creating a new instance of TestSupplierImpl. This new instance's predicate has a null reference of model. This makes sense because at the moment of creation of the predicate, model reference is null.
Line 2: assign to variable model a new instance of TestSupplierModel.
Line 3: test.predicate now has model reference with the new assigned value. Why is this ?
I don't understand why ,when I changed model reference, the predicate updates its model reference to the new one. How is that ?
Thanks in advance !
Does it make sense if you rewrote your TestSupplierImpl() constructor as follows?
public Predicate<Integer> predicate;
public TestSupplierModel model;
public TestSupplierImpl() {
// same effect as this.predicate = i -> model.something.equals(i);
this.predicate = new Predicate<Integer>() {
public boolean test(Integer i) {
return model.something.equals(i);
}
};
}
#Override
public Boolean get() {
return predicate.test(3);
}
So here is the order of things.
// the constructor is run and the test method defined BUT NOT executed.
TestSupplierImpl test = new TestSupplierImpl(); // line 1
// Now you define model
test.model = new TestSupplierModel(3); // line 2
// Then you execute the predictate via get()
Boolean resultado = test.get(); // line 3
model and something aren't required until you issue the get() method. By that time they are already defined.
I have an object in use throughout my codebase, UnsecureObject. This object is auto-generated with no getters/setters, and all member fields are public. So editing is done by doing something like the following:
unsecureObjInstance.firstName = "Jane";
This is not desirable for numerous reasons that I probably don't have to explain here. But using this generated class is required for some other technical details with our messaging pipeline that I won't go into.
I have a desire is to leverage a mapping utility written by someone else on my team to convert this UnsecureObject to a pojo that I am writing.
An example of the mapper in action (with two normal classes w/ getters/setters) would be something like:
new MapperBuilder<>(PojoOne.class, PojoTwo.class)
.from(PojoOne::getName).to(PojoTwo::getFirstName)
.build();
This will map the PojoOne#name field to the PojoTwo#firstName field.
Is there a way to translate this to input my UnsecureObject here? I have tried something like the following:
new MapperBuilder<>(UnsecureObject.class, SecureObject.class)
.from(u -> u.firstName).to(SecureObject::getFirstName)
.build();
But get an error here, something along the lines of 'u -> u.firstName' could not be invoked.
So the question is:
Is there a way to essentially "construct" a getter on the fly using these public members? So in the .from() method, I can construct the call to look like a standard method that will yield my u.firstName?
Thanks for the help!
EDIT:
this is approx what the MapperBuilder class looks like (attempted to edit a bit to take away project specific wrappers/simplify)
/**
* This class is used to convert between POJO getter method references to the corresponding field names.
* #param <B> type
*/
public interface PojoProxy<B> {
/**
* Invokes the given getter method and returns information about the invocation.
* #param getter the getter to invoke
* #return information about the method invoked
*/
<T> GetterInvocation<T> invokeGetter(Function<B, T> getter);
}
/**
* Stores information about a method invocation.
* #param <T> method return type
*/
public interface GetterInvocation<T> {
public Class<T> getReturnType();
public String getFieldName();
}
/**
* A builder class to create {#link Mapper} instances.
* #param <FROM> source type
* #param <TO> target type
*/
public class MapperBuilder<FROM, TO> {
private final Class<FROM> _fromClass;
private final Class<TO> _toClass;
private final PojoProxy<FROM> _fromProxy;
private final PojoProxy<TO> _toProxy;
public MapperBuilder(Class<FROM> fromClass, Class<TO> toClass) {
_fromClass = fromClass;
_toClass = toClass;
//We will pretend there is an impl that provides the proxy.
//Proxies wrap the from and to classes in order to get reflection information about their getter calls.
_fromProxy = PojoProxy.of(fromClass);
_toProxy = PojoProxy.of(toClass);
}
public <FROM_VALUE> ToFieldBuilder<FROM_VALUE> from(Function<FROM, FROM_VALUE> getter) {
GetterInvocation<FROM_VALUE> methodInvocation = _fromProxy.invokeGetter(getter);
return new ToFieldBuilder<>(methodInvocation.getFieldName(), methodInvocation.getReturnType());
}
public class ToFieldBuilder<FROM_VALUE> {
private final String _fromFieldPath;
private final Class<FROM_VALUE> _fromClass;
public ToFieldBuilder(String fromFieldPath, Class<FROM_VALUE> fromClass) {
_fromFieldPath = fromFieldPath;
_fromClass = fromClass;
}
public <TO_VALUE> FromFieldBuilder<FROM_VALUE, TO_VALUE> to(Function<TO, TO_VALUE> getter) {
//similar to above, but now using a FromFieldBuilder.
}
}
public class FromFieldBuilder<FROM_VALUE, TO_VALUE> {
//impl..
}
}
I dont see MapperBuilder.from() method details, you can try this implementation of MapperBuilder.java Function (getter) -> (BiConsumer) setter
public class MapperBuilder<S, D> {
private final S src;
private final D dest;
public MapperBuilder(S src, Class<D> dest) {
this.src = src;
try {
this.dest = dest.newInstance();
} catch (Exception e) {
throw new RuntimeException("Required default constructor for: " + dest);
}
}
//getter - function to get value from source instance
//setter - biConsumer to set value to destination instance
//example - map(SrcClass::getSrcValue, DestClass::setDestValue)
public <V> MapperBuilder<S, D> map(Function<S, V> getter, BiConsumer<D, V> setter) {
setter.accept(dest, getter.apply(src));
return this;
}
public D build() {
return dest;
}
}
SrcClass.java some source class:
public class SrcClass {
private String srcValue;
public String getSrcValue() {
return srcValue;
}
public void setSrcValue(String srcValue) {
this.srcValue = srcValue;
}
}
DestClass.java some destination class:
package com.example.demo;
public class DestClass {
private String destValue;
public String getDestValue() {
return destValue;
}
public void setDestValue(String destValue) {
this.destValue = destValue;
}
}
DemoApplication.java demo:
public class DemoApplication {
public static void main(String[] args) {
SrcClass src = new SrcClass();
src.setSrcValue("someValue");
DestClass dest = new MapperBuilder<>(src, DestClass.class)
.map(SrcClass::getSrcValue, DestClass::setDestValue)
// map another fields
.build();
// for your UnsecureObject case
UnsecureObject unsecureObject = new MapperBuilder<>(src, UnsecureObject.class)
.map(SrcClass::getSrcValue,
(unsecure, srcValue) -> unsecure.unsecureValue = srcValue)
.build();
}
}
I have a class with,
a field called something,
a setter method called setSomething, and,
a method called onChange which should be called every time something is changed.
I want to be able to freely add more fields and have the same behavior for all of them.
I don't want to manually call onChange because,
A lot of boilerplate,
Code will be written in Kotlin so I don't want to write setter functions at all.
The ideal solution I've been able to think of has been to somehow inject the onChange call right before the return for each setter method in compile time.
I've looked at annotation processing, but apparently classes aren't actually compiled at that stage, so I'd have to generate the entire class all over again? I don't exactly understand this.
The other option seems to be writing a gradle plugin that will find the relevant class(es) and modify their bytecode.
I've actually started work on this as a pure Java project (gradle plugin is semi-done) and have been able to find the classes and inject the method call. Can't seem to successfully write the results to a class file though.
Here's what I have (using BCEL):
public class StateStoreInjector {
public static void main(String[] args) {
// Find all classes that extends StateStore
Reflections reflections = new Reflections("tr.xip.statestore");
Set<Class<? extends StateStore>> classes = reflections.getSubTypesOf(StateStore.class);
for (Class c : classes) {
try {
JavaClass clazz = Repository.lookupClass(c.getName());
JavaClass superClazz = Repository.lookupClass(StateStore.class.getName());
if (Repository.instanceOf(clazz, superClazz)) {
injectInClass(clazz, superClazz);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
private static void injectInClass(JavaClass clazz, JavaClass superClazz) {
ClassGen classGen = new ClassGen(clazz);
ConstantPoolGen cp = classGen.getConstantPool();
// Find the onChange method
Method onChangeMethod = null;
for (Method m : superClazz.getMethods()) {
if (m.getName().equals("onChange")) {
onChangeMethod = m;
}
}
if (onChangeMethod == null) {
throw new RuntimeException("onChange method not found");
}
ClassGen superClassGen = new ClassGen(superClazz);
ConstantPoolGen superCp = superClassGen.getConstantPool();
// Add onChange method ref to the class ConstantPool
MethodGen onChangeMethodGen = new MethodGen(onChangeMethod, superClassGen.getClassName(), superCp);
cp.addMethodref(onChangeMethodGen);
// Loop through all methods to inject method invocations if applicable
for (Method m : clazz.getMethods()) {
// Skip methods with names shorter than 3 chars - we're looking for setters and setters would be min 4 chars
if (m.getName().length() < 3) continue;
// Check if the method actually starts with the keyword "set"
boolean isSetMethod = m.getName().substring(0, 3).toUpperCase().equals("SET");
// Get method name without the "set" keyword
String methodName = m.getName().substring(3, m.getName().length());
// Check that we actually have a field set by this setter - that this setter is "valid"
boolean fieldWithSameNameExists = false;
for (Field f : clazz.getFields()) {
if (f.getName().toUpperCase().equals(methodName.toUpperCase())) {
fieldWithSameNameExists = true;
break;
}
}
// Proceed with injection if criteria match
Method newMethod = null;
if (isSetMethod && fieldWithSameNameExists) {
newMethod = injectInMethod(m, onChangeMethodGen, classGen, cp);
}
// Injection returned. Do we have a new/modified method? Yes? Update and write class.
if (newMethod != null) {
classGen.removeMethod(m);
classGen.addMethod(newMethod);
classGen.update();
try {
String packageName = clazz.getPackageName().replace(".", "/");
String className = clazz.getClassName();
className = className.substring(className.lastIndexOf(".") + 1, className.length());
clazz.dump(packageName + "/" + className + "Edited.class");
}
catch (IOException e) {
e.printStackTrace();
}
}
}
}
private static Method injectInMethod(Method m, MethodGen onChangeMethodGen, ClassGen cg, ConstantPoolGen cp) {
MethodGen methodGen = new MethodGen(m, cg.getClassName(), cp);
InstructionList il = methodGen.getInstructionList();
println(il.toString() + "pre insert ^");
// Find the "return" instruction
Instruction returnInstruction = null;
for (Instruction i : il.getInstructions()) {
if (i.getOpcode() == 177) returnInstruction = i;
}
// If found, insert onChange invocation instruction before the return instruction
if (returnInstruction != null) {
int index = cp.lookupMethodref(onChangeMethodGen); // Find the index of the onChange method in the CP
il.insert(returnInstruction, new INVOKEVIRTUAL(index)); // Insert the new instruction
println(il.toString() + "post insert ^");
il.setPositions(); // Fix positions
println(il.toString() + "post set pos ^");
il.update();
methodGen.update();
return methodGen.getMethod();
}
return null;
}
private static void println(String message) {
System.out.println(message);
}
}
Input Java class:
public class DummyStateStore extends StateStore {
private int id = 4321;
public void setId(int id) {
this.id = id;
}
public int getId() {
return id;
}
}
Parent Store class:
public class StateStore {
public void onChange() {
// notifies all subscribers
}
}
Output (decompiled) class file:
public class DummyStateStore extends StateStore {
private int id = 4321;
public DummyStateStore() {
}
public void setId(int id) {
this.id = id;
}
public int getId() {
return this.id;
}
}
Log output:
0: aload_0[42](1)
1: iload_1[27](1)
2: putfield[181](3) 2
5: return[177](1)
pre insert ^
0: aload_0[42](1)
1: iload_1[27](1)
2: putfield[181](3) 2
-1: invokevirtual[182](3) 26
5: return[177](1)
post insert ^
0: aload_0[42](1)
1: iload_1[27](1)
2: putfield[181](3) 2
5: invokevirtual[182](3) 26
8: return[177](1)
post set pos ^
(I checked the index 26 by debugging the code and it is the correct index in the CP)
Now, the questions are:
Why can't the invocation be seen in the decompiled code but it seems to be added to the instructions list? What am I missing?
Where would I be exporting the modified class files in an android build for them to be included in the final apk?
You're trying to use reflection, but there should be no need to do so with Kotlin as you can create higher order functions (functions that take functions as inputs).
You could do something like:
class ChangeableType<T>(private var value: T, private val onChange: () -> Unit) {
fun set(value: T) {
this.value = value
this.onChange.invoke()
}
}
class MyRandomClass() {
val something = ChangeableType(0, { System.print("Something new value: $value") })
val anotherThing = ChangeableType("String", { System.print("Another thing new value: $value") })
}
class ConsumingClass {
val myRandomClass = MyRandomClass()
fun update() {
myRandomClass.apply {
something.set(1)
anotherThing.set("Hello World")
}
}
}