I would like to expose a public API (a kind of Runnable) and let users implement it, and then execute that code against our servers (given the class name containing the code to run). Users provide a jar containing their implementation and should not have access to implementation details.
Below is a snippet illustrating the issue.
The public API:
package mypackage
trait MyTrait {
def run(i: Int) : Unit
}
A sample user's implementation:
package mypackage
object MyImpl extends MyTrait {
override def run(i : Int) : Unit = {
println(i)
}
}
The server-side code running the user's code:
package mypackage
import scala.reflect.runtime.{universe => ru}
object MyTest extends App {
val m = ru.runtimeMirror(getClass.getClassLoader)
val module = m.staticModule("mypackage.MyImpl")
val im = m.reflectModule(module)
val method = im.symbol.info.decl(ru.TermName("run")).asMethod
val objMirror = m.reflect(im.instance)
objMirror.reflectMethod(method)(42)
}
The above code works (printing "42"), but the deisgn seems ugly to me.
In addition it seems unsafe (class instead of object, object that does not exist or does not implement the correct interface).
What's the best way to achieve this ?
I am using Scala 2.11.8.
Thanks for your help
Related
Context: I want design a proto file containing a currency field which will be used in gRPC service response. I am trying to follow this tutorial
I get this error
Type mismatch.
Required:
GeneratedMessageV3.Builder<*>!
Found:String
It clearly says I must use GeneratedMessageV3.Builder but I don't know how do it.
Here is the proto
syntax = "proto3";
package com.mycomp.adapters.grpc.test;
import "google/api/annotations.proto";
import "google/type/money.proto";
service TestService {
rpc GetTest (GetTestRequest) returns (Test) {
}
}
message GetTestRequest{
string id_cliente = 1;
}
message Test {
string id_cliente = 1;
google.type.Money test_money = 2;
}
How I implemented the service and my issue to initialize a very simple com.google.type.Money variable.
import com.google.type.Money
...other imports
#Singleton
class TestEndpoint() : TestServiceGrpcKt.TestServiceCoroutineImplBase() {
override suspend fun getTest(request: GetTestRequest): Test {
val test = Test.newBuilder()
...
test.testMoney = Money("999.99") //*** certainly my mistake is here
return test.build()
}
In case it is relevant, here are the most important part of build.gradle
dependencies {
implementation("io.micronaut:micronaut-validation")
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:${kotlinVersion}")
implementation("org.jetbrains.kotlin:kotlin-reflect:${kotlinVersion}")
implementation("io.micronaut.kotlin:micronaut-kotlin-runtime")
implementation("io.micronaut:micronaut-runtime")
runtimeOnly("com.fasterxml.jackson.module:jackson-module-kotlin")
implementation("io.micronaut:micronaut-http-client")
implementation ("com.google.api.grpc:proto-google-common-protos:1.0.0")
}
I understand the only dependency I need in order to use import "google/api/annotations.proto" in proto file and import com.google.type.Money in Kotlin is
com.google.api.grpc:proto-google-common-protos:1.0.0
If I interpret the javadoc correctly, you cannot instantiate the Money class directly. Instead use something like:
test.testMoney = Money.newBuilder()
.setCurrencyCode("USD")
.setUnits(999)
.build();
What is kotlin equivalent of this java class?
public class StatefulActor extends AbstractActor<StatefulActor.State> implements Some
{
public static class State
{
String lastMessage;
}
}
I tried:
class HelloActor: AbstractActor<HelloActor.State>(), Hello
{
inner class State {
var lastMessage: String? = null
}
but results in Cloud.orbit.exception.UncheckedException: Don't know how to handle state
What is kotlin equivalent of this java class?
Your Kotlin and Java code differs in two ways, the relationship of the State to StatefulActor and the ability of State to allow subclassing.
For State what you want is a Nested class not an Inner class in Kotlin terms. The former corresponds to static modifier in Java whereas the latter is like an inner class without the static modifier.
So for equivalence with the Java code you gave, you should drop the inner keyword.
Cloud.orbit.exception.UncheckedException: Don't know how to handle state
As for your Orbit problem you can try the following. This will also explain why subclassing is an issue:
// compile and run with cloud.orbit:orbit-runtime:1.2.0
import cloud.orbit.actors.runtime.AbstractActor
import cloud.orbit.actors.Actor
import cloud.orbit.actors.Stage
import cloud.orbit.concurrent.Task
class HelloActor: AbstractActor<HelloActor.ActorState>(), Hello
{
override fun sayHello(greeting: String): Task<String> {
val lastMessage = state().lastMessage
state().lastMessage = greeting
return Task.fromValue(lastMessage)
}
class ActorState {
var lastMessage: String? = null
}
}
interface Hello : Actor {
fun sayHello(greeting: String): Task<String>
}
fun main(args : Array<String>) {
val stage = Stage.Builder().clusterName("orbit-helloworld-cluster").build()
stage.start().join()
stage.bind()
val helloActor = Actor.getReference(Hello::class.java, "0");
var response = helloActor
.sayHello("Welcome to orbit 1").join()
println(response) // should print null
response = helloActor
.sayHello("Welcome to orbit 2").join()
println(response) // should print "Welcome to orbit 1"
stage.stop().join()
}
Notice that the Actor's nested class is called ActorState and not State as in your question. When I named the Actor's state class State I got a similar error:
cloud.orbit.exception.UncheckedException: Don't know how to handle state: HelloActor$State...
Caused by: cloud.orbit.exception.UncheckedException: cloud.orbit.exception.UncheckedException: Don't know how to handle state: HelloActor$State
Caused by: cloud.orbit.exception.UncheckedException: Don't know how to handle state: HelloActor$State
Caused by: cloud.orbit.exception.UncheckedException: java.lang.ClassNotFoundException: HelloActor$ActorState
But when I used the nested class name HelloActor.ActorState instead it works.
This is because by default all classes in Kotlin are closed (i.e. final in Java terms).
By default, all classes in Kotlin are final, which corresponds to Effective Java, Item 17: Design and document for inheritance or else prohibit it.
While in orbit 1.2.0 the code (if you do not use the special name ActorState) tries to subclass your State class and then instantiate it. This will not work if you go with the closed Kotlin default extensibility.
If you wish to use your own name for the Actor's state class you must declare it as open. e.g.
class HelloActor: AbstractActor<HelloActor.State>(), Hello
{
override fun sayHello(greeting: String): Task<String> {
val lastMessage = state().lastMessage
state().lastMessage = greeting
return Task.fromValue(lastMessage)
}
open class State {
var lastMessage: String? = null
}
}
I am using hazelcast in my project and I want to unit test some function but i do not want it to connect to real hazelcast and perform test on it for that i created a custom mock class which simply uses scala map because in hazelcast maps also there
here is my code
trait UserRepository {
def getUserObj(id: String):Option[User]
def addToUserRepo(user: User)
}
class UserRepo extends UserRepository{
def getUserObj(id: String):Option[User] = {
val userMap = hcastClient.getMap[String, User]("UserMap")
val userObj = userMap.get(id)
Option(userObj)
}
def addToUserRepo(user: User) = {
val directUserMap: IMap[String, User] = hcastClient.getMap[String,User]("UserMap")
directUserMap.set(user.uuid, user)
}
and here i created a simple customized mocked version class where the functionality is same just; replaced it with scala map:
class UserRepoMock extends UserRepository {
val map:Map[String,User]=Map[String,User]()
def getUserMap:Map[String,User] = {
map
}
def getUserObj(id: String):User = {
val userMap = getUserMap
val userObj = userMap.get(id)
userObj
}
def addToUserRepo(user: User) = {
val userMap = getUserMap
userMap.put(user.uuid, user)
}
class UserUtil(userRepo:UserRepo) {
def addUser(user:User):Boolean={
try{
userRepo.addToUserRepo(user)
true
}
catch {
case e:Exception=>false
}
def getUser(id:String):User={
val user=userRepo.getUserObj(id)
user
}
Mow i want to unit test methods addUser and getUserof UserUtil class
by doing like this:
class UserUtilTest extends funSpec {
val userUtil=new UserUtil(new UserRepoMock)
userUtil.addUser //perform unit test on it
userUtil.getUser //perform unit test on it
// instead of doing this val userUtil=new UserUtil(new UserRepo)
}
but the compiler not allowing me to do that,there is something which i am missing, Please help me how can i achieve the desired functionality
This is the compiler error:
type mismatch; found : testhcastrepo.UserRepoMock required: com.repositories.UserRepo
Well: your utils class says:
class UserUtil(userRepo:UserRepo)
So it needs an instance of UserRepo.
But then your are passing an instance of UserRepoMock. A UserRepoMock is a UserRepository, as UserRepo is; but a UserRepoMock is not a UserRepo!
Probably it is as simple as changing the utils to
class UserUtil(userRepo:UserRepository)
to indicate that you don't want to specify a specific class. Instead you simply say: anything that has the trait will do!
Beyond that: the real answer might be: have a look at your naming habits. You see, those two names UserRepositor and UserRepo; they are pretty "close" to each other; and it is not at all clear, what the difference between the two is. If the names would be more distinct, like UserRepositoryTrait and HCastUserRepository you probably would not have made this mistake in the first place (not sure my suggestions are "good" names according to scala conventions; but they are just meant to give you an idea).
I am trying to write integration test for my scala application(with akka-http). I am running into a problem, for which I am not able to find a solution.
My Case classes are as below:
case class Employee(id:Long, name:String, departmentId:Long, createdDate:Timestamp) extends BaseEntity
case class EmployeeContainer(employee:Employee, department:Department) extends BaseEntity
I have a method like this
trait BaseTrait[E<:BaseEntity, C <: BaseEntity]{
def getById(id:Long): Future[List[C]] = {
//query from db and return result.
}
def save(obj:E) = {
//set the createDate field to the current timestamp
//insert into database
}
}
I can extend my class with BaseTrait and just override the getById() method. Rest of the layers are provided by our internal framework.
class MyDao extends BaseTrait[Employee, EmployeeContainer] {
override def getById(id:Long) = {
for {
val emp <- getFromDb(id)
val dept <- DeptDao.getFromDb(emp.departmentId)
val container = EmployeeContainer(emp,dept)
} yield(container)
}
}
So in the rest layer, I will be getting the response as the EmployeeContainer. The problem now I am facing is that, the modified date is automaticaally updated with the current timestamp. So, when I get back the result, the timestamp in the object I passed to save() method will be overwritten with the current time. When I write the test case, I need to have an object to compare to. But the timestamp of that object and the one I get abck will never be the same.
Is there anyway, in which I can replace all the occurrance of createDate with a known value of timestamp so that I can compare it in my testcase? The main problem is that I can not predict the structure of the container (it can have multiple case classes(nested or flat) with or without createDate fields).
I was able to replace the field using reflection if it comes in the main case class, but unable to do for nested structures.
You probably need to use some for of Inversion of Control. Your main problem is that you are calling the db directly: val emp <- getFromDb(id) and thus have no control on a test of the values that are received. Calling the DB on a unit test is also arguably a bad idea, since it expands the unit to the entire database layer. You want to test a small, self-contained unit.
A simple solution is to encapsulate your DB calls as an interface and pass an instance of that interface. For instance:
class MyDao extends BaseTrait[Employee, EmployeeContainer](val dbCall: Long => Employee) {
override def getById(id:Long) = {
for {
val emp <- dbCall(id)
val dept <- DeptDao.getFromDb(emp.departmentId)
val container = EmployeeContainer(emp,dept)
} yield(container)
}
}
Then you can simply use new MyDao(getFromDb) for normal code and val testDao = new MyDao(id => Employee(id, myFixedName, myFixedDeptID, myFixedTestDate)) from test code.
I don't know why but the class below doesn't work if instance variable text is private, but if I leave out private, it works.
Debugging the test in section "setField" I could see that the instance variable name should be "text" but it becomes "com$test$SimpleTest$$text"
package com.test
import org.testng.annotations.Test
import org.springframework.test.util.ReflectionTestUtils
class SimpleTest {
private var text = ""
#Test
def testValueOfX(): Unit = {
val simpleTest = new SimpleTest
ReflectionTestUtils.setField(simpleTest,"text", "abc")
println(
Option[String](null)
.map(v => v + " 123")
.getOrElse {
simpleTest.text + " 321"
})
}
}
I believe that the problem someway be the "getOrElse" because if I leave out too, it works.
Scala compiler has a right to compile your private field into an any working java code, as it doesn't affect interoperability (if you don't do any tricks). Spring's setField actually do such trick, as it makes your private field accessible (setAccessible(true) inside). Public fields are always compiling as is to give you appropriate interface from Java.
Use http://docs.scala-lang.org/overviews/reflection/environment-universes-mirrors.html to work with Scala reflection. Also this article may be helpful.
Here is explanation why scalac uses another name for private field.
P.S. The reason why removing .getOrElse(text) make it work is because you don't use text anywhere but inside this piece of code.
This class is only to show the problem, actually it is very different of real class. So I changed the strategy to receive an instance by #Autowired a method instead #Autowired a field.
package com.test
import org.testng.annotations.Test
import org.springframework.test.util.ReflectionTestUtils
class SimpleTest {
// item 1
private var text = ""
#Test
def testValueOfX(): Unit = {
val simpleTest = new SimpleTest
ReflectionTestUtils.invokeSetterMethod(simpleTest, "text", "abc")
println(
Option[String](null)
.map(v => v + " 123")
.getOrElse {
simpleTest.text + " 321"
})
}
// item 2
def setText(text: String): Unit = {
this.text = text
}
}
I'm not using #Autowired in this sample but in the real class I am. So if you need to get an instance follow instructions below.
Item 1 -> if I put on #Autowired it doesn't work because like said dk14 Scala compiler has a right to compile your private field into an any working java code. So, the compiler change the field's name when it compiles the class
Item 2 -> I put on #Autowired in the setter method, it works.