0

Supposed I have a User list on Post entity

private List<User> users = new ArrayList<>();

and I can clear it using

post.getUsers().clear();

and can add to it with

post.getUsers().addAll(Something);

how can I do the same if use to call the function getUsers dynamically? I tried

post.getClass().getMethod("getUsers").invoke(post).getClass().getMethod("clear").invoke(new ArrayList<>());

and also I tried

ArrayList.class.getMethod("clear").invoke(post);

but im getting a

WARN  o.s.w.s.m.m.a.ExceptionHandlerExceptionResolver - Resolved [java.lang.IllegalArgumentException: object is not an instance of declaring class]

Any idea on how can I do it?

take note that this is working

post.getClass().getMethod("getUsers").invoke(post); //get the users

I just have no idea how can I chained the clear method or the addAll on it.

Beginner
  • 1,700
  • 4
  • 22
  • 42

3 Answers3

1

Method.invoke returns an Object and the Object class does not have a clear() method, so you need to cast the returned object into a List.

Post post = new Post();
Method m = post.getClass().getMethod("getUsers");
List<User> users = (List<User>)m.invoke(post);
users.clear();

And if you want it in one line, it is ugly, but can be done:

((List<User>)(post.getClass().getMethod("getUsers").invoke(post))).clear();

This also works:

List.class.cast(post.getClass().getMethod("getUsers").invoke(post)).clear();
Bentaye
  • 9,403
  • 5
  • 32
  • 45
  • Sorry for the late reply where having a holiday. How can I use it on addAll? I tried this List.class.cast(getMethodEntity).addAll((Collection>) Objects.requireNonNull(fieldValue)); this is working but im having a warning saying that Unchecked call to 'addAll(Collection extends E>)' as a member of raw type 'java.util.List' – Beginner Dec 09 '19 at 02:03
  • check this https://stackoverflow.com/questions/59241734/java-list-cast-to-be-able-to-use-addall-function – Beginner Dec 09 '19 at 02:17
  • @Beginner This is because the list you get from `invoke` has no type. When you try to add a `User`, you have a warning, and it basically telling you: "Watch out, you are trying to add a `User` to a `List`, and I can't know if that List is a `List`". You know it is a `List` so you can ignore that warning, or suppress it using an annotation. I don't think there is a way around that. It is ok. – Bentaye Dec 09 '19 at 09:08
0

Just check the JavaDocs of ArrayList.

ArrayList.clear() returns nothing because it's a void method, ArrayList.addAll() returns a boolean.

So to allow for method chaining, you'd have to wrap the calls in your Post entity to return the post entity itself. Then you could get method chaining.

So, in your Post entity, you'd add:

public Post clearUsers() {
    users.clear();
    return this;
}

and

public Post addAllUsers(List<User> usersToAdd) {
    users.addAll(usersToAdd);
    return this;
}

and invoke these methods instead of getUsers().xyz() (which is very bad style anyway. The posobject owns these users. it should be the only one to manipulate these).

Nicktar
  • 5,548
  • 1
  • 28
  • 43
0

You need to invoke those methods on the array list object contained by post.

For example, you can call clear on post.getUsers() as

ArrayList.class.getMethod("clear").invoke(
                // this will give you reference to array list contained by post
                post.getClass().getMethod("getUsers").invoke(post)
        );

Tested above code as following

public class DynamicInvocation {
    public static void main(String[] args) throws Exception {
        Post post = new Post();
        post.getUsers().add(new User());
        System.out.println(post.getUsers());
        ArrayList.class.getMethod("clear").invoke(
                post.getClass().getMethod("getUsers").invoke(post)
        );
        System.out.println(post.getUsers());
    }
}

class Post {
    private List<User> users = new ArrayList<>();

    public List<User> getUsers() {
        return users;
    }
}

class User {
}
Yogesh Badke
  • 4,249
  • 2
  • 15
  • 23