Access a field from an unknown Groovy class in Java - java

I have a Groovy class:
class SomeGroovyThing {
String name
}
And in Java I receive a reference to an instance of this class as an Object:
Object o = project.getExtensions().getByName("groovyThing")
I can't cast the Object because I don't have access to the Groovy class in Java (for unrelated reasons). How can I retrieve the value of the name property (i.e. I want to do o.name but obviously that doesn't work).
I am wanting to do some sort of Reflection, but the fact that my Object is a Groovy class is throwing a wrench in things.

You can do this using Reflection.
You can get it:
String name=(String)o.getClass().getField("name").get(o);
Or set it:
o.getClass().getField("name").set(o,name);
If name is private, you can set or get it using the setter/getter methods(getMethod() in Class) or use setAccessible(true) on the Field.

Related

Kotlin interface in not accessible from Java class

I have created an interface on kotlin.
interface IDataManager{
val dataType: String?
}
Now I am trying to get its variable in my java class, like following.
public static DataWrapper getInstance(IDataManager iDataManager) {
dataType= iDataManager.dataType;
return instance;
}
But I am getting error: cannot find symbol iDataManager.dataType
Please call getter function to get a value of the variable:
dataType = iDataManager.getDataType();
If we use properties on Kotlin side we should use getters and setters to access those properties on Java side.
edit - as Alexey points out in the comments, this doesn't work for interfaces, since the property needs a backing field and properties in interfaces can't have those. It's still useful to know, but it doesn't apply to the OP's question
As well as what Sergey said, you can add the #JvmField annotation on things if you want to expose them as a field instead of generating the getters and setters
interface IDataManager{
#JvmField val dataType: String?
}
#JvmStatic is another useful one for Java interop, you can put it on properties and functions in companion objects, so instead of this
Utils.Companion.coolUtility()
you can do this (like you're used to)
Utils.coolUtility()

Android / Java - get TYPE of a hidden class via Reflection

I am trying to use the hidden package manager method installPackage via reflections.
My major problem is that one of its parameters is another hidden class android.content.pm.IPackageInstallObserver. How can I get the TYPE of that class (not an instance of it)?
val cPackageManager = Class.forName("android.content.pm.PackageManager")
val cPackageInstallObserver = Class.forName("android.content.pm.IPackageInstallObserver")
// here I need the IPackageInstallObserver type as a parameter type to look up the method
val installPackageMethod = cPackageManager.getMethod("installPackage", Uri::class.java, cPackageInstallObserver::class.java, Integer.TYPE, String::class.java)
In the way above, cPackageInstallObserver::class.java resolves to only a Class but not the actual type I need.
Does anybody have a solution for that?
You just did a simple mistake here
Uri::class.java, cPackageInstallObserver, Integer.TYPE, String::class.java)
As cPackageInstallObserver is already a class you need, as Class.forName returns a Class type, but you used cPackageInstallObserver::class.java so it is just same as doing String.class.getClass() in java, so just Class.class.

Accessing a Scala object from Java code

I am trying to use a Scala class that has a default argument:
object SimpleCredStashClient {
def apply(kms: AWSKMSClient, dynamo: AmazonDynamoDBClient, aes: AESEncryption = DefaultAESEncryption)
...
}
When I try to instantiate an instance of this class from Java, I get the error:
Error:(489, 43) java: cannot find symbol
symbol: method SimpleCredStashClient(com.amazonaws.services.kms.AWSKMSClient,com.amazonaws.services.dynamodbv2.AmazonDynamoDBClient)
location: class com.engineersgate.build.util.CredentialsUtil
DefaultAESEncryption is a Scala object. How do I access the Scala object in Java?
Default arguments become synthetic methods of the form <meth>$default$<idx>(). Further, instances of an object A may be found at A$.MODULE$ (if A is a top-level object), or at outer.A() (if A is defined as something like class O { object A }).Therefore, there are two ways to do this:
Direct usage of object:
SimpleCredStashClient.apply(
kms,
dynamo,
DefaultAESEncryption$.MODULE$
);
Default argument:
SimpleCredStashClient.apply(
kms,
dynamo,
SimpleCredStashClient.apply$default$3()
);
The first one certainly looks better, but if the default argument ever changes, you'll have to update this code too. In the second one, the argument is whatever the default argument is, and will only break if the argument stops having a default, or changes its index. Scala uses the second method when compiled.

Can we cast a object into a class type whose name is only known?

I have to dynamically fetch the tables whose names are available in dropdown in a jsp. Upon the selection of table name corresponding columns should be printed. For that I was running a loop in jsp and trying but is it possible to cast an object of "Object" type into a class whose class name is only known and after that using that object I have to acesss the corresponding class methods.
ex: className I got from jsp is "Book" and I have a class Book.class which has a method getName() so something like this is what I wanted:
Object obj1 = Class.forName(className).cast(obj);
obj1.getName();
Here obj is the object I have got through session.
forName takes a String and you can't call getMethod on Object because there is no such method. Ideally you'd have an interface defining the method that's common in all the types you can select from your drop down.
If that is not an option, then there is an uglier option using reflection where you don't actually need to know the type in advance:
Class<?> clazz = Class.forName("Book");
// Object obj1 = clazz.cast(obj);
// The method getName() is undefined for the type Object
Method m = clazz.getMethod("getName");
String res = (String) m.invoke(obj);
I'd not recommend using this code as is in any production application though. You'll need quite a bit of validation and exception handling in order to make this work safely.
Yes you can do that but the object must belong to that class or some of its child class else it will give you a ClassCastException. You also need to pass complete path of that class mean fully qualified class name with package.
Object obj1 = Class.forName(com.Book).cast(obj);
obj1.getName();

How can I create an instance from a own class in FreeMarker (FTL)

I wish to instantiate a java class that I have defined in my domain and I want to use it from my FTL code in this way, but I'm getting an error.
<#assign myClassInstance = "com.domain.MyClass"?new())>
Is it possible? What I should change to do it?
MyClass doesn't implements the TemplateModel
Thanks!
There's no built-in function for instantiating arbitrary non-TemplateModel classes... maybe there should be a setting to allow that for ?new. Anyway, for now you can write a TemplateMethodModelEx that does that, and then you can pull that into some of your commonly included/imported templates like <#assign unrestrictedNew = "com.example.UnrestrictedNewMethodModel"?new()> (or just put the instance into the data-model or into the Configuration as a shared variable) and then you can do <#assign myClassInstance = unrestrictedNew("com.domain.MyClass")(arg1, arg2, argN)> in your templates. There are two tricky parts in implementing such a TemplateMethodModel. One is resolving the class name to a Class, for which I recommend env.getNewBuiltinClassResolver().resolve(className, env, null), where env is the current freemarker.core.Environment object. The other is calling the constructor, as then you have to convert parameter values and possibly chose an overloaded constructor. For that I recommend calling ow = env.getObjectWrapper(), see if ow instanceof BeansWrapper (throw exception if it isn't), then do return ((BeansWrapper) ow).newInstance(cl, arguments).

Categories

Resources