dimanche 29 novembre 2020

Getting an Object by reference in Java

New to this website, and excited to share my first question :)

Ok so I'm going to be explaining what I have set-up currently so that my question can be understood better.

I have 2 java applications:

  1. Logic Application (Where all the heavy load occurs)
  2. Instrumented Application (Application instrumented into a running game)

What I do with these 2 applications is extract information from a game using the Instrumented Application then send it to the Logic Application. The extraction of information/data is done through the Java Reflection API. Then after the information has been extracted, it is sent to the Logic Application through RMI (more on this below).

The reason I have 2 applications instead of 1 is because the game runs on Java 7 (old game), so the Instrumented Application runs on Java 7, and I can run the Logic application on whatever java version I want.

The way I transfer data/information between the 2 is through RMI (Remote Method Invocation). Explanation: The Logic application invokes a getter method at the Instrumented App, and the method uses the Reflection API to grab the field value from the game it's instrumented into and return it.

Now as you guys have understood what I'm basically doing, now comes the challenge that I have been bamboozled by for quite some time.

Problem:

Most of the Field Values that are returned by Reflection are Serializable, therefore they pass-through RMI with no problem. But, some are Un-serializable objects like for an example "Item". "Item" is an object and it holds 3 values: ID, Name, Quantity. So my thought was to make a wrapper and send the wrapper and it would be problem solved right? but no, another challenge popped up.

The challenge that popped up was: What if I needed to know the quantity of the object "Item" that I pulled out at another time? If my whole thing was 1 application, I would've used the Reflection API to get the Field using the Object by: getClassLoader().loadClass("ItemClass").getDeclaredField("Item").get(ObjectThatIPreviouslyFetched); But since I have to transfer the objects over to the Logic Application, I cannot transfer the Object itself "Item" so I have no way to return to that object and get updated information unless I look for the object again which is a waste of resources and makes my whole process slower.

Applications work like so:

Instrumented App -> Reflection -> Game -> Field Value (Object called Item) -> Wrapper -> RMI -> Logic Application (Object information is sent but Object itself can't be sent due to it being unserializable)

Summary of the question (using the pointers just above): How can I get the Object (Item) back so I can get updated information about it using Reflection.

This is the method I made to get the Field Values (Objects):

   /**
    *
    * @param params owner;fieldName;multiplier
    * @param object null if static
    * @return returns the value of the object provided.
    */
   public Object getFieldValue(String params, Object object) {
       String[] paramsSplit = params.split(";");
       try {
           Class<?> clazz = classLoader.loadClass(paramsSplit[0]);
           Field field = clazz.getDeclaredField(paramsSplit[1]);
           field.setAccessible(true);
           Object o = field.get(object);
           if(!paramsSplit[2].equals("0")) return getMultipliedValue((Number) o,paramsSplit[2]);
           else return o;
       } catch (IllegalAccessException | NoSuchFieldError | ClassNotFoundException | NoSuchFieldException e) {
           e.printStackTrace();
       }
       return null;
   } 

This method is found in the Logic Application and it attaches the Instrumented Application to the running game:

    public void inject() {
        VirtualMachine vm = null;
        try {
            vm = VirtualMachine.attach(String.valueOf(pid));
            vm.loadAgent(Info.baseLocation());
        } catch (AttachNotSupportedException | IOException |
                AgentLoadException | AgentInitializationException e) {
            e.printStackTrace();
        } finally {
            try {
                if(vm != null) vm.detach();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

I hope everything was understandable, I'm not an English native so I apologize if something seems wrong.

Thank you!





Aucun commentaire:

Enregistrer un commentaire