Skip to content

Instantly share code, notes, and snippets.

@k33g
Last active August 25, 2015 21:38
Show Gist options
  • Select an option

  • Save k33g/4783f8d03194230c8185 to your computer and use it in GitHub Desktop.

Select an option

Save k33g/4783f8d03194230c8185 to your computer and use it in GitHub Desktop.
module frankenstein
import gololang.Adapters
struct dynamicClass = {
className,
fields,
methods,
_ctClass
}
augment dynamicClass {
function field = |this, fieldName, fieldType| {
this: fields(): put(fieldName, fieldType)
return this
}
function implements = |this, methodName, typeReturn, arguments, method| {
this: methods(): put(methodName, [typeReturn, arguments, method])
return this
}
function toAdapter = |this| {
let resolveCtClass = |clazz| {
let pool = javassist.ClassPool.getDefault()
return pool: get(clazz: getName())
}
this: fields(): each(|fieldName, fieldType| {
let field = javassist.CtField(resolveCtClass(clazz= fieldType), fieldName, this: _ctClass())
field: setModifiers(javassist.Modifier.PUBLIC())
this: _ctClass(): addField(field)
})
this: methods(): each(|methodName, entry| {
let counter = Observable(0)
let params = entry: get(1)?: map(|type| {
counter: set(counter: get() + 1)
return type: getName() + " arg" + counter: get()
})?: join(", ") orIfNull ""
let method = javassist.CtNewMethod.make(
"public " + (entry: get(0)?: getName() orIfNull "void") + " " + methodName +"("+ params +") { return null ; }"
, this: _ctClass()
)
this: _ctClass(): addMethod(method)
})
let klass = this: _ctClass(): toClass()
let klassDef = Adapter(): extends(this: className())
this: methods(): each(|methodName, entry| {
klassDef: implements(methodName, entry: get(2))
})
return klassDef
}
}
function DynamicClass = |className| {
let pool = javassist.ClassPool.getDefault()
let ctClass = pool: makeClass(className)
let dynaKlass = dynamicClass(className, map[], map[], ctClass)
return dynaKlass
}
function main = |args| {
let Human = DynamicClass("org.k33g.Human")
: field("name", String.class)
: field("age", Integer.class)
: implements(
methodName= "hello",
typeReturn= null,
arguments= null,
method = |this| -> println("Hello " + this: name() + "!")
)
: implements(
methodName= "yo",
typeReturn= null,
arguments= null,
method = |this| -> println(">>> " + this: age() + "!")
)
: implements(
methodName= "toString",
typeReturn= String.class,
arguments= null,
method = |this| -> this: name() + " - " + this: age()
)
: implements(
methodName= "changeAge",
typeReturn= null,
arguments= [Integer.class],
method = |this, newAge| -> this: age(newAge)
)
: implements(
methodName= "say",
typeReturn= String.class,
arguments= [String.class, String.class],
method = |this, message, someBody| {
return "Hey " + someBody + "! I'am " + this: name() + ", " + message
}
)
: toAdapter()
let bob = Human: newInstance()
bob: name("Bob Morane"): age(42)
bob: hello()
bob: yo()
bob: changeAge(24)
println(bob: toString())
println(bob: say(message="I'm happy", someBody="Sam"))
#let objDef = Adapter(): extends("org.k33g.Human")
#let sam = objDef: newInstance()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment