Get a static final field in scala with a string reference - scala

Suppose I have a fully qualified reference string:
val location = "org.path.to.some.field"
val foo = getFieldFromString(location)
I want to get the same value as if I did:
import org.path.to.some.field
How do I do this? Does it make sense to use reflection?

I think this might be the way to do it:
Class.forName("org.path.to.some").getField("field").get(null)
One problem is that you do need to know the type of the field in order for this to return something other than AnyRef. The get(null) is because we don't need an instance to get the static field.

Related

How do I access an object field via its field name in string form?

I'm figuring out at compile-time the name of a specific field of an object that I want to access. Before I compile, I do not necessarily know which field that is going to be, so I just have that field name as a string. How can I leverage nim's metaprogramming to access that field on the object?
You can write a very simple macro that evaluates to a dot expression (aka object.yourFieldNameString).
Here an example of how that can look like:
import std/[macros]
macro getField*(obj: object, fieldName: static string): untyped =
nnkDotExpr.newTree(obj, ident(fieldName))
This will only work if you know the field at compiletime (aka when you have it as a static string)! Keep that in mind!

Pass a class name as string argument to create instance

Is there any possible way to pass a class name/path as String argument to call it in code in runtime?
Im working with some legacy code and i have no way to change it globally. Creating new integration to it suggest me to create new copy of class X, rename it, and pass new instance of Y i have created manually. My mind tells me to pass Y as some kind of argument and never copy X again.
I don't quite understand why you (think that) you need to do what you are trying to do (why copy class in the first place rather than just using it? why pass classname around instead of the class itself?), but, yeah, you can instantiate classes by (fully qualified) name using reflection.
First you get a handle to the class itself:
val clazz = Class.forName("foo.bar.X")
Then, if constructor does not need any arguments, you can just do
val instance = clazz.newInstance
If you need to pass arguments to constructor, it gets a bit more complicated.
val constructor = clazz.getConstructors().find { c =>
c.getParameters().map(_.getParameterizedType) == args.map(_.getClass)
}.getOrElse (throw new Exception("No suitable constructor found")
// or if you know for sure there will be only one constructor,
// could just do clazz.getConnstructors.headOption.getOrElse(...)
val instance = constructor.newInstance(args)
Note though, that the resulting instance is of type Object (AnyRef), so there isn't much you can actually do with it without casting to some interface type your class is known to implement.
Let me just say it again: it is very likely not the best way to achieve what you are actually trying to do. If you open another question and describe your actual problem (not the solution to it you are trying to implement), you might get more helpful answers.

Refer generic class by name

Consider the case that I want to deserialize a JSON string:
def deserialize[T](json)
I can provided class that I want to apply the function explicitly while writing code like
class Person(name: String)
deserialize[Person]("""{ "name": "Jennie" }""")
But, what if I need other class, I have to provide it in my code, compile again. I want my program more flexible, it can take a config file that contains name of which class I want to use. So, when ever require a new class, I just need to write the class definition, build it into another jar file, put it in classpath, then restart the program.
val config = ConfigLoader.load("config.txt")
val className = config.getString("class-to-deserialize")
deserialize[<from className to type>](json)
So, is it possible to do that in scala?
No. But because of type erasure, if you have a function def deserialize[T](json: String), its behavior can't depend on T in the first place and it doesn't matter what you pass as the type parameter. You may just need to add a cast at the end.
What is possible is to write such a function which also accepts an implicit ClassTag or TypeTag parameter, in which case you just need to create the parameter from class/type name, and that's entirely possible: just search for questions about this.

Why I need that field like that

case class AlertWindowDto(id: String)
protected val InitialWindowPeriodOneOnPeak = AlertWindowDto(ValidId)
protected val ValidId = "someSite"
I saw these there lines in different different classes. just I put together for understanding.
In general, If i am creating an dummy or some object of Class, then I give some value or null or empty string. What is the need of creating another field ValidId and assign some value and assign that field to final object.
is there any benefit, or anything help in test cases.
could you please help me.
Imagine this:
protected val InitialWindowPeriodOneOnPeak = AlertWindowDto("someSite")
Does it convey the information that "someSite" is a valid id for an alert window?
This is a trivial example, but the general idea is that sometimes breaking down expressions and assigning names to them is great for expressing meaning.
I would also add that the more this naming information is in the types, the better. For instance, here's another way of achieving the same result, without using a variable name.
case class ValidId(value: String) extends AnyVal
case class AlertWindowDto(id: ValidId)
protected val InitialWindowPeriodOneOnPeak = AlertWindowDto(ValidId("someSite"))
Same information, but the "valid id" information is now stored in the type system.

what is the input type of classOf

I am wondering what type do I put in place of XXX
def registerClass(cl:XXX) = kryo.register(classOf[cl])
EDIT: For why I want to do this.
I have to register many classes using the above code. I wanted to remove the duplication of calling kyro.register several times, hoping to write code like below:
Seq(com.mypackage.class1,com.mypackage.class2,com.mypackage.class3).foreach(registerClass)
Another question, can I pass String instead? and convert it somehow to a class in registerClass?
Seq("com.mypackage.class1","com.mypackage.class2").foreach(registerClass)
EDIT 2:
When I write com.mypackage.class1, it means any class defined in my source. So if I create a class
package com.mypackage.model
class Dummy(val ids:Seq[Int],val name:String)
I would provide com.mypackage.model.Dummy as input
So,
kryo.register(classOf[com.mypackage.model.Dummy])
Kryo is a Java Serialization library. The signature of the register class is
register(Class type)
You could do it like this:
def registerClass(cl:Class[_]) = kryo.register(cl)
And then call it like this:
registerClass(classOf[Int])
The type parameter to classOf needs to be known at compile time. Without knowing more about what you're trying to do, is there any reason you can't use:
def registerClass(cl:XXX) = kryo.register(cl.getClass)