1

I am currently doing a project for my university. I work on an application that allows a user to type java methods into a text area. The application then puts these methods into a class and should compile it when the user hits the compile button.

So far I used this approach: https://stackoverflow.com/a/2946402

And it worked for me at first, but it only compiles a simple (standalone) class. The class I have to compile at runtime extends another class from the application. In this way the user should get access to some methods from the super class, which I implemented. This is the method I use to compile the class:

    public Class<?> loadClass(String filename) {
        WorkingDirectory workingDirectory = WorkingDirectory.getInstance();
        File directory = workingDirectory.getCompileDirectory();
        File javaFile = workingDirectory.createJavaFileFromUserProgram(filename);
        Class<?> cls = null;
        try {

            // Compile source file.
            JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();

            compiler.run(null, null, null, javaFile.getPath());

            URLClassLoader classLoader = URLClassLoader.newInstance(new URL[] { directory.toURI().toURL() });
            cls = Class.forName(filename, true, classLoader);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return cls;
    }

This works fine with a class that does'nt extend anything. When I add the extends I end up with this error message:

    error: cannot find symbol
    public class UsersClass extends ExistingClass { public void main() {
                                    ^
      symbol: class ExistingClass
    1 error
    java.lang.ClassNotFoundException: UsersClass
        at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
        at java.net.FactoryURLClassLoader.loadClass(URLClassLoader.java:814)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
        at java.lang.Class.forName0(Native Method)
        at java.lang.Class.forName(Class.java:348)
        at utils.SimulatorClassloader.loadClass(SimulatorClassloader.java:51)
        at simulator.Simulator.lambda$4(Simulator.java:171)....

Does someone know what I need to add/change in my method? I did some research for several hours, but I didn't make progress since then.

Community
  • 1
  • 1
JWo
  • 650
  • 1
  • 6
  • 23
  • did you create `ExisitingClass` too? – msagala25 Jan 27 '17 at 02:50
  • ExistingClass is a class that already exists in that application. I implemented it. It contains some private methods and some public methods, that the user can use, because the users class extends the existing class. UsersClass is a class that doesn't exist at the time the application start. The application creates a .java file and compiles it when the user hits the compile button at runtime. – JWo Jan 27 '17 at 02:56
  • 1
    do you think that `UserClass` imported `ExistingClass` , maybe they are in different package. check it. – msagala25 Jan 27 '17 at 02:58
  • Seems `ExistingClass` is not in the classpath. See this question http://stackoverflow.com/questions/1563909/how-to-set-classpath-when-i-use-javax-tools-javacompiler-compile-the-source – xiaofeng.li Jan 27 '17 at 03:17
  • Thank so much. You gave me the answer, LKTN.25. I didn't recognized some mistakes, because I had no code highlighting and error marks like in an IDE, because the users class always was existed inside of a simple text area. I had imported the class (but with a mistake) and the class only had one constructor with parameters and no default one. And the users class of course didn't overwrite it. After I added the constructor everything works fine. Now I just have to get rid of the constructor and use a default one instead. I'm a bit ashamed, because of this "simple" mistake, but happy, too. – JWo Jan 27 '17 at 03:19

1 Answers1

0

I didn't recognized some mistakes, but with LKTN.25 hint I found them.

First: UsersClass had a typo at the import section. After this mistake was gone another error came up.

Second: My base class didn't have a default constructor and the sub class too. And the subclass didn't overrite the other constructor. Therefore no instance of the subclass could be created.

Apparently "Does someone know what I need to add/change in my method?" wasn't the right question. The mistake was somewhere else.

Update: I thought I had to insert a constructor in the users class, because I couldn't create an instance at runtime. The users class doesn't need a constructor at all (Like usual in java). It gets it from the super class.

Apparently the following snippet doesn't work.

    Class<?> cls = new SimulatorClassloader().loadClass(this.simulatorGUI.getStageTitle());
                try {
                    Method method = cls.getMethod("main");
                    try {
                        method.invoke(cls.newInstance());
                    } catch (Exception e1) {
                        // TODO Auto-generated catch block
                        e1.printStackTrace();
                    }

But this (slightly modified code) actually does work:

    Class<?> cls = new SimulatorClassloader().loadClass(this.simulatorGUI.getStageTitle());
                try {
                    Method method = cls.getMethod("main");
                    try {
                        Object obj = cls.newInstance();
                        method.invoke(obj);
                    } catch (Exception e1) {
                        // TODO Auto-generated catch block
                        e1.printStackTrace();
                    }
JWo
  • 650
  • 1
  • 6
  • 23