1

Some background - I'm trying to write a generic way of overriding values coming from server, without knowing exactly on which class they should be set. So what I'm doing is:

I look at the key/value I got from the server and then I start looking (iterating) at the "User" object and all of it's fields - if one of the fields matches what I got from server - I need to override it's value.

One of the User fields can be another class by itself like "Settings" and then I need to repeat the iteration on the settings class and so on -until I find a match.

Once I found a match I need to set the value. And here is where my problem is:

Trying to set a method in a class type but I get thrown IllegalArgumentException

target.declaredMethods[1].invoke(target, true)

java.lang.IllegalArgumentException: Expected receiver of type test.reflectiveparser.User$Settings, but got java.lang.Class<test.reflectiveparser.User$Settings>

I realise I need to invoke the method on the instance and not the Class type - but how do I do that if I don't know what class I'm working on until runtime?

(trying to build a generic way of setting values in different classes)

Yosi199
  • 1,745
  • 4
  • 22
  • 47
  • Need to check out the factory design pattern. [Factories](https://docs.oracle.com/javase/7/docs/technotes/guides/rmi/Factory.html) – Cowboy Farnz Jan 04 '18 at 10:16
  • Looks like method you are trying to access need to be static. If this is not the case then you can always create the instance of the class using reflection. You have Class instance and you can create the object from it using Class.newInstance(...) and then set the value. – Har Krishan Jan 04 '18 at 10:39
  • Yeah but that's not what I wanna do - I wanna be able to set a specific field in an existing class instance without affecting other fields in that instance – Yosi199 Jan 04 '18 at 10:45

3 Answers3

1

Type is class and you have to create an instance of that class check this

Object instance  = type.forName(className).getConstructor().newInstance();

target.declaredMethods[1].invoke(instance,true);
Saltuk
  • 1,159
  • 9
  • 12
0

Seems target is Class < T > type variable. You should call target.invoke method only with T object instance but you are calling it with Class < T > object.

Vladyslav Nikolaiev
  • 1,819
  • 3
  • 20
  • 39
0

As you've identified, you need to call the method on the instance. In your case, the instance is one of the fields on the User object.

For example:

class Settings {
    fun methodToCall(bool: Boolean) = "value is: $bool"
}

class User {
    val settings = Settings()
}

fun main(args: Array<String>) {
    val user = User()

    val field = user::class.java.declaredFields[0]
    field.isAccessible = true // allow access to the field (or you can call the getter method if you prefer)

    // get the value of the settings field
    val settings = field[user]

    // invoke with the instance
    println(field.type.declaredMethods[0].invoke(settings, true))
}
JK Ly
  • 2,845
  • 2
  • 18
  • 13