Skip to content

Instantly share code, notes, and snippets.

@theaspect
Created December 12, 2020 04:08
Show Gist options
  • Save theaspect/fd5dcfcfef20e54a291b260db41a2a17 to your computer and use it in GitHub Desktop.
Save theaspect/fd5dcfcfef20e54a291b260db41a2a17 to your computer and use it in GitHub Desktop.
DSL
package dsl4
import javax.script.Bindings
import javax.script.ScriptContext
import javax.script.ScriptEngineManager
class MyClass {
fun doAfterDelay(delay: Long, callback: Runnable) {
println("Java: before thread ${Thread.currentThread().id}")
val thread = Thread {
println("Java: thread begin ${Thread.currentThread().id}")
Thread.sleep(delay)
callback.run()
println("Java: thread end ${Thread.currentThread().id}")
}
// thread.isDaemon = true
thread.start()
// thread.join()
println("Java: after thread ${Thread.currentThread().id}")
}
}
class MyAnotherClass {
fun sum(a: Int, b: Int): Int {
println("Java: function sum")
return a + b
}
}
fun main() {
val engine = ScriptEngineManager().getEngineByName("JavaScript")
val bindings: Bindings = engine.getBindings(ScriptContext.ENGINE_SCOPE)
bindings.put("polyglot.js.allowHostAccess", true)
bindings.put("polyglot.js.allowHostClassLookup", { true })
// Eval from string
val resultString = engine.eval(
"""
// JavaScript code inside java
var a = 10;
var b = 20;
// Result of the last line will be return value of the script
print("JS: " + (a + b));
print("JS: " + a + b);
"JS"
"""
)
println("Java: return from script $resultString")
engine.put("myJavaVariable", "Hello From Java")
engine.put("myAsync", MyClass())
// Eval from file in fs
// val resultFile = engine.eval(FileReader("myscript.js"))
// Eval from file in classpath/jar
val resultFile = engine.eval(
(object {})::class.java.getResourceAsStream("/myscript.js").bufferedReader()
)
println(resultFile)
}
package dsl3
import java.time.LocalDate
@DslMarker annotation class PersonDsl
data class Person(
val firstName: String? = null,
val lastName: String? = null,
val patronymic: String? = null,
val dateOfBirth: LocalDate? = null,
val gender: Gender? = null,
val addresses: List<Address>? = null
)
enum class Gender {
MALE, FEMALE, OTHER
}
data class Address(
val country: String? = null,
val region: String? = null,
val area: String? = null,
val city: String? = null,
val street: String? = null,
val house: String? = null,
val building: String? = null,
val room: String? = null
)
@PersonDsl
class AddressBuilder {
var country: String? = null
var region: String? = null
var area: String? = null
var city: String? = null
var street: String? = null
var house: String? = null
var building: String? = null
var room: String? = null
val countries = setOf("Russia")
fun country(country: String): AddressBuilder {
check(this.country == null) { "Country already declared" }
check(validateCountry(country)) { "Uknown country $country" }
this.country = country
return this
}
fun region(region: String): AddressBuilder {
check(this.region == null) { "Region already declared" }
check(this.country != null) { "Country not declared" }
check(validateRegion(region)) { "Unknown region $region" }
this.region = region
return this
}
fun area(area: String): AddressBuilder {
// TOOD checks
this.area = area
return this
}
fun city(city: String): AddressBuilder {
// TOOD checks
this.city = city
return this
}
fun street(street: String): AddressBuilder {
// TOOD checks
this.street = area
return this
}
fun house(house: String): AddressBuilder {
// TOOD checks
this.house = house
return this
}
fun building(building: String): AddressBuilder {
// TOOD checks
this.building = building
return this
}
fun room(room: String): AddressBuilder {
// TOOD checks
this.room = room
return this
}
private fun validateCountry(country: String): Boolean = country in countries
private fun validateRegion(region: String): Boolean = true
fun build() = Address(
country,
region,
area,
city,
street,
house,
building,
room
)
}
@PersonDsl
class PersonBuilder {
var firstName: String? = null
var lastName: String? = null
var patronymic: String? = null
var dateOfBirth: LocalDate? = null
var gender: Gender? = null
var addresses: MutableList<Address> = mutableListOf()
fun name(firstName: String, lastName: String): PersonBuilder {
this.firstName = firstName
this.lastName = lastName
return this
}
fun name(firstName: String, lastName: String, patronymic: String): PersonBuilder {
this.firstName = firstName
this.lastName = lastName
this.patronymic = patronymic
return this
}
fun dateOfBirth(year: Int, month: Int, day: Int): PersonBuilder {
this.dateOfBirth = LocalDate.of(year, month, day)
return this
}
fun gender(gender: Gender): PersonBuilder {
this.gender = gender
return this
}
fun address(address: Address): PersonBuilder {
this.addresses.add(address)
return this
}
fun build() = Person(firstName, lastName, patronymic, dateOfBirth, gender, addresses)
}
/**
* Lambda with receiver
*/
fun person(body: PersonBuilder.() -> Unit) = PersonBuilder().apply(body).build()
/**
* Add method to person builder
*/
fun PersonBuilder.address(body: AddressBuilder.() -> Unit) {
val ab = AddressBuilder()
ab.body()
addresses.add(ab.build())
}
fun main() {
// Create via DSL version
val db3 = listOf(
person {
name("Linnick", "Constantine")
dateOfBirth(1988, 8, 17)
gender(Gender.MALE)
address {
country("Russia")
region("Kemerovskaya oblast")
city("Kemerovo")
street("Bakinsky pereulok")
house("18b")
room("112")
}
},
person {
name("Vasilisa", "Pupkina", "Petrovna")
dateOfBirth(1996, 2, 29)
gender(Gender.FEMALE)
address {
// Parent lambda call forbidden
// gender(Gender.FEMALE)
// this@person.gender(Gender.FEMALE)
country("Russia")
region("Novosibirskaya oblast")
area("Bolotny rayon")
city("Demidovo")
street("Lenina")
house("1")
}
address {
country("Russia")
region("Kemerovskaya oblast")
city("Novokuznetsk")
street("Sovetskaya")
house("10")
building("2")
room("20")
}
}
)
// Pattern DSL
println(db3)
}
// JavaScript code inside java
var a = 10;
var b = 20;
function myJsFunction() {
print("JS: callback function")
}
print("JS: before Async");
myAsync.doAfterDelay(2000, function () {
print("JS: anonymous function")
});
print("JS: after Async");
// Result of the last line will be return value of the script
print("JS: " + myJavaVariable + ": " + (a + b));
var MyAnotherClassType = Java.type("dsl4.MyAnotherClass");
var another = new MyAnotherClassType();
print("JS: "+ another.sum(1, 2));
"JS: return value";
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment