javaandroidstringruntimebeanshell

Runtime java code (string) injection and execution


I'm trying to inject in my existing code and execute a string of additional java code that uses classes defined in my project and manipulates data provided in my "compiled" code. I have tried using beanshell but I had some problems with the usage of already existing classes (other than problems with using lambda functions, diamond operator, ...). I know this is not safe at all but I'm using this for testing purposes. This is what my code looks like now:

DiscoverViewModel viewModel = new ViewModelProvider(viewModelStoreOwner).get(DiscoverViewModel.class);

        try {
            ArrayList<EntityConsumedThings> things = new ArrayList<>();
            viewModel.getAllThingsLiveData().observe((LifecycleOwner) context,
                    things::addAll);

            Map<String, ConsumedThing> consumedThingMap = new HashMap<>();
            for (EntityConsumedThings t : things) {
                ConsumedThing consumedThing = WotInteraction.getInstance(context).getWot().consume(Thing.fromJson(t.thingJSON));
                consumedThingMap.put(consumedThing.getId(), consumedThing);
            }
        } catch (WotException | JSONException ex){
            ex.printStackTrace();
        }

        // EXAMPLE CODE - IT WILL BE AUTOGENERATED AND RETRIEVED FROM A SERVER
        String code = "ConsumedThing consumedThing = consumedThingsMap.get(\"urn:uuid:92e5b68f-322a-433a-8cff-f50f6ca1b519\");" +
                        "if(consumedThing!=null){" +
                            "ConsumedThingProperty property = consumedThing.getProperty(\"resources\");" +
                            "property.read();\n" +
                        "} else {\n" +
            "               System.out.println(\"RUNTIME ERROR: Thing not found.\");\n" +
                "        }\n;";

        // EXECUTE THE CODE HERE

ConsumedThing, ConsumedThingProperty classes are defined in my project. Is there a way to do what I'm trying to do or is it impossible? Thanks in advance to anybody will answer me.


Solution

  • I just had to import in the beanshell script the classes I needed and to pass the variable instantiated in my code to the beanshell context.

    DiscoverViewModel viewModel = new ViewModelProvider(viewModelStoreOwner).get(DiscoverViewModel.class);
    
            // EXAMPLE CODE - IT WILL BE AUTOGENERATED AND RETRIEVED FROM A SERVER
            String code = "import com.example.wot_servient.wot.thing.ConsumedThing;\n"+
                    "import com.example.wot_servient.wot.thing.action.ConsumedThingAction;\n" +
                    "import com.example.wot_servient.wot.thing.property.ConsumedThingProperty;\n" +
                    "ConsumedThing consumedThing = consumedThingsMap.get(\"urn:uuid:92e5b68f-322a-433a-8cff-f50f6ca1b519\");" +
                    "if(consumedThing!=null){" +
                    "ConsumedThingProperty property = consumedThing.getProperty(\"resources\");" +
                    "property.read();\n" +
                    "} else {\n" +
                    "               System.out.println(\"RUNTIME ERROR: Thing not found.\");\n" +
                    "        }\n;";
            // EXECUTE THE CODE HERE
    
            Executors.newSingleThreadExecutor().execute(() -> {
                try {
                    List<EntityConsumedThings> things = viewModel.getAllThingsList();
    
                    Map<String, ConsumedThing> consumedThingsMap = new HashMap<>();
                    for (EntityConsumedThings t : things) {
                        ConsumedThing consumedThing = WotInteraction.getInstance(context).getWot().consume(Thing.fromJson(t.thingJSON));
                        consumedThingsMap.put(consumedThing.getId(), consumedThing);
                    }
                    Interpreter interpreter = new Interpreter();
                    interpreter.set("consumedThingsMap", consumedThingsMap);
                    interpreter.eval(code);
                } catch (WotException | JSONException | EvalError ex){
                    ex.printStackTrace();
                }
            });